ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 на SSD для Jolah Molivski ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия ноды ETHEREUM и тестов
Обновление (2022-02-26): инструмент стал общедоступным: https://github.com/kazet/wpgarlic.
Плагины WordPress открывают ряд интерфейсов, таких как:
Эти интерфейсы имеют согласованную границу доверия: мы знаем, куда идет недоверенный вход, и можем определить, какие операции выполняются на этом входе.
Например, если вы посещаете страницу с .php кодом , предоставляете соответствующие параметры и вызываете удаление файла, вы знаете, что это уязвимость. Вы знаете, какие параметры вы контролируете, а какие нет - например, вы можете перенаправить вошедшего в систему администратора на страницу меню администратора с произвольными GET-параметрами, но вы не контролируете его cookies.
Поэтому возможно полуавтоматическое сканирование на наличие нескольких классов уязвимостей во всех плагинах WordPress.
Я написал инструмент, который:
Этот метод можно перенести на другие экосистемы плагинов CMS, но не напрямую, например, на пакеты Python. Если пакет Python позволяет удалять произвольные файлы, это может быть или не быть уязвимостью в зависимости от роли пакета и вашей конкретной установки.
Простой имитатор массива $_POST можно создать с помощью следующего кода:
В приведенном выше фрагменте будет выведена полезная нагрузка.
Предположим, что массив $_REQUEST был подделан способом, аналогичным описанному выше, и что AJAX-маршрут обрабатывается следующей функцией:
При обращении к $_REQUEST['block_id'] mock вернет полезную нагрузку, что позволит определить, что wp_delete_post был вызван на контролируемом злоумышленником значении.
Такой подход позволял легко внедрять полезную нагрузку, даже если имя параметра было трудно угадать - инструмент не различал id и secret_parameter_65e3c14a1d.
Некоторые ключи нужно было исключить вручную (например, $_SERVER['HTTP_AUTHORIZATION'] или $_GET['doing_wp_cron']), поскольку их значения обрабатывались WordPress, и их предоставление приводило к тому, что код плагина не был доступен.
Кроме того, с некоторой вероятностью вместо строковой полезной нагрузки возвращался массив случайного типа:
Инструмент содержит проверки для обнаружения:
Для обнаружения XSS были реализованы проверки, обнаруживающие, что полезная нагрузка возвращается эхом (или возвращается с экранированием, которое не предотвращает XSS, например, префикс " с \).
Были обнаружены следующие типы сбоев:
Выходные данные анализировались на предмет отображения известных электронных адресов пользователей или имен файлов.
WordPress был проанализирован для обнаружения:
Обновление (2022-02-26): кроме того, любые попытки доступа к загруженным файлам записываются в журнал, чтобы их можно было проверить вручную.
К сожалению, это привело к большому количеству ложных срабатываний. Ложные срабатывания были, например, в виде:
Единственным решением этой проблемы, которое я использовал, был просмотр этих ложных срабатываний и ругань. Дальнейшие исследования могут привести к появлению других решений.
Кроме того, я исправил интерпретатор PHP таким образом:
При разработке критически важным был подход, основанный на тестировании. Тесты проверяли, что инструмент найдет известную уязвимость. Например, я могу написать тест для проверки того, что при проверке конечной точки wp_ajax_heateor_sss_import_config плагина sassy-social-share версии 3.3.23 инструмент должен обнаружить, что maybe_unserialize() вызывается на управляемой злоумышленником полезной нагрузке. Этот подход привел к большому количеству ложных срабатываний. Это было преднамеренное решение, поскольку я хотел отсортировать множество отчетов, а не пропустить уязвимости. Может быть написание дополнительной логики фильтрации. Например, было несколько отчетов, в которых HTML полезная нагрузка возвращалась эхом - но при их проверке я заметил, что добавляется правильный JSON Content-Type заголовок. Это был один из случаев, которые можно было бы проверять автоматически. Фаззинг проводился внутри контейнеров Docker, созданных заново для каждого плагина. Было важно отключить сеть, потому что многие плагины вызывают другие веб-сервисы, и я хотел избежать отправки туда случайных полезных нагрузок. Мне также показалось полезным разделить проверку плагинов и анализ выходных данных. Поскольку выходные данные анализировались с помощью множества регулярных выражений, возникали ошибки. Поэтому относительно быстрое повторное сканирование позволяло ускорить разработку. Сканирование тысяч плагинов было бы невозможно без автоматизации работы. К счастью, плагины WordPress используют согласованные интерфейсы для интеграции с WordPress, например:
Все вышеперечисленные приемы позволили создать инструмент, не требующий специфического для плагинов кода.
Из-за нехватки времени я сосредоточился только на самых популярных плагинах. На данный момент следующие ошибки, найденные инструментом, уже исправлены и опубликованы:
Не все уязвимости были найдены непосредственно фаззером. Например, CVE-2021-25096 была обнаружена случайно при написании PoC для CVE-2021-25095. Для некоторых других уязвимостей предупреждения инструмента были лишь частью информации об уязвимости - например, инструмент уведомлял, что опция WordPress может быть обновлена любым пользователем - и поиск последствий (может ли это привести, например, к хранимому XSS) требовал ручной работы.
Я не буду высмеивать какого-либо конкретного автора плагина, однако считаю, что некоторыми выводами стоит поделиться.
is_admin
Функция WordPress is_admin(), как вы уже, наверное, догадались определяет, предназначен ли текущий запрос для страницы административного интерфейса.
(с сайта https://developer.wordpress.org/reference/functions/is_admin/)
Документация также предупреждает, что она не проверяет, является ли пользователь администратором; для проверки ролей и возможностей используйте функцию current_user_can().
Как вы уже, наверное, догадались, это стало источником пары уязвимостей в виде:
Рассмотрим следующий код:
Какие значения ID могут быть переданы в обработчик? Правильный ответ: все - просто используйте /?rest_route=/(...)/1&id=hehehe.
get_users()
Некоторые плагины позволяют искать пользователей по части адреса электронной почты. Это позволяет слить e-mail любого пользователя, используя следующие шаги:
В связи с этим я добавил проверку, которая предупреждает о вызове get_users(). К сожалению, помимо обнаружения уязвимостей данного типа, она также привела к многочисленным ложным срабатываниям.
Не делайте следующее:
Несколько XSS-уязвимостей также были вызваны отладочными помощниками в виде:
Проверка CAPTCHA
Не делайте этого:
Я наблюдал этот паттерн много раз, как для CAPTCHA, так и для несов.
Это была лишь пробная версия, чтобы проверить, являются ли автоматические методы жизнеспособным методом для поиска ошибок в плагинах WordPress. Я уверен, что он может быть улучшен, например, путем
Эта техника может быть реализована и для других экосистем плагинов.
Многие из найденных мною уязвимостей легко предотвратить с помощью современных методов разработки программного обеспечения. Во многих плагинах WordPress HTML строится с помощью подверженной ошибкам кучи echo-заявлений, вместо языка шаблонов. Аналогично, конечные точки AJAX по умолчанию доступны для всех вошедших или не вошедших пользователей, вместо того чтобы требовать от разработчика фиксированного списка ролей или разрешений (так что им пришлось бы явно отмечать маршрут как доступный для всех вошедших пользователей). Внедрение методов, затрудняющих совершение ошибок, и поощрение их использования - это, к сожалению, то, что может сделать только команда WordPress, а не разработчики плагинов.
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 на SSD для Jolah Molivski ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия ноды ETHEREUM и тестов
Обновление (2022-02-26): инструмент стал общедоступным: https://github.com/kazet/wpgarlic.
Плагины WordPress открывают ряд интерфейсов, таких как:
- конечные точки AJAX (/wp-admin/admin-ajax.php)
- Страницы меню администратора (/wp-admin/admin.php?page=...)
- PHP-файлы (в каталоге /wp-content/plugins/),
- REST-маршруты (/wp-json/...).
Эти интерфейсы имеют согласованную границу доверия: мы знаем, куда идет недоверенный вход, и можем определить, какие операции выполняются на этом входе.
Например, если вы посещаете страницу с .php кодом , предоставляете соответствующие параметры и вызываете удаление файла, вы знаете, что это уязвимость. Вы знаете, какие параметры вы контролируете, а какие нет - например, вы можете перенаправить вошедшего в систему администратора на страницу меню администратора с произвольными GET-параметрами, но вы не контролируете его cookies.
Поэтому возможно полуавтоматическое сканирование на наличие нескольких классов уязвимостей во всех плагинах WordPress.
Я написал инструмент, который:
- выполняет каждую конечную точку AJAX, страницу меню, маршрут REST или файл несколько раз,
- внедряет полезную нагрузку в массивы GET, POST и т.д. или параметры REST (подробнее о том, как это делается, в следующем разделе),
- анализирует выходные данные с помощью уродливой кучи регулярных выражений1 , чтобы обнаружить
- вызовы функций WordPress (таких как wp_delete_post),
- сбои ("No such file or directory", "You have an error in your SQL syntax", ...),
- XSS (передача известной полезной нагрузки, содержащей " или <),
- и т.д.
Этот метод можно перенести на другие экосистемы плагинов CMS, но не напрямую, например, на пакеты Python. Если пакет Python позволяет удалять произвольные файлы, это может быть или не быть уязвимостью в зависимости от роли пакета и вашей конкретной установки.
Инъекция параметров
В PHP массивы _GET, _POST, _SERVER, _COOKIE и _REQUEST содержат различные параметры запроса (например, данные GET и POST, cookies, конфигурацию сервера и заголовки). Я заменил их на объекты-макеты, которые позволяют получить доступ к любому ключу - и с определенной вероятностью возвращают полезную нагрузку из предопределенного списка полезной нагрузки.Простой имитатор массива $_POST можно создать с помощью следующего кода:
Код:
<?php
class Mock implements ArrayAccess {
function offsetGet($offset) {
return "payload";
}
function offsetExists($offset) {
return true;
}
function offsetSet($offset, $value) { }
function offsetUnset($offset) { }
}
$_POST = new Mock();
echo $_POST["parameter_name"];
В приведенном выше фрагменте будет выведена полезная нагрузка.
Предположим, что массив $_REQUEST был подделан способом, аналогичным описанному выше, и что AJAX-маршрут обрабатывается следующей функцией:
Код:
public function delete_saved_block() {
$block_id = (int) sanitize_text_field($_REQUEST['block_id']);
$deleted_block = wp_delete_post($block_id);
wp_send_json_success($deleted_block);
}
При обращении к $_REQUEST['block_id'] mock вернет полезную нагрузку, что позволит определить, что wp_delete_post был вызван на контролируемом злоумышленником значении.
Такой подход позволял легко внедрять полезную нагрузку, даже если имя параметра было трудно угадать - инструмент не различал id и secret_parameter_65e3c14a1d.
Некоторые ключи нужно было исключить вручную (например, $_SERVER['HTTP_AUTHORIZATION'] или $_GET['doing_wp_cron']), поскольку их значения обрабатывались WordPress, и их предоставление приводило к тому, что код плагина не был доступен.
Кроме того, с некоторой вероятностью вместо строковой полезной нагрузки возвращался массив случайного типа:
- одноэлементный массив со строковой полезной нагрузкой,
- рекурсивно, объект, позволяющий получить доступ к любому ключу,
- одноэлементный массив: случайная полезная нагрузка → случайная полезная нагрузка.
Обнаружение уязвимостей
Инструмент содержит проверки для обнаружения:
- различные виды сбоев,
- потенциально опасных операций,
- утечки информации.
XSS
Для обнаружения XSS были реализованы проверки, обнаруживающие, что полезная нагрузка возвращается эхом (или возвращается с экранированием, которое не предотвращает XSS, например, префикс " с \).
СБОИ
Были обнаружены следующие типы сбоев:
- fopen() / file_get_contents() / require() / require_once() / include() / include_once() ошибки и сообщения об ошибках "No such file or directory" или "failed to open stream",
- сообщения об ошибках unlink(),
- сбои, связанные с call_user_func(),
- сообщения об ошибках SQL,
- ошибки unserialize(),
- ошибки разбора / синтаксиса для обнаружения вызовов eval(),
- сообщение об ошибке "команда не найдена",
- сообщения об ошибках simplexml_load_string()2.
Утечки информации
Выходные данные анализировались на предмет отображения известных электронных адресов пользователей или имен файлов.
Операции WordPress
WordPress был проанализирован для обнаружения:
- вызовы maybe_unserialize,
- вызовы update_option/update_site_option/delete_option,
- вызовы wp_insert_user,
- вызовы wp_insert_post/wp_update_post/wp_delete_post,
- вызовы wp_mail,
- вызовы query (этот вызов дал особенно много ложных срабатываний, которые потребовали дополнительной фильтрации),
- вызовы get_users (этот вызов был добавлен после случайного обнаружения CVE-2021-25110, где злоумышленник может слить произвольные сообщения электронной почты пользователя через созданный поисковый запрос пользователя).
Дополнительные проверки
После фаззинга панель администратора, главная страница и страницы постов были просмотрены на предмет обнаружения вхождений известных полезных нагрузок. Это позволило, например, обнаружить CVE-2021-24975 в social-networks-auto-poster-facebook-twitter-g.Обновление (2022-02-26): кроме того, любые попытки доступа к загруженным файлам записываются в журнал, чтобы их можно было проверить вручную.
Изменения в PHP
Я исправил PHP так, чтобы сравнение равенства между любым значением и известной полезной нагрузкой возвращало true с вероятностью 1/3. С помощью этого патча я смог обнаружить:
Код:
if ($_GET['action'] == 'please-remove-post') {
wp_delete_post($_GET['id']);
}
К сожалению, это привело к большому количеству ложных срабатываний. Ложные срабатывания были, например, в виде:
Код:
if (in_array($order, array("ASC", "DESC"), true)) {
query("(...) ORDER BY $order");
}
Единственным решением этой проблемы, которое я использовал, был просмотр этих ложных срабатываний и ругань. Дальнейшие исследования могут привести к появлению других решений.
Другие изменения
Кроме того, я исправил интерпретатор PHP таким образом:
- При выполнении base64_decode для известной полезной нагрузки, эта полезная нагрузка возвращалась снова,
- Когда json_decode выполнялся над известной полезной нагрузкой, возвращался объект, который возвращал полезную нагрузку при обращении к любому ключу. Это были те же объекты, которые служили, например, массивами $_GET,
- когда выполнялось перенаправление, отображалась соответствующая информация, чтобы можно было обнаружить уязвимости Open Redirect.
Тестирование
При разработке критически важным был подход, основанный на тестировании. Тесты проверяли, что инструмент найдет известную уязвимость. Например, я могу написать тест для проверки того, что при проверке конечной точки wp_ajax_heateor_sss_import_config плагина sassy-social-share версии 3.3.23 инструмент должен обнаружить, что maybe_unserialize() вызывается на управляемой злоумышленником полезной нагрузке. Этот подход привел к большому количеству ложных срабатываний. Это было преднамеренное решение, поскольку я хотел отсортировать множество отчетов, а не пропустить уязвимости. Может быть написание дополнительной логики фильтрации. Например, было несколько отчетов, в которых HTML полезная нагрузка возвращалась эхом - но при их проверке я заметил, что добавляется правильный JSON Content-Type заголовок. Это был один из случаев, которые можно было бы проверять автоматически. Фаззинг проводился внутри контейнеров Docker, созданных заново для каждого плагина. Было важно отключить сеть, потому что многие плагины вызывают другие веб-сервисы, и я хотел избежать отправки туда случайных полезных нагрузок. Мне также показалось полезным разделить проверку плагинов и анализ выходных данных. Поскольку выходные данные анализировались с помощью множества регулярных выражений, возникали ошибки. Поэтому относительно быстрое повторное сканирование позволяло ускорить разработку. Сканирование тысяч плагинов было бы невозможно без автоматизации работы. К счастью, плагины WordPress используют согласованные интерфейсы для интеграции с WordPress, например:
- все REST-маршруты собираются в центральном реестре, доступном через: rest_get_server()->get_routes(),
- действия AJAX создаются путем добавления хука с именем, начинающимся с wp_ajax_,
- существует один реестр со всеми страницами меню администратора.
Все вышеперечисленные приемы позволили создать инструмент, не требующий специфического для плагинов кода.
Из-за нехватки времени я сосредоточился только на самых популярных плагинах. На данный момент следующие ошибки, найденные инструментом, уже исправлены и опубликованы:
| ID | Plugin | CVE | Number of active installations | Type | Link |
|---|---|---|---|---|---|
| 1 | woocommerce | CVE-2022-0775 | 5,000,000 | Arbitrary comment deletion | WPScan |
| 2 | updraftplus | CVE-2021-25022 | 3,000,000 | Reflected XSS | WPScan |
| 3 | code-snippets | CVE-2021-25008 | 500,000 | Reflected XSS | WPScan |
| 4 | woocommerce-pdf-invoices-packing-slips | CVE-2021-24991 | 300,000 | Reflected XSS | WPScan |
| 5 | ad-inserter | CVE-2022-0288 | 200,000 | Reflected XSS | WPScan |
| 6 | caldera-forms | CVE-2022-0879 | 200,000 | Reflected XSS | WPScan |
| 7 | complianz-gdpr | CVE-2022-0193 | 200,000 | Reflected XSS | WPScan |
| 8 | custom-facebook-feed | CVE-2021-25065 | 200,000 | Reflected XSS | WPScan |
| 9 | favicon-by-realfavicongenerator | CVE-2022-0471 | 200,000 | Reflected XSS | WPScan |
| 10 | loginpress | CVE-2022-0347 | 200,000 | Reflected XSS | WPScan |
| 11 | popup-builder | CVE-2022-0479 | 200,000 | Reflected XSS | WPScan |
| 12 | use-any-font | CVE-2021-24977 | 200,000 | Arbitrary CSS append + stored XSS | WPScan |
| 13 | white-label-cms | CVE-2022-0422 | 200,000 | Reflected XSS | WPScan |
| 14 | wp-cerber | CVE-2022-0429 | 200,000 | Stored XSS | WPScan |
| 15 | wp-gdpr-compliance | CVE-2022-0147 | 200,000 | Reflected XSS | WPScan |
| 16 | capability-manager-enhanced | CVE-2021-25032 | 100,000 | Arbitrary settings update | WPScan |
| 17 | chaty | CVE-2021-25016 | 100,000 | Reflected XSS | WPScan |
| 18 | cmp-coming-soon-maintenance | CVE-2022-0188 | 100,000 | Possibility to add arbitrary CSS | WPScan |
| 19 | download-manager | CVE-2021-24969 | 100,000 | Stored XSS | WPScan |
| 20 | download-manager | CVE-2021-25069 | 100,000 | Reflected XSS | WPScan |
| 21 | email-subscribers | CVE-2022-0439 | 100,000 | Blind SQL Injection | WPScan |
| 22 | learnpress | CVE-2022-0271 | 100,000 | Reflected XSS | WPScan |
| 23 | menu-image | CVE-2022-0450 | 100,000 | Stored XSS | WPScan |
| 24 | modern-events-calendar-lite | CVE-2021-24925 | 100,000 | Reflected XSS | WPScan |
| 25 | modern-events-calendar-lite | CVE-2021-24946 | 100,000 | Blind SQL injection | WPScan |
| 26 | modern-events-calendar-lite | CVE-2021-25046 | 100,000 | Stored XSS | WPScan |
| 27 | paid-memberships-pro | CVE-2021-25114 | 100,000 | Blind SQL Injection | WPScan |
| 28 | squirrly-seo | CVE-2021-25019 | 100,000 | Reflected XSS | WPScan |
| 29 | ti-woocommerce-wishlist | CVE-2022-0412 | 100,000 | Blind SQL Injection | WPScan |
| 30 | webp-converter-for-media | CVE-2021-25074 | 100,000 | Open redirect | WPScan |
| 31 | woocommerce-products-filter | CVE-2021-25085 | 100,000 | Reflected XSS | WPScan |
| 32 | wpvivid-backuprestore | CVE-2021-24994 | 100,000 | Stored XSS | WPScan |
| 33 | wpvivid-backuprestore | CVE-2022-0531 | 100,000 | Reflected XSS | WPScan |
| 34 | advanced-cf7-db | CVE-2021-24905 | 90,000 | Arbitrary file removal | WPScan |
| 35 | kingcomposer | CVE-2021-25048 | 90,000 | Stored XSS | WPScan |
| 36 | kingcomposer | CVE-2022-0165 | 90,000 | Open redirect | WPScan |
| 37 | social-networks-auto-poster-facebook-twitter-g | CVE-2021-24975 | 90,000 | Stored XSS | WPScan |
| 38 | social-networks-auto-poster-facebook-twitter-g | CVE-2021-25072 | 90,000 | CSRF post removal | WPScan |
| 39 | themify-portfolio-post | CVE-2022-0200 | 80,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 40 | woo-product-feed-pro | CVE-2021-24974 | 80,000 | Stored XSS | WPScan |
| 41 | woo-product-feed-pro | CVE-2022-0426 | 80,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 42 | www-xml-sitemap-generator-org | CVE-2022-0346 | 70,000 | Reflected XSS and RCE | WPScan |
| 43 | booking | CVE-2021-25040 | 60,000 | Reflected XSS | WPScan |
| 44 | interactive-3d-flipbook-powered-physics-engine | CVE-2022-0423 | 60,000 | Stored XSS | WPScan |
| 45 | mappress-google-maps-for-wordpress | CVE-2022-0208 | 60,000 | Reflected XSS | WPScan |
| 46 | permalink-manager | CVE-2022-0201 | 60,000 | Reflected XSS | WPScan |
| 47 | post-grid | CVE-2022-0447 | 60,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 48 | powerpack-lite-for-elementor | CVE-2021-25027 | 60,000 | Reflected XSS | WPScan |
| 49 | real-cookie-banner | CVE-2022-0445 | 60,000 | CSRF settings reset and deleting all GDPR consents | WPScan |
| 50 | wd-instagram-feed | CVE-2021-25047 | 60,000 | Reflected XSS | WPScan |
| 51 | woocommerce-currency-switcher | CVE-2021-25043 | 60,000 | Reflected XSS | WPScan |
| 52 | woocommerce-currency-switcher | CVE-2022-0234 | 60,000 | Reflected XSS | WPScan |
| 53 | wp-responsive-menu | CVE-2021-24971 | 60,000 | Stored XSS | WPScan |
| 54 | wp-rss-aggregator | CVE-2021-24988 | 60,000 | Stored XSS | WPScan |
| 55 | wp-rss-aggregator | CVE-2022-0189 | 60,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 56 | ditty-news-ticker | CVE-2022-0533 | 50,000 | Reflected XSS | WPScan |
| 57 | event-tickets | CVE-2021-25028 | 50,000 | Open redirect | WPScan |
| 58 | nimble-builder | CVE-2022-0314 | 50,000 | Reflected XSS | WPScan |
| 59 | simple-membership | CVE-2022-0328 | 50,000 | CSRF member deletion | WPScan |
| 60 | super-socializer | CVE-2021-24987 | 50,000 | Reflected XSS | WPScan |
| 61 | bnfw | CVE-2022-0345 | 40,000 | E-mail leak | WPScan |
| 62 | thirstyaffiliates | CVE-2022-0398 | 40,000 | Arbitrary affiliate link creation | WPScan |
| 63 | tutor | CVE-2021-25017 | 40,000 | Reflected XSS | WPScan |
| 64 | advanced-cron-manager | CVE-2021-25084 | 30,000 | Arbitrary cron configuration change | WPScan |
| 65 | contact-form-7-skins | CVE-2021-25063 | 30,000 | Reflected XSS | WPScan |
| 66 | content-egg | CVE-2022-0428 | 30,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 67 | easy-paypal-donation | CVE-2021-24989 | 30,000 | CSRF post removal | WPScan |
| 68 | futurio-extra | CVE-2021-25110 | 30,000 | E-mail leak | WPScan |
| 69 | google-pagespeed-insights | CVE-2022-0431 | 30,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 70 | insight-core | CVE-2021-24950 | 30,000 | Stored XSS + object injection | WPScan |
| 71 | lead-form-builder | CVE-2021-24967 | 30,000 | Stored XSS | WPScan |
| 72 | master-addons | CVE-2022-0327 | 30,000 | Reflected XSS | WPScan |
| 73 | meks-easy-instagram-widget | CVE-2021-24958 | 30,000 | Stored XSS | WPScan |
| 74 | my-calendar | CVE-2021-24927 | 30,000 | Reflected XSS | WPScan |
| 75 | notificationx | CVE-2022-0349 | 30,000 | Blind SQL Injection | WPScan |
| 76 | photo-gallery | CVE-2022-0169 | 30,000 | SQL Injection | WPScan |
| 77 | protect-wp-admin | CVE-2021-24906 | 30,000 | Disabling of plugin security features | WPScan |
| 78 | pz-linkcard | CVE-2021-25012 | 30,000 | Reflected XSS | WPScan |
| 79 | site-reviews | CVE-2021-24973 | 30,000 | Stored XSS | WPScan |
| 80 | ultimate-faqs | CVE-2021-24968 | 30,000 | Possibility to add arbitrary FAQs | WPScan |
| 81 | video-conferencing-with-zoom-api | CVE-2022-0384 | 30,000 | E-mail leak | WPScan |
| 82 | woo-smart-wishlist | CVE-2022-0397 | 30,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 83 | wp-user-frontend | CVE-2021-25076 | 30,000 | SQL injection in admin panel leading to reflected XSS | WPScan |
| 84 | xcloner-backup-and-restore | CVE-2022-0444 | 30,000 | Resetting settings, including encryption key | WPScan |
| 85 | ad-invalid-click-protector | CVE-2022-0190 | 20,000 | SQL injection | WPScan |
| 86 | ad-invalid-click-protector | CVE-2022-0191 | 20,000 | CSRF ban removal | WPScan |
| 87 | advanced-product-labels-for-woocommerce | CVE-2022-0399 | 20,000 | Reflected XSS (logged-in POST 3) | WPScan |
| 88 | asgaros-forum | CVE-2022-0411 | 20,000 | Blind SQL Injection | WPScan |
| 89 | bwp-google-xml-sitemaps | CVE-2022-0230 | 20,000 | Stored XSS | WPScan |
| 90 | crazy-bone | CVE-2022-0385 | 20,000 | Stored XSS | WPScan |
| 91 | event-calendar-wd | CVE-2021-25024 | 20,000 | XSS | WPScan |
| 92 | event-calendar-wd | CVE-2021-25025 | 20,000 | Possibility to add arbitrary events | WPScan |
| 93 | float-menu | CVE-2022-0313 | 20,000 | CSRF menu deletion | WPScan |
| 94 | gmap-embed | CVE-2021-25011 | 20,000 | Arbitrary post removal, plugin settings update | WPScan |
| 95 | gmap-embed | CVE-2021-25081 | 20,000 | Arbitrary post removal, plugin settings update via CSRF | WPScan |
| 96 | image-hover-effects-ultimate | CVE-2021-25031 | 20,000 | Reflected XSS | WPScan |
| 97 | material-design-for-contact-form-7 | CVE-2022-0404 | 20,000 | DoS | WPScan |
| 98 | miniorange-2-factor-authentication | CVE-2022-0229 | 20,000 | DoS | WPScan |
| 99 | mycred | CVE-2021-25015 | 20,000 | Reflected XSS | WPScan |
| 100 | mycred | CVE-2022-0287 | 20,000 | E-mail leak | WPScan |
| 101 | mycred | CVE-2022-0363 | 20,000 | Arbitrary post creation | WPScan |
| 102 | mystickyelements | CVE-2022-0148 | 20,000 | Reflected XSS | WPScan |
| 103 | navz-photo-gallery | CVE-2021-24909 | 20,000 | Reflected XSS | WPScan |
| 104 | newstatpress | CVE-2022-0206 | 20,000 | Reflected XSS | WPScan |
| 105 | page-views-count | CVE-2022-0434 | 20,000 | SQL injection | WPScan |
| 106 | restaurant-reservations | CVE-2021-24965 | 20,000 | Stored XSS | WPScan |
| 107 | woocommerce-product-addon | CVE-2021-25018 | 20,000 | Stored XSS | WPScan |
| 108 | wp-accessiblity-helper | CVE-2022-0150 | 20,000 | Reflected XSS | WPScan |
| 109 | wp-stats-manager | CVE-2021-24750 | 20,000 | SQL injection | WPScan |
| 110 | wp-stats-manager | CVE-2021-25042 | 20,000 | Stored XSS | WPScan |
| 111 | wp-stats-manager | CVE-2022-0410 | 20,000 | Blind SQL Injection | WPScan |
| 112 | wplegalpages | CVE-2021-25106 | 20,000 | Stored XSS | WPScan |
| 113 | advanced-page-visit-counter | CVE-2021-24957 | 10,000 | Blind SQL injection | WPScan |
| 114 | advanced-page-visit-counter | CVE-2021-25086 | 10,000 | Stored XSS | WPScan |
| 115 | affiliates-manager | CVE-2021-25078 | 10,000 | Stored XSS | WPScan |
| 116 | akismet-privacy-policies | CVE-2021-25071 | 10,000 | Reflected XSS | WPScan |
| 117 | ari-fancy-lightbox | CVE-2022-0161 | 10,000 | Reflected XSS | WPScan |
| 118 | business-profile | CVE-2021-25060 | 10,000 | Stored XSS | WPScan |
| 119 | coming-soon-page | CVE-2022-0164 | 10,000 | Sending any e-mail to all subscribers | WPScan |
| 120 | coming-soon-page | CVE-2022-0199 | 10,000 | Sending any e-mail to all subscribers via CSRF | WPScan |
| 121 | dropdown-menu-widget | CVE-2021-25113 | 10,000 | Stored XSS | WPScan |
| 122 | duplicate-page-or-post | CVE-2021-25075 | 10,000 | Stored XSS | WPScan |
| 123 | easy-pricing-tables | CVE-2021-25098 | 10,000 | CSRF post removal | WPScan |
| 124 | english-wp-admin | CVE-2021-25111 | 10,000 | Open redirect | WPScan |
| 125 | ibtana-visual-editor | CVE-2021-25014 | 10,000 | Stored XSS | WPScan |
| 126 | ip2location-country-blocker | CVE-2021-25095 | 10,000 | Banning arbitrary countries | WPScan |
| 127 | ip2location-country-blocker | CVE-2021-25096 | 10,000 | Ban circumvention | WPScan |
| 128 | ip2location-country-blocker | CVE-2021-25108 | 10,000 | Banning countries via CSRF | WPScan |
| 129 | link-library | CVE-2021-25091 | 10,000 | Reflected XSS | WPScan |
| 130 | link-library | CVE-2021-25092 | 10,000 | CSRF settings reset | WPScan |
| 131 | link-library | CVE-2021-25093 | 10,000 | Arbitrary link removal | WPScan |
| 132 | modal-window | CVE-2021-25051 | 10,000 | CSRF RCE | WPScan |
| 133 | page-builder-add | CVE-2021-25067 | 10,000 | Reflected XSS | WPScan |
| 134 | portfolio-wp | CVE-2021-25090 | 10,000 | Stored XSS | WPScan |
| 135 | powerpack-addon-for-beaver-builder | CVE-2022-0176 | 10,000 | Reflected XSS | WPScan |
| 136 | qubely | CVE-2021-25013 | 10,000 | Arbitrary post removal | WPScan |
| 137 | rearrange-woocommerce-products | CVE-2021-24928 | 10,000 | SQL injection | WPScan |
| 138 | registrations-for-the-events-calendar | CVE-2021-24943 | 10,000 | SQL injection | WPScan |
| 139 | registrations-for-the-events-calendar | CVE-2021-25083 | 10,000 | Reflected XSS | WPScan |
| 140 | secure-copy-content-protection | CVE-2021-24931 | 10,000 | SQL injection | WPScan |
| 141 | smart-forms | CVE-2022-0163 | 10,000 | Downloading form data | WPScan |
| 142 | spider-event-calendar | CVE-2022-0212 | 10,000 | Reflected XSS | WPScan |
| 143 | stopbadbots | CVE-2021-25070 | 10,000 | Blind SQL injection | WPScan |
| 144 | ultimate-product-catalogue | CVE-2021-24993 | 10,000 | Possibility to add arbitrary products | WPScan |
| 145 | whmcs-bridge | CVE-2021-25112 | 10,000 | Reflected XSS | WPScan |
| 146 | wicked-folders | CVE-2021-24919 | 10,000 | SQL injection | WPScan |
| 147 | woo-orders-tracking | CVE-2021-25062 | 10,000 | Reflected XSS | WPScan |
| 148 | woocommerce-exporter | CVE-2022-0149 | 10,000 | Reflected XSS | WPScan |
| 149 | woocommerce-store-toolkit | CVE-2021-25077 | 10,000 | Reflected XSS | WPScan |
| 150 | wp-booking-system | CVE-2021-25061 | 10,000 | Reflected XSS | WPScan |
| 151 | wp-coder | CVE-2021-25053 | 10,000 | CSRF RCE | WPScan |
| 152 | wp-photo-album-plus | CVE-2021-25115 | 10,000 | Stored XSS | WPScan |
| 153 | wp125 | CVE-2021-25073 | 10,000 | CSRF ad deletion | WPScan |
| 154 | wpcargo | CVE-2021-25003 | 10,000 | RCE | WPScan |
| 155 | events-made-easy | CVE-2021-25030 | 7,000 | SQL injection | WPScan |
| 156 | likebtn-like-button | CVE-2021-24945 | 7,000 | Sensitive data exposure | WPScan |
| 157 | likebtn-like-button | CVE-2022-0745 | 7,000 | Arbitrary e-mail sending | WPScan |
| 158 | wp-email-users | CVE-2021-24959 | 7,000 | SQL injection + object injection | WPScan |
| 159 | responsive-vector-maps | CVE-2021-24947 | 6,000 | Arbitrary file read | WPScan |
| 160 | button-generation | CVE-2021-25052 | 5,000 | CSRF RCE | WPScan |
Выводы, достойные упоминания
Я не буду высмеивать какого-либо конкретного автора плагина, однако считаю, что некоторыми выводами стоит поделиться.
is_admin
Функция WordPress is_admin(), как вы уже, наверное, догадались определяет, предназначен ли текущий запрос для страницы административного интерфейса.
(с сайта https://developer.wordpress.org/reference/functions/is_admin/)
Документация также предупреждает, что она не проверяет, является ли пользователь администратором; для проверки ролей и возможностей используйте функцию current_user_can().
Как вы уже, наверное, догадались, это стало источником пары уязвимостей в виде:
Код:
if (is_admin()) {
/* опасное действие */
}
URL-адреса REST-маршрутов
Рассмотрим следующий код:
Код:
register_rest_route((...), '/(...)/(?P<id>[\d]+)', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'callback'),
'permission_callback' => '__return_true',
),
));
/* ... */
function callback($request) {
$id = $request['id'];
}
Какие значения ID могут быть переданы в обработчик? Правильный ответ: все - просто используйте /?rest_route=/(...)/1&id=hehehe.
get_users()
Некоторые плагины позволяют искать пользователей по части адреса электронной почты. Это позволяет слить e-mail любого пользователя, используя следующие шаги:
- Перебор первой буквы доменного имени (поиск по @a, @b и т.д. и проверка, когда имя пользователя появляется в результатах поиска).
- Запоминание первой буквы и использование ее для угадывания второй буквы. Допустим, доменное имя электронной почты пользователя начинается с g. Тогда можно перебором найти вторую букву (@ga, @gb, ...).
- Повторяем описанные выше действия для остальной части адреса электронной почты.
В связи с этим я добавил проверку, которая предупреждает о вызове get_users(). К сожалению, помимо обнаружения уязвимостей данного типа, она также привела к многочисленным ложным срабатываниям.
Защита от XSS
Не делайте следующее:
Код:
if (/* обнаружен потенциальный XSS в $parameter */) die('Invalid parameter: ' . $parameter);
Несколько XSS-уязвимостей также были вызваны отладочными помощниками в виде:
Код:
echo "<!--";
var_dump($_POST);
echo "-->";
Проверка CAPTCHA
Не делайте этого:
Код:
if (isset($_POST['captcha'])) {
/* проверяем капчу */
}
/* выполнить действие, которое должно быть защищено CAPTCHA */
Выводы
Это была лишь пробная версия, чтобы проверить, являются ли автоматические методы жизнеспособным методом для поиска ошибок в плагинах WordPress. Я уверен, что он может быть улучшен, например, путем
- добавлением проверок для обнаружения других типов опасных операций,
- попытаться уменьшить количество ложных срабатываний без большой потери истинных срабатываний. Процент ложных срабатываний был одним из главных препятствий в этом проекте.
Эта техника может быть реализована и для других экосистем плагинов.
Многие из найденных мною уязвимостей легко предотвратить с помощью современных методов разработки программного обеспечения. Во многих плагинах WordPress HTML строится с помощью подверженной ошибкам кучи echo-заявлений, вместо языка шаблонов. Аналогично, конечные точки AJAX по умолчанию доступны для всех вошедших или не вошедших пользователей, вместо того чтобы требовать от разработчика фиксированного списка ролей или разрешений (так что им пришлось бы явно отмечать маршрут как доступный для всех вошедших пользователей). Внедрение методов, затрудняющих совершение ошибок, и поощрение их использования - это, к сожалению, то, что может сделать только команда WordPress, а не разработчики плагинов.