Что такое error-based SQL-инъекция через EXTRACTVALUE?

Error-based SQL-инъекция — это метод атаки на базы данных, при котором злоумышленник извлекает информацию, заставляя СУБД возвращать данные в сообщениях об ошибках. В MySQL одной из самых популярных функций для этого является EXTRACTVALUE() — функция для работы с XML, которая генерирует ошибку, если переданный XPath-выражение некорректно. Атакующий подставляет в уязвимый параметр специально сконструированную строку, и в тексте ошибки MySQL отображает результат выполнения вложенного подзапроса.

Пример, который часто встречается в отчётах пентестеров и на учебных платформах (например, DVWA), выглядит так:

%'))) AND EXTRACTVALUE(1919,CONCAT(0x7e,((SELECT (ELT(1919=1919,1)))),0x7e))-- -

Эта строка — классический пример error-based SQL-инъекции. Она предназначена для извлечения данных из базы через вывод сообщения об ошибке.

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

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

  • %'))) — часть, которая «ломает» оригинальный SQL-запрос, закрывая кавычки и скобки, чтобы внедрить свой код.
  • AND EXTRACTVALUE(1919, CONCAT(0x7e, ((SELECT (ELT(1919=1919,1)))), 0x7e)) — вызов функции EXTRACTVALUE. Первый аргумент (1919) — произвольное число, второй — XPath-выражение, которое формируется через CONCAT. Символ 0x7e — это тильда (~), используется как разделитель, чтобы результат было легко найти в тексте ошибки.
  • ELT(1919=1919,1) — функция ELT возвращает N-й элемент из списка. Здесь 1919=1919 — всегда истина (1), поэтому ELT(1,1) вернёт 1. Это простейший пример; на практике вместо этого подзапроса внедряют SELECT для получения имён таблиц, колонок или паролей.
  • -- - — комментарий, который обрезает оставшуюся часть оригинального запроса.

Когда MySQL выполняет EXTRACTVALUE с некорректным XPath (а CONCAT создаёт строку вроде ~1~, что не является валидным XPath), генерируется ошибка вида: XPATH syntax error: '~1~'. В этом сообщении и оказывается результат подзапроса.

Зачем нужна такая инъекция?

Error-based инъекции применяются, когда другие методы (UNION, blind) недоступны или неудобны. Они позволяют быстро получить данные, если веб-приложение выводит ошибки СУБД на страницу. Основные сценарии:

  1. Извлечение версии MySQL, имени базы, пользователя.
  2. Получение имён таблиц и колонок из information_schema.
  3. Чтение конкретных данных (логины, пароли, номера карт).

Для этого вместо ELT(1919=1919,1) подставляют подзапрос, например: (SELECT table_name FROM information_schema.tables LIMIT 0,1). Результат также попадёт в ошибку.

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

Предположим, есть уязвимый параметр id в URL: http://site.com/product.php?id=1. Атакующий может отправить:

1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))

В ответе сервера появится ошибка с именем текущей базы данных. Это демонстрирует опасность отсутствия фильтрации входных данных.

Меры защиты

Чтобы предотвратить error-based SQL-инъекции, необходимо:

  • Использовать подготовленные выражения (prepared statements) с параметризацией запросов. Это самый надёжный способ.
  • Экранировать специальные символы с помощью функций вроде mysqli_real_escape_string (для MySQL).
  • Отключить вывод ошибок СУБД в production-окружении. Ошибки должны логироваться, а не показываться пользователю.
  • Применять принцип наименьших привилегий для учётной записи БД: не давать прав на чтение information_schema без необходимости.
  • Использовать WAF (Web Application Firewall) для фильтрации подозрительных запросов.

Важно понимать, что EXTRACTVALUE — не единственная функция для error-based инъекций. Также используются UPDATEXML, GTID_SUBSET, EXP и другие. Однако EXTRACTVALUE остаётся популярной из-за простоты и наглядности.

Заключение

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

Источники