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

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

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

Анатомия запроса

1. Начальный фрагмент %'

Символ % часто используется в SQL-шаблонах LIKE. Здесь он, скорее всего, является частью исходного запроса, в который внедряется инъекция. Апостроф ' закрывает строковый литерал, позволяя злоумышленнику добавить собственный SQL-код. Например, если уязвимый запрос выглядит как SELECT * FROM users WHERE name LIKE '%...%', то подстановка %' AND ... разрывает строку и добавляет условие.

2. Функция EXTRACTVALUE(6486, CONCAT(...))

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

В нашем случае первым аргументом передаётся число 6486 — оно не является корректным XML-документом, но это не важно: злоумышленник использует функцию исключительно как «генератор ошибок».

3. CONCAT(0x7e, ..., 0x7e)

Функция CONCAT объединяет строки. 0x7e — это шестнадцатеричное представление символа тильды ~. Тильда выбрана не случайно: она не является допустимым символом в XPath-выражении, поэтому её наличие гарантированно вызывает ошибку синтаксиса. Это нужно, чтобы MySQL вывел сообщение об ошибке, содержащее полезную нагрузку.

4. Подзапрос (SELECT (ELT(6486=6486,1)))

Внутренний подзапрос возвращает результат выражения ELT(6486=6486,1). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь N — это результат сравнения 6486=6486, который всегда истинен и равен 1. Следовательно, ELT(1,1) вернёт строку '1'. Таким образом, подзапрос возвращает строку '1'.

В реальной атаке вместо ELT(6486=6486,1) подставляются вызовы вроде (SELECT DATABASE()) или (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE()), чтобы извлечь имя текущей базы данных или список таблиц. В нашем примере используется безобидная заглушка, чтобы продемонстрировать структуру.

5. Комментарий -- -

Два дефиса с пробелом (или -- -) — это комментарий в MySQL. Он «отрезает» оставшуюся часть оригинального запроса, чтобы синтаксис оставался корректным. Пробел после дефисов обязателен в некоторых реализациях, отсюда и дополнительный дефис.

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

Соберём логику:

  1. Апостроф закрывает строку в уязвимом запросе.
  2. Добавляется условие AND EXTRACTVALUE(6486, CONCAT(0x7e, (SELECT (ELT(6486=6486,1))), 0x7e)).
  3. Внутри CONCAT формируется строка вида ~1~ (тильда, результат подзапроса, тильда).
  4. EXTRACTVALUE пытается интерпретировать эту строку как XPath-выражение, но тильды недопустимы, поэтому возникает ошибка.
  5. MySQL возвращает сообщение об ошибке, в котором фигурирует переданная строка, например: XPATH syntax error: '~1~'.
  6. Злоумышленник видит результат выполнения подзапроса (в данном случае 1) в тексте ошибки.

Если заменить ELT(6486=6486,1) на полезный запрос, например (SELECT DATABASE()), то в ошибке отобразится имя текущей базы данных. Такой метод позволяет извлекать произвольные данные посимвольно или целыми строками, если использовать GROUP_CONCAT.

Зачем это нужно злоумышленнику?

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

Описанная конструкция с EXTRACTVALUE и CONCAT(0x7e,...) стала классикой благодаря своей надёжности: она работает на многих версиях MySQL, где функция EXTRACTVALUE ещё не удалена. В MySQL 8.0.17 и новее эта функция помечена как устаревшая, но во многих реальных системах всё ещё используются старые версии.

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

Лучший способ — не допускать попадания пользовательского ввода в SQL-запросы без обработки. Основные меры:

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

Итог

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

Источники