Введение
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.
Чтобы проверить работоспособность плагина, создали из имеющихся шаблонов простой Popup и разместили его на тестовой странице.
Разбор уязвимости
В исходном коде плагина нас интересует функция ls_get_popup_markup()
, находящаяся в файле assets/wp/actions.php
.
Она является обработчиком HTTP GET запроса /wp-admin/admin-ajax.php?action=ls_get_popup_markup
.
Из исходного кода видно, что плагин использует данную функцию для получения popup’a по id
, где идентификатор может быть указан с помощью GET параметра. И если id
не является числом, то он напрямую попадает в функцию find()
класса LS_Sliders
.
В самой функции find()
, аргумент проходит несколько проверок. Первая из них - это проверка на тип. Прочитав конструкцию условного ветвления, становится понятно, что поддерживаются несколько вариантов аргумента, но нам интересен только последний, когда аргументом является map.
Начиная с 80 строки кода, мы можем наблюдать, как формируется запрос к базе данных. Примечательным местом тут является цикл со 102 строки по 107. Он написан с целью так называемого эскейпа спец символов SQL из пользовательского ввода. В результате такой процедуры все спецсимволы SQL синтаксиса просто экранируются. Но если обратить внимание на условие внутри данного цикла, становится ясно, что это не происходит с элементом стоящим под ключом 'where'
. Скорее всего это было сделано с целью поддержки каких-то пользовательских фильтров на языке SQL, так как в коде ниже мы видим, как из этого элемента формируются дополнительные условия запроса.
В конце все части аргументов собираются в один запрос и он отправляется базе данных.
В итоге получается, что любые специальные символы и слова языка 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
Из результата работы инструмента, помимо данных, можно увидеть, что он определил тип SQL-инъекции как time-based blind и использовал SLEEP
в своих пэйлоадах.
Меры защиты
К счастью, эта уязвимость уже устранена в версии 7.10.1 LayerSlider, и всем пользователям данного плагина настоятельно рекомендуется обновиться до последней версии. Если обновление невозможно, тогда есть шанс, что удастся снизить некоторые риски с помощью WAF, который должен быть настроен на блокирование попыток внедрения SQL-кода, хотя на это не следует полагаться.
Заключение
В данной статье мы детально разобрали уязвимость в плагине LayerSlider для WordPress, позволяющую выполнять произвольные запросы к базе данных и, как следствие, получать любую чувствительную информацию из нее.
Подписывайтесь на наш Telegram-канал