LayerSlider WordPress CVE-2024-2879

Введение

25 марта 2024 года в рамках программы Bug Bounty Extravaganza исследователь под ником 1337_wannabe обнаружил уязвимость типа SQL-injection в одном из популярных плагинов для WordPress — LayerSlider.

Уязвимость получила идентификатор CVE-2024–2879 и балл CVSS равный 9,8 (критический).

Данный недостаток хоть и является по большей части SQL-инъекцией типа blind основанной на времени, всё равно позволяет злоумышленнику легко получить конфиденциальную информацию из базы данных.

Стоит выделить, что плагин LayerSlider достаточно популярен среди пользователей WordPress и насчитывает более 1 миллиона установок. Из чего можно сделать вывод, что на данный момент остается огромное количество уязвимых сайтов в сети, которые пока не обновились до последней версии, так как автоматические обновления данным плагином не поддерживаются.

Тестовый стенд

Для тестирования данной уязвимости мы подняли WordPress версии 6.5 и установили туда уязвимый плагин LayerSlider версии 7.9.11.

b80edd69a0cfb71d61dd1724879b6856.png

Чтобы проверить работоспособность плагина, создали из имеющихся шаблонов простой Popup и разместили его на тестовой странице.

ab88b8453f6f61b1fe368dd20110ae8b.png

Разбор уязвимости

В исходном коде плагина нас интересует функция ls_get_popup_markup(), находящаяся в файле assets/wp/actions.php.

Она является обработчиком HTTP GET запроса /wp-admin/admin-ajax.php?action=ls_get_popup_markup.

aa651028af439f0f0b90c11a45de1aca.png

Из исходного кода видно, что плагин использует данную функцию для получения popup«a по id, где идентификатор может быть указан с помощью GET параметра. И если id не является числом, то он напрямую попадает в функцию find() класса LS_Sliders.

cc43c267423b724a1171c3052eeaa6e2.png

В самой функции find(), аргумент проходит несколько проверок. Первая из них — это проверка на тип. Прочитав конструкцию условного ветвления, становится понятно, что поддерживаются несколько вариантов аргумента, но нам интересен только последний, когда аргументом является map.

Начиная с 80 строки кода, мы можем наблюдать, как формируется запрос к базе данных. Примечательным местом тут является цикл со 102 строки по 107. Он написан с целью так называемого эскейпа спец символов SQL из пользовательского ввода. В результате такой процедуры все символы SQL синтаксиса просто удаляются. Но если обратить внимание на условие внутри данного цикла, становится ясно, что это не происходит с элементом стоящим под ключом 'where'. Скорее всего это было сделано с целью поддержки каких-то пользовательских фильтров на языке SQL, так как в коде ниже мы видим, как из этого элемента формируются дополнительные условия запроса.

15d09c22b635ccf875af2729af38d889.png

В конце все части аргументов собираются в один запрос и он отправляется базе данных.

e118d604403736c9f2cc7ec2123a634f.png

В итоге получается, что любые специальные символы и слова языка SQL, оставленные пользователем в параметре GET-запроса под ключом 'where', без изменений попадут напрямую в запрос к базе данных, а это означает, что в данном функционале присутствует уязвимость под названием SQL-инъекция.

Остаётся отметить, что из-за специфики того, как формируется данный запрос и какой ответ доходит до пользователя, здесь не получится реализовать UNION-based инъекцию и получить данные напрямую. Но это не исключает возможность воспользоваться time-based методом слепой SQL-инъекции.

Практическая эксплуатация

Опираясь на информацию полученную из разбора выше, можно составить подобный HTTP-запрос, где в URI, в параметре id, будет находиться наш пэйлоад.

http://192.168.3.10:32768/wp-admin/admin-ajax.php?action=ls_get_popup_markup&id[where]=1)

Обратите внимание как задается параметр id. Таким образом PHP поймет, что это тип данных array, а точнее map.

Для эксплуатации слепой SQL инъекции типа time-based мы будем использовать автоматизированный инструмент SQLmap.

В качестве аргументов укажем сформированный URI, а также параметры --level=3 и --risk=2, чтобы SQLmap проверил большее количество пэйлоадов.

Для демонстрации мы получали такие данные как имя текущего пользователя и имя хоста, для этого следует указать параметры --current-user и --hostname.

Итоговая команда получилась следующая:

sqlmap "http://192.168.3.10:32768/wp-admin/admin-ajax.php?action=ls_get_popup_markup&id[where]=1)" --level=3 --risk=2 --current-user --hostname

e7fffdacb94417100bffb08d5e06c426.png

Из результата работы инструмента, помимо данных, можно увидеть, что он определил тип SQL-инъекции как time-based blind и использовал SLEEP в своих пэйлоадах.

Меры защиты

К счастью, эта уязвимость уже устранена в версии 7.10.1 LayerSlider, и всем пользователям данного плагина настоятельно рекомендуется обновиться до последней версии. Если обновление невозможно, тогда есть шанс, что удастся снизить некоторые риски с помощью WAF, который должен быть настроен на блокирование попыток внедрения SQL-кода, хотя на это не следует полагаться.

Заключение

В данной статье мы детально разобрали уязвимость в плагине LayerSlider для WordPress, позволяющую выполнять произвольные запросы к базе данных и, как следствие, получать любую чувствительную информацию из нее.

Подписывайтесь на наш Telegram-канал

© Habrahabr.ru