Что это за строка?
Строка '))) AND EXTRACTVALUE(3501,CONCAT(0x7e,((SELECT (ELT(3501=3501,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции (инъекции на основе ошибок) для СУБД MySQL. Такие конструкции используют для извлечения данных из базы данных через сообщения об ошибках, которые возвращает сервер.
Внешне это выглядит как бессмысленный набор символов, но на самом деле каждый элемент здесь имеет строгое назначение. Давайте разберём его по частям.
Разбор структуры эксплойта
1. Начало: ')))
Три закрывающие скобки и одинарная кавычка. Это попытка «закрыть» предыдущие части оригинального SQL-запроса, чтобы внедрить свой код. Одинарная кавычка завершает строковый литерал, а скобки закрывают возможные группировки. Злоумышленник предполагает, что исходный запрос выглядит примерно так:
SELECT * FROM users WHERE id = ('$input')
Тогда после подстановки получается:
SELECT * FROM users WHERE id = (' '))) AND EXTRACTVALUE(...)-- - ')
Лишние символы отбрасываются, и внедрённое условие начинает выполняться.
2. AND EXTRACTVALUE(3501, CONCAT(0x7e, ... ,0x7e))
EXTRACTVALUE — это встроенная функция MySQL для работы с XML. Она извлекает значение из XML-фрагмента по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(xml_frag, xpath_expr).
Если XPath-выражение некорректно, MySQL генерирует ошибку, в тексте которой отображается переданный XML-фрагмент. Это и есть основа атаки: злоумышленник может поместить в XML-фрагмент результат подзапроса, и сервер вернёт его в сообщении об ошибке.
Первый аргумент — 3501 — просто число, которое будет преобразовано в строку "3501" и использовано как XML. Второй аргумент — CONCAT(0x7e, ((SELECT ...)), 0x7e). 0x7e — это шестнадцатеричное представление символа тильды (~). Тильды служат маркерами, чтобы в сообщении об ошибке было легко найти внедрённые данные.
3. Внутренний подзапрос: (SELECT (ELT(3501=3501,1)))
ELT — функция MySQL, которая возвращает N-й элемент из списка строк. Синтаксис: ELT(N, str1, str2, ...). Если N=1, возвращается первая строка, если N=2 — вторая и т.д.
Выражение 3501=3501 всегда истинно, то есть возвращает 1 (в MySQL TRUE = 1). Таким образом, ELT(1, 1) вернёт строку "1". Это простейший случай, который можно заменить на любой другой подзапрос, например, (SELECT password FROM users LIMIT 1). В данном примере просто демонстрируется работоспособность метода.
Весь подзапрос возвращает строку "1", которая затем попадает в CONCAT с тильдами: ~1~.
4. Завершение: -- -
Два дефиса и пробел — это комментарий в SQL. Всё, что идёт после -- , игнорируется сервером. Это позволяет «отрезать» оставшуюся часть оригинального запроса (например, закрывающую кавычку и скобку), чтобы не нарушать синтаксис.
Как это работает на практике
Предположим, уязвимый запрос выглядит так:
SELECT * FROM articles WHERE id = '$_GET[id]'
Злоумышленник передаёт в параметре id строку '))) AND EXTRACTVALUE(3501,CONCAT(0x7e,((SELECT (ELT(3501=3501,1)))),0x7e))-- -.
После подстановки запрос принимает вид:
SELECT * FROM articles WHERE id = ' '))) AND EXTRACTVALUE(3501,CONCAT(0x7e,((SELECT (ELT(3501=3501,1)))),0x7e))-- - '
MySQL пытается выполнить EXTRACTVALUE с XML-фрагментом "3501" и XPath-выражением "~1~". Поскольку "~1~" не является корректным XPath, возникает ошибка:
XPATH syntax error: '~1~'
В этом сообщении виден результат подзапроса — "1". Если заменить ELT на извлечение данных, например (SELECT version()), то в ошибке появится версия MySQL. Так пошагово можно вытащить любую информацию из базы.
Зачем это нужно злоумышленнику?
Error-based SQL-инъекции позволяют получать данные напрямую из сообщений об ошибках, без необходимости использовать слепые методы (boolean-based или time-based). Это быстрее и удобнее. Основные цели:
- Получение версии СУБД и другой служебной информации.
- Извлечение имён таблиц и колонок из information_schema.
- Чтение конфиденциальных данных: логинов, паролей, email, номеров карт.
- В некоторых случаях — выполнение произвольных команд через дополнительные уязвимости.
Как защититься?
Главная причина возможности таких атак — динамическое построение SQL-запросов с прямым включением пользовательского ввода. Надёжные меры защиты:
- Использование подготовленных выражений (prepared statements). Это самый эффективный способ. Параметры передаются отдельно от SQL-кода, и СУБД не интерпретирует их как часть запроса.
- Хранимые процедуры. Если они написаны корректно, риск инъекций снижается.
- Экранирование специальных символов. Например, функция
mysql_real_escape_string()в PHP, но она не гарантирует полной защиты при неправильной настройке кодировки. - Ограничение прав пользователя БД. Не давайте приложению прав на чтение information_schema или выполнение опасных функций.
- Валидация входных данных. Если параметр должен быть числом, приводите его к числу, а не просто проверяйте регуляркой.
- Использование WAF (Web Application Firewall). Может блокировать известные сигнатуры атак, но не является панацеей.
Важно понимать, что EXTRACTVALUE — не единственная функция, используемая в error-based инъекциях. Аналогично применяются UPDATEXML, GTID_SUBSET, EXP и другие. Однако принцип остаётся тем же: вызвать ошибку, содержащую полезные данные.
Заключение
Строка '))) AND EXTRACTVALUE(3501,CONCAT(0x7e,((SELECT (ELT(3501=3501,1)))),0x7e))-- - — это хорошо продуманный эксплойт для error-based SQL-инъекции в MySQL. Понимание принципов его работы помогает разработчикам осознать важность защиты от SQL-инъекций и правильно применять методы предотвращения. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.
Комментарии
—Войдите, чтобы оставить комментарий