Что это за строка?

Строка %" AND EXTRACTVALUE(6040,CONCAT(0x7e,((SELECT (ELT(6040=6040,1)))),0x7e))-- - представляет собой классический пример error-based SQL-инъекции для СУБД MySQL. Она предназначена для извлечения данных из базы через вывод сообщения об ошибке. Подобные конструкции часто встречаются в отчётах об уязвимостях и пентестах.

Внешне это выглядит как бессмысленный набор символов, но каждый элемент здесь имеет строгое назначение. Давайте разберём её по частям.

Разбор компонентов

1. Начало: %"

Символ % часто используется в URL-кодировании, но в данном контексте это, скорее всего, часть полезной нагрузки, которая попала в строку запроса. Далее идёт " — закрывающая кавычка, которая разрывает исходное строковое значение в SQL-запросе. Это типичный приём для внедрения в параметры, где ожидается строка в кавычках.

2. AND

Логический оператор AND добавляется, чтобы внедряемое условие было истинным и не нарушало синтаксис исходного запроса. Если исходный запрос был SELECT ... WHERE id = '...', то после подстановки получается WHERE id = '%" AND ... — и часть с AND выполняется только если первое условие истинно (или ложно, в зависимости от логики).

3. EXTRACTVALUE(6040, CONCAT(...))

EXTRACTVALUE — это функция MySQL для работы с XML. Она извлекает значение из XML-строки по указанному XPath-выражению. Синтаксис: EXTRACTVALUE(XML_document, XPath_expression). Если XPath-выражение некорректно, MySQL генерирует ошибку, в тексте которой может содержаться переданное значение.

В нашем случае первый аргумент — 6040 (просто число, которое будет преобразовано в строку XML). Второй аргумент — CONCAT(0x7e, ..., 0x7e) — конкатенация символа ~ (0x7e в hex) с некоторым выражением и снова ~. Символ ~ используется как маркер, чтобы в сообщении об ошибке было легко найти извлечённые данные.

4. CONCAT(0x7e, ((SELECT (ELT(6040=6040,1)))), 0x7e)

Здесь 0x7e — это шестнадцатеричное представление символа ~ (тильда). CONCAT объединяет тильду, результат подзапроса и снова тильду.

Подзапрос: (SELECT (ELT(6040=6040,1))). ELT — функция MySQL, которая возвращает N-й элемент из списка. ELT(N, str1, str2, ...) возвращает str1, если N=1, str2, если N=2, и т.д. В данном случае 6040=6040 — это выражение, которое всегда истинно (1). Значит, ELT(1, 1) вернёт 1. То есть подзапрос возвращает число 1. Это простейший пример; в реальной атаке вместо 1 могло бы быть имя пользователя, пароль или другая конфиденциальная информация, полученная через подзапрос.

5. Завершение: -- -

Два дефиса -- начинают комментарий в SQL. Всё, что идёт после них, игнорируется. Пробел после -- (или дефис в данном случае) нужен, чтобы некоторые парсеры корректно распознали комментарий. Это позволяет отсечь остаток оригинального запроса, который мог бы вызвать синтаксическую ошибку.

Как это работает целиком

Предположим, уязвимый запрос выглядит так:

SELECT * FROM users WHERE username = '$input';

Если в $input передать нашу строку, то запрос станет:

SELECT * FROM users WHERE username = '%" AND EXTRACTVALUE(6040,CONCAT(0x7e,((SELECT (ELT(6040=6040,1)))),0x7e))-- -';

После закрывающей кавычки и AND выполняется функция EXTRACTVALUE. Так как второй аргумент не является корректным XPath (начинается с ~), MySQL выдаст ошибку вида:

XPATH syntax error: '~1~'

В этом сообщении мы видим ~1~ — это и есть результат подзапроса, обрамлённый тильдами. Если бы вместо 1 был, например, database(), мы бы увидели имя текущей базы данных. Таким образом, злоумышленник может извлекать произвольные данные, вызывая ошибки.

Зачем это нужно?

Error-based SQL-инъекции — мощный инструмент в руках атакующего, когда другие методы (union-based, blind) не работают. Они позволяют быстро получить информацию о структуре базы, учётных данных и т.д. Однако современные СУБД и фреймворки часто отключают вывод подробных ошибок, что делает такие атаки менее эффективными.

Как защититься?

  • Используйте параметризованные запросы (prepared statements). Это самый надёжный способ предотвратить SQL-инъекции.
  • Экранируйте пользовательский ввод. Но помните, что экранирование не панацея.
  • Отключайте вывод ошибок СУБД на продакшене. Ошибки должны логироваться, но не показываться пользователю.
  • Применяйте принцип наименьших привилегий. Учётная запись приложения должна иметь только необходимые права.
  • Регулярно обновляйте СУБД и фреймворки. Многие уязвимости закрываются в новых версиях.

Заключение

Строка %" AND EXTRACTVALUE(6040,CONCAT(0x7e,((SELECT (ELT(6040=6040,1)))),0x7e))-- - — это учебный пример эксплуатации error-based SQL-инъекции в MySQL. Понимание таких конструкций помогает разработчикам и специалистам по безопасности лучше защищать свои приложения. Никогда не используйте подобные техники против систем, на которые у вас нет разрешения.

Источники