
SureForms <= 2.2.0 - Неаутентифицированное хранимое Cross-Site Scripting
Критическая уязвимость Stored XSS существует в плагине SureForms. Уязвимость возникает из-за небезопасной реализации на стороне клиента в entries.js, где пользовательский ввод программно декодируется (отменяя серверную санитацию) и затем отображается с помощью dangerouslySetInnerHTML без надлежащей санитации на стороне клиента. Это позволяет неаутентифицированным злоумышленникам внедрять вредоносные JavaScript-нагрузки через стандартные поля формы, обходя стандартные фильтры WordPress.
wp_ksesЧтобы проверить, работает ли целевой сайт с SureForms, проверьте заголовок файла перевода, который обычно содержит номер версии.
Целевой URL:
http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot
Команда проверки:
curl -s "http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot" | grep "Project-Id-Version"
Уязвимость находится в React-интерфейсе администратора, предназначенном для просмотра записей формы (entries.js).
В минифицированном файле entries.js есть вспомогательная функция (идентифицированная как Xv в проанализированной сборке), предназначенная для обработки HTML-сущностей.
Логика кода (восстановленная):
// Function Xv: Pre-processing field values
var Xv = function(input) {
var value = input.value;
// VULNERABILITY ROOT CAUSE:
// If the string contains HTML entities (e.g., <), create a textarea,
// inject the content, and extract the value.
// This effectively DECODES HTML entities back to raw HTML tags.
// Example: "<img ...>" becomes ""
if (typeof value === "string" && value.match(/&[a-zA-Z0-9#]+;/)) {
var textarea = document.createElement("textarea");
textarea.innerHTML = value;
// Logic to revert sanitization
if (textarea.value.includes("<") || textarea.value.includes(">")) {
value = textarea.value; // Now 'value' contains RAW HTML
}
}
return { ...input, value: value };
}
Анализ: Эта функция нейтрализует защиту бэкенда. Даже если WordPress правильно сохранит <script> как <script> в базе данных, эта функция преобразует его обратно в <script> сразу после получения из API.
После декодирования данные передаются в компонент рендеринга (идентифицированный как Jv).
Логика кода (восстановленная):
// Function Jv: Rendering the field
var Jv = function(props) {
var field = props.field;
var val = field.value; // This value is now raw HTML (post-decoding)
// THE TRIGGER: Check if the string looks like HTML
if (typeof val === "string" && val.match(/<[^>]+>/g)) {
// THE SINK: Render using dangerouslySetInnerHTML WITHOUT client-side sanitization (e.g., DOMPurify)
return React.createElement("span", {
dangerouslySetInnerHTML: { __html: val }
});
}
// Safe render for non-HTML text
return React.createElement("span", null, val);
}
Внедрение: Неаутентифицированный злоумышленник отправляет форму на фронтенде. Вместо использования сырых HTML-тегов (которые были бы удалены/санированы бэкендом WordPress), злоумышленник отправляет HTML-сущности.
Хранение: WordPress считает ввод (например, <img...) безопасным текстом и сохраняет его в базе данных.
Выполнение (ловушка):
Xv обнаруживает сущности и декодирует <img... обратно в ` Entries.Нажмите на запись, отправленную в Шаге 1, чтобы просмотреть детали.
Результат: Браузер выполнит JavaScript-нагрузку (alert('XSS_SUREFORMS')).