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

SQL-инъекция (SQL Injection) — один из самых распространённых способов взлома веб-приложений, при котором злоумышленник внедряет вредоносный код в SQL-запросы. Особый интерес представляет error-based SQL-инъекция, при которой атакующий заставляет базу данных выдать конфиденциальные данные прямо в тексте ошибки. Функция ExtractValue в MySQL — популярный инструмент для реализации таких атак.

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

Как работает атака через ExtractValue

Рассмотрим классический пример, который часто встречается в лабораториях по безопасности (например, SQLi-labs). Предположим, что веб-приложение уязвимо к SQL-инъекции, и злоумышленник передаёт следующий параметр:

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

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

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

Когда MySQL выполняет ExtractValue с некорректным XPath (а строка, начинающаяся с тильды, не является валидным XPath), возникает ошибка вида: XPATH syntax error: '~1~'. В этом сообщении отображается результат подзапроса — в данном случае «1». Если вместо 1 подставить, например, (SELECT user()), то в ошибке появится имя текущего пользователя базы данных.

Пошаговый пример извлечения данных

Чтобы получить имя пользователя БД, злоумышленник может отправить такой запрос:

%')))) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT user()),0x7e))-- -

Ответ сервера будет содержать ошибку: XPATH syntax error: '~root@localhost~'. Таким образом, атакующий узнаёт логин и хост. Аналогично можно извлечь имена таблиц, колонок и даже хеши паролей, используя подзапросы с LIMIT и смещением.

В более сложных случаях применяют функцию ELT с условием, как в исходном запросе, чтобы обойти фильтры или извлечь конкретное значение. Например, ELT(9288=9288,1) — это упрощённый тест; в реальной атаке вместо 1 может стоять (SELECT password FROM users LIMIT 0,1).

Другие функции для error-based инъекций

Помимо ExtractValue, в MySQL существуют и другие функции, вызывающие ошибки с полезной нагрузкой:

  • UpdateXML — аналогична ExtractValue, но обновляет XML-документ. Также генерирует ошибку XPath.
  • GeometryCollection, Polygon, MultiPoint — при некорректных аргументах выводят данные в сообщении об ошибке.
  • Exp — переполнение при больших числах (например, exp(999999)) вызывает ошибку с числом, которое можно заменить на подзапрос.

Все они эксплуатируют небрежную обработку ошибок в веб-приложении: если приложение выводит текст ошибки MySQL на страницу, злоумышленник получает канал утечки данных.

Как защититься от ExtractValue SQL-инъекций

Основная причина уязвимости — недостаточная фильтрация пользовательского ввода и вывод ошибок базы данных. Вот ключевые меры защиты:

  1. Использование подготовленных выражений (prepared statements) с параметризацией запросов. Это самый надёжный способ, так как данные не интерпретируются как SQL-код.
  2. Экранирование специальных символов с помощью функций вроде mysqli_real_escape_string (для MySQL). Однако этот метод уступает подготовленным выражениям.
  3. Отключение вывода ошибок БД в production-окружении. Ошибки должны логироваться, а пользователю показываться общее сообщение.
  4. Ограничение прав пользователя БД: не используйте root для подключения из приложения. Выдавайте минимально необходимые привилегии.
  5. Использование WAF (Web Application Firewall) для блокировки подозрительных запросов, содержащих функции ExtractValue, UpdateXML и т.п.
  6. Регулярное обновление MySQL и фреймворков, чтобы закрыть известные уязвимости.

Также рекомендуется проводить аудит кода и пентесты для выявления подобных дыр до того, как их найдут злоумышленники.

Заключение

SQL-инъекция через ExtractValue — яркий пример того, как даже безобидная функция может стать оружием в руках атакующего. Понимание механизма работы таких атак помогает разработчикам и специалистам по безопасности своевременно закрывать уязвимости. Помните: безопасность — это процесс, а не одноразовое действие. Используйте параметризованные запросы, скрывайте ошибки и следите за обновлениями.

Источники