Введение в SQL-инъекции через ExtractValue

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

Что такое функция EXTRACTVALUE?

Функция EXTRACTVALUE() в MySQL предназначена для работы с XML-документами. Она принимает два строковых аргумента: фрагмент XML-разметки и выражение XPath (локатор). Функция возвращает текст (CDATA) первого текстового узла, который является дочерним для элемента или элементов, соответствующих XPath-выражению. Например, запрос SELECT EXTRACTVALUE('<a>текст</a>', '/a') вернёт строку 'текст'.

Однако при некорректном XPath-выражении MySQL генерирует ошибку, которая может содержать переданные данные. Это и используется в error-based SQL-инъекциях: злоумышленник конструирует такой XPath, чтобы в тексте ошибки появилась информация из базы данных.

Разбор полезной нагрузки

Рассмотрим по частям запрос %") OR EXTRACTVALUE(8694,CONCAT(0x7e,((SELECT (ELT(8694=8694,1)))),0x7e))-- -.

  • %") — это начало, которое часто используется для закрытия предыдущего выражения в SQL-запросе. Символ % может быть частью LIKE-условия, а ") закрывает кавычку и скобку. Точная интерпретация зависит от контекста исходного запроса.
  • OR EXTRACTVALUE(...) — логический оператор OR, за которым следует вызов уязвимой функции. Если предыдущее условие ложно, выполнится правая часть.
  • 8694 — первый аргумент EXTRACTVALUE, который должен быть XML-фрагментом. Здесь передано число, что приведёт к ошибке, но это не важно, так как цель — вызвать ошибку с полезной нагрузкой.
  • CONCAT(0x7e,((SELECT (ELT(8694=8694,1)))),0x7e) — второй аргумент, XPath-выражение. Функция CONCAT объединяет символ ~ (0x7e в шестнадцатеричном виде), результат подзапроса и ещё один ~. Символ ~ используется как маркер, чтобы легко найти данные в сообщении об ошибке.
  • SELECT (ELT(8694=8694,1)) — подзапрос, который возвращает 1, если 8694=8694 (всегда истина), и NULL в противном случае. ELT — это функция, возвращающая N-й элемент из списка. Здесь список состоит из одного элемента 1. Фактически это заглушка, но в реальной атаке вместо неё был бы запрос к базе, например, (SELECT user()).
  • -- - — комментарий, который обрезает оставшуюся часть исходного SQL-запроса, чтобы не вызвать синтаксическую ошибку.

Как работает эксплуатация

Когда MySQL выполняет EXTRACTVALUE с некорректным XPath, он возвращает ошибку вида: XPATH syntax error: '~1~'. В нашем случае XPath будет содержать ~1~, и эта строка попадёт в сообщение об ошибке, которое затем отобразится на странице (если приложение не подавляет ошибки). Таким образом, атакующий может извлечь данные из базы, подставляя вместо ELT(8694=8694,1) произвольные подзапросы, например, (SELECT version()) или (SELECT password FROM users LIMIT 1).

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

Пример реальной атаки

Предположим, есть уязвимый параметр id в URL: http://example.com/product.php?id=1. Запрос в коде может выглядеть так: SELECT * FROM products WHERE id = '$id'. Если передать 1' OR EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))-- -, то база вернёт ошибку с именем текущей базы данных. Это классический пример error-based SQL-инъекции.

В нашем разбираемом запросе используется более сложная конструкция с % и "), что говорит о том, что исходный запрос, вероятно, был частью LIKE-поиска или имел закрывающую скобку и кавычку. Например: SELECT * FROM table WHERE name LIKE '%" + input + "%'. Тогда полезная нагрузка закрывает кавычку и скобку, добавляет OR и комментарий.

Защита от SQL-инъекций

Основной способ защиты — использование параметризованных запросов (prepared statements). Это гарантирует, что пользовательский ввод никогда не интерпретируется как SQL-код. Также рекомендуется:

  • Экранировать специальные символы с помощью функций типа mysqli_real_escape_string.
  • Использовать ORM или query builder, которые автоматически параметризуют запросы.
  • Ограничить права пользователя базы данных, чтобы даже при инъекции нельзя было получить лишние данные.
  • Отключить вывод ошибок базы данных на продакшене, чтобы не давать атакующему информацию.
  • Регулярно обновлять СУБД и применять патчи безопасности.

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

Заключение

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