
CalderaForms 1.5.9.1 XSS (плагин WordPress) - руководство
CalderaForms 1.5.9.1 XSS (WordPress плагин) - учебное руководство
CalderaForm — это плагин для WordPress, позволяющий легко создавать формы с помощью drag and drop. Во время недавней работы мне довелось тестировать несколько порталов, один из которых содержал контактную форму, созданную с помощью этого плагина. Особая конфигурация данного инстанса позволила мне найти уязвимость: благодаря своей простоте, похожей на учебную, я думаю, это хороший повод проиллюстрировать некоторые механизмы новичкам.
Исключительно в образовательных целях - не используйте эту информацию для тестирования целей без явного разрешения и для незаконных целей - не ныряйте в холодную воду после еды - одевайтесь как луковица в жару
Полный эксплойт:
https://www.exploit-db.com/exploits/44489/
CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7747
В анализируемой конфигурации форма была настроена отвечать пользователю благодарственным сообщением, обращаясь к нему по только что введённому имени.
Чтобы воспроизвести тестовую среду, установите локально экземпляр WordPress и установите плагин CalderaForms версии 1.5.9.1 (доступен здесь или здесь).
После установки: в консоли администратора WordPress > левая колонка > "Caldera Forms" > верхние кнопки > "New Form" > выберите Contact Form, переименуйте и "Create Form"

После создания можно изменить его конфигурацию: верхние кнопки > "Form Settings" > измените Success Message так, чтобы он включал одно из введённых пользователем данных. Нажмите на поле, и появится выпадающий список подсказок.
Добавьте %first_name%

Верхние кнопки > "Save Form"
Чтобы вставить форму на страницу: левая колонка > "Pages" > "Sample Page" > "Edit" > "Caldera Form" > выберите созданную форму > "Insert Form" > правая колонка > "Update"

Готово.
Разберём по одному все шаги, необходимые для построения такой атаки, следуя парадигме «разделяй и властвуй».
При тестировании, когда вы взаимодействуете с компонентом, всегда нужно обращать внимание на его реакции на подаваемые стимулы; в частности, мы сосредоточимся на «пути» введённых нами данных и возможных преобразованиях, которым они подвергаются.
Конкретный пример для нашего случая следующий:
Посещаем страницу, содержащую форму: http://127.0.0.1/wordpress/sample-page/
Заполняем форму следующими данными
"First Name": myName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Данные обрабатываются согласно логике плагина
Полученное благодарственное сообщение содержит строку, которую мы ввели в поле First Name
"Thank you myName, form has been successfully submitted."

Строка, введённая нами в поле "First Name", возвращается нам в благодарственном сообщении.
В частности, строка содержится в HTML-теге div.
Наш ввод попадает в HTML страницы.
Вывод: «Нам это нравится. У нас есть точка контакта.»
Сделаем шаг вперёд. Как обрабатывается наш ввод на этапе, который мы назвали «обработкой» (пункт 2)? В частности, мы хотим узнать: есть ли ограничения на символы (и их комбинации), которые мы можем использовать?
Очевидно, цель — суметь внедрить «что-нибудь». При попытке выполнить инъекцию нужно помнить, где заканчивается наш ввод, и использовать подходящий «язык».
Наш ввод обрабатывается SQL-интерпретатором? Нужно говорить на его языке
Наш ввод обрабатывается PHP-скриптом? Нужно говорить на его языке
Наш ввод попадает на HTML-страницу? ...
Поэтому нам интересно понять, можем ли мы использовать типичные для HTML символы и конструкции, и в частности, учитывая способность этого языка содержать/интерпретировать код JavaScript, понять, найдём ли мы стратегию для размещения нашего кода в «зоне приземления», то есть в отмеченном ранее теге div.
Для этого вставим в поле "First Name" простой HTML-тег и посмотрим, будет ли он «санитизирован» (от sanitized), то есть изменён так, чтобы стать безвредным/неинтерпретируемым, или же будет возвращён как есть. Используем для этого тег <br>, который применяется для вставки разрыва строки в текст.
Следуя предыдущей нумерации:
Заполняем форму следующими данными
"First Name": m<br>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Благодарственное сообщение содержит наш HTML-тег, который не был изменён и корректно интерпретирован, вставляя разрыв строки в середину сообщения
"Thank you m
yName, form has been successfully submitted."

Вывод: «Нам это нравится. Мы можем использовать символы „меньше“ и „больше“, можем вставлять HTML-теги, которые не санитизируются и интерпретируются.»
Шаг вперёд. Заменим тег форматирования на что-то более полезное, например на тег <script>, который позволяет вставлять и выполнять код JavaScript внутри страницы.
Заполняем форму следующими данными
"First Name": m<script>alert(1);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Благодарственное сообщение содержит наш HTML-тег, который не был изменён и корректно интерпретирован, показывая нам окно alert

Вывод 1: «Нам это нравится. Мы можем выполнять произвольный код JavaScript в контексте браузера пользователя.»
Вывод 2: «Нам это не нравится. Пользователь, выполняющий JavaScript, — мы сами»
Ситуация такая: мы можем выполнять JavaScript через сайт, который не контролируем, в контексте браузера пользователя, но этот пользователь в данный момент — тот же, кто вводит значения в форму. Всё это довольно бесполезно.
Идея в следующем: существует ли способ вызвать благодарственное сообщение, содержащее наш код, который нужно выполнить?
Вернёмся к нашей первой отправке, «разведывательной» (или заново выполним первые шаги).
Анализируя сетевой трафик или исходный код страницы, мы понимаем, что форма выполняет POST-запрос на адрес
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4
(последняя часть может меняться; измените её соответствующим образом во всех следующих примерах)
то есть на адрес
http://<target>/cf-api/<form-id>
и что ответ на этот запрос — JSON, содержащий некоторые данные, включая благодарственное сообщение, со следующей структурой:
{
"data":
{"cf_id":"48"},
"html":"<div class=\" alert alert-success\">Thank you myName, form has been successfully submitted.<\/div>",
"type":"complete",
"form_id":"CF5ad9b3176c0f4",
"form_name":"MyContactForm",
"status":"complete"
}
Отложим эту информацию в сторону, скоро мы к ней вернёмся; особенно обратите внимание на поля "form_id" и "cf_id".
Что находится по адресу, на который выполняется POST? Не будем строить догадок — посмотрим, что произойдёт, если выполнить GET, то есть посетить страницу по адресу http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4, и обнаружим, ни много ни мало, HTML этой формы.