
CVE-2024-11972 dans Hunk Companion <1.9.0 permet à des attaquants non authentifiés d'exploiter des points de terminaison REST API non sécurisés et d'installer des plugins vulnérables, risquant ainsi l'exécution de code à distance (RCE), l'injection SQL (SQLi), le cross-site scripting (XSS) et l'installation de portes dérobées.
CVE-2024-11972 est une vulnérabilité critique dans le plugin WordPress Hunk Companion dans les versions antérieures à 1.9.0. Cette faille permet à des attaquants non authentifiés d'exploiter des points d'API REST mal autorisés, leur permettant d'installer et d'activer des plugins depuis le dépôt WordPress.org, y compris ceux qui sont obsolètes ou présentent des vulnérabilités connues. L'exploitation de cette vulnérabilité peut entraîner des risques de sécurité graves, tels que l'exécution de code à distance, l'injection SQL, le XSS ou des portes dérobées administratives.
Un exemple courant d'abus de cette vulnérabilité est l'utilisation du plugin WP Query Console. Une fois installé via cette exploitation, le plugin fournit une interface console dans WordPress où les utilisateurs peuvent exécuter des requêtes SQL sur la base de données du site, permettant le vol de données, la création de portes dérobées et la compromission complète de la base de données.
Bibliothèques Python nécessaires -> argparse, requests, urljoin
options:
-h, --help show this help message and exit
-u URL, --url URL Base URL of the WordPress site (default: http://localhost/wordpress/).
-p PLUGIN, --plugin PLUGIN
Plugin name to install (default: classic-editor).
<insérez l'URL WordPress> -p <insérez le nom du plugin>Le point de terminaison vulnérable, /wp-json/hc/v1/themehunk-import, a été initialement identifié par Daniel Rodriguez lors d'une analyse des journaux d'accès dans le cadre d'une enquête en cours.
Grâce à cette information, nous pouvons examiner le code source du point de terminaison d'importation.
À l'intérieur du fichier /import/core/class-installation.php, nous pouvons voir la ligne suivante :
204 | $temp_file = download_url('https://downloads.wordpress.org/plugin/'.$slug.'.zip');
La classe HUNK_COMPANION_SITES_BUILDER_SETUP gère l'installation et l'activation des plugins et thèmes WordPress, en traitant les types gratuits et premium en fonction des paramètres d'entrée.
Elle vérifie dynamiquement si un plugin ou un thème est installé ou actif, télécharge et décompresse les fichiers nécessaires s'ils sont manquants, et les active à l'aide des fonctions principales de WordPress.
Cette fonctionnalité codée en dur permet au plugin de télécharger n'importe quel plugin depuis le dépôt WordPress, même ceux qui sont supprimés ou abandonnés, donnant ainsi aux attaquants l'opportunité d'exploiter des plugins vulnérables.
Pour approfondir le problème, nous pouvons examiner /import/app/app.php,
comparons les différentes corrections introduites dans les versions 1.8.0 | 1.8.7 | 1.9.0, car chacune a ajouté une couche de sécurité supplémentaire :
register_rest_route( 'hc/v1', 'themehunk-import', array(
'methods' => 'POST',
'callback' => array( $this, 'tp_install' ),
'permission_callback' => '__return_true',
) );
Le permission_callback renvoie toujours true, ce qui permet à tout utilisateur ou acteur non authentifié d'accéder au point de terminaison via une requête POST.
Comme il n'y a aucun type de vérification Nonce ni de processus d'authentification, un attaquant pourrait contourner les autorisations nécessaires et installer directement le plugin souhaité.
Dans la version 1.8.7, plusieurs améliorations de sécurité ont été introduites pour corriger les défauts des versions précédentes,
mais le point de terminaison /hc/v1/themehunk-import et l'implémentation globale présentent encore des failles significatives :
public function register_routes() {
register_rest_route( 'hc/v1', 'themehunk-import', array(
'methods' => 'POST',
'callback' => array( $this, 'tp_install' ),
'permission_callback' => function () {
// Check if the user is logged in
if ( ! is_user_logged_in() ) {
return new WP_REST_Response( 'Unauthorized: User not logged in', 401 );
}
// Debug: Log the user role and capabilities to see what they have
$current_user = wp_get_current_user();
// error_log( 'Current user: ' . $current_user->user_login );
// error_log( 'User roles: ' . implode( ', ', $current_user->roles ) );
// error_log( 'User capabilities: ' . print_r( $current_user->allcaps, true ) );
// Ensure the user has the 'install_plugins' capability
if ( ! current_user_can( 'install_plugins' ) ) {
return new WP_REST_Response( 'Unauthorized: Insufficient capabilities', 401 );
}
// Get the nonce from the request header
$nonce = $request->get_header('X-WP-Nonce');
// Verify the nonce
if ( ! wp_verify_nonce( $nonce, 'hc_import_nonce' ) ) {
return new WP_REST_Response( 'Unauthorized: Invalid nonce', 401 );
}
return true; // Permission granted
Bien que cette version inclue des vérifications pour s'assurer que l'utilisateur est connecté (is_user_logged_in()) et qu'il possède les capacités appropriées (current_user_can('install_plugins')), en renvoyant une réponse 401 Unauthorized dans le cas contraire, elle néglige toujours le problème principal qui reste non résolu.
La logique de rappel de WordPress concernant permission_callback est évaluée comme suit :

Cela signifie qu'une réponse correcte serait l'une des suivantes : true | false | WP_Error.
Le problème vient du fait que WP_REST_Response renvoyé n'est ni un booléen ni un WP_Error. Comme WordPress ne l'interprète ni comme un refus (false) ni comme une erreur (WP_Error(), il pourrait implicitement l'accepter et accorder l'accès à un utilisateur non authentifié, ne résolvant ainsi pas le problème principal.
La version 1.9.0 a résolu le problème avec succès, rendant la vulnérabilité inexploitable :
public function register_routes() {
register_rest_route( 'hc/v1', 'themehunk-import', array(
'methods' => 'POST',
'callback' => array( $this, 'tp_install' ),
'permission_callback' => function () {
// Check if the user is logged in
if ( ! is_user_logged_in() ) {
return false;
}
// Debug: Log the user role and capabilities to see what they have
$current_user = wp_get_current_user();
// error_log( 'Current user: ' . $current_user->user_login );
// error_log( 'User roles: ' . implode( ', ', $current_user->roles ) );
// error_log( 'User capabilities: ' . print_r( $current_user->allcaps, true ) );
// Ensure the user has the 'install_plugins' capability
if ( ! current_user_can( 'install_plugins' ) ) {
return false;
}
// Get the nonce from the request header
$nonce = $request->get_header('X-WP-Nonce');
// Verify the nonce
if ( ! wp_verify_nonce( $nonce, 'hc_import_nonce' ) ) {
return false;
}
return true; // Permission granted
Dans cette version, nous pouvons voir qu'une valeur false appropriée est renvoyée si l'utilisateur n'est pas connecté ou ne possède pas les autorisations correctes,
garantissant ainsi que permission_callback refuse correctement l'accès non autorisé, rendant l'exploit non viable.