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

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

Как работает этот эксплойт?

Разберём по частям:

  • %' — закрывает предыдущее строковое значение в SQL-запросе и добавляет символ % для обхода возможной фильтрации. Одинарная кавычка разрывает строку, позволяя внедрить произвольный SQL-код.
  • OR — логический оператор, который делает условие истинным, если внедрённая часть верна. Это гарантирует, что исходный запрос не сломается, но выполнится внедрённый код.
  • EXTRACTVALUE(7294,CONCAT(0x7e,((SELECT (ELT(7294=7294,1)))),0x7e)) — вызов функции MySQL EXTRACTVALUE, которая извлекает значение из XML-документа. Первый аргумент — произвольное число (7294), второй — строка, которая должна быть корректным XPath-выражением. Если второй аргумент не является валидным XPath, MySQL выбрасывает ошибку XPATH syntax error, в тексте которой отображается переданная строка. Это и есть канал утечки данных.
  • CONCAT(0x7e,((SELECT (ELT(7294=7294,1)))),0x7e) — конкатенация символа ~ (0x7e в шестнадцатеричном виде), результата подзапроса и ещё одного ~. Символы ~ служат маркерами для удобного извлечения данных из сообщения об ошибке.
  • SELECT (ELT(7294=7294,1)) — подзапрос, который возвращает 1, если условие 7294=7294 истинно (что всегда так). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь N=1, поэтому возвращается 1. В реальных атаках вместо этого подзапроса подставляют вызовы, извлекающие данные: имена таблиц, колонок, пароли и т.д. Например, SELECT table_name FROM information_schema.tables LIMIT 1.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального SQL-запроса, чтобы синтаксис был корректным.

В результате выполнения такого запроса MySQL вернёт ошибку вида: XPATH syntax error: '~1~'. Злоумышленник видит значение 1 и понимает, что инъекция работает. Далее он может извлекать любые данные, подставляя вместо ELT(7294=7294,1) другие подзапросы.

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

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

  • версию MySQL;
  • имя текущей базы данных;
  • список таблиц и колонок через information_schema;
  • учётные данные пользователей, хеши паролей, персональные данные.

Функция EXTRACTVALUE — не единственная в арсенале. Аналогично работают UPDATEXML, GTID_SUBSET, EXP (в старых версиях) и другие функции, вызывающие ошибки с подконтрольным текстом. Выбор EXTRACTVALUE часто обусловлен тем, что она доступна во многих версиях MySQL и MariaDB и стабильно возвращает данные в сообщении об ошибке.

Пример реального использования

Предположим, на сайте есть скрипт product.php?id=1, который выполняет запрос:

SELECT * FROM products WHERE id = '$id';

Если параметр id не фильтруется, злоумышленник может передать:

1' OR EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))-- -

В ответе сервера появится ошибка: XPATH syntax error: '~mydb~', где mydb — имя текущей базы данных. Аналогично можно получить версию: SELECT version(), или хеши паролей: SELECT password FROM users LIMIT 1.

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

Основной метод — использование параметризованных запросов (prepared statements). В PHP с PDO или MySQLi, в Java с JDBC, в Python с psycopg2 и т.д. Параметризация гарантирует, что пользовательский ввод никогда не интерпретируется как SQL-код.

Дополнительные меры:

  • Валидация входных данных — если параметр ожидает число, приводите его к целому типу, отбрасывайте всё, что не является числом.
  • Экранирование спецсимволов — используйте функции вроде mysqli_real_escape_string, но помните, что это не панацея.
  • Отключение вывода ошибок СУБД — на продакшене ошибки базы данных не должны попадать в ответ клиенту. Логируйте их, но не показывайте.
  • Принцип наименьших привилегий — пользователь БД для веб-приложения должен иметь доступ только к необходимым таблицам и операциям.
  • WAF — веб-application firewall может блокировать известные сигнатуры атак, но не заменяет исправление кода.

Помните, что SQL-инъекции по-прежнему входят в топ OWASP и остаются одной из самых опасных уязвимостей. Регулярно проводите аудит кода и используйте сканеры уязвимостей.

Частые вопросы

Почему используется именно 7294?

Число 7294 — произвольное. Оно не несёт смысловой нагрузки, кроме как быть первым аргументом EXTRACTVALUE. В других примерах можно встретить 7974, 3720 и т.п. Главное — чтобы функция вызвалась и сгенерировала ошибку.

Что означает 0x7e?

0x7e — шестнадцатеричное представление символа ~ (тильда). Его используют как разделитель, чтобы в сообщении об ошибке было легко найти начало и конец извлечённых данных. Тильда редко встречается в реальных данных, поэтому служит надёжным маркером.

Можно ли использовать эту инъекцию на других СУБД?

Нет, EXTRACTVALUE — специфичная для MySQL и MariaDB функция. В PostgreSQL, Oracle, MS SQL используются другие техники error-based инъекций.

Заключение

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

Источники