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

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

В данной статье мы детально разберём конкретный payload:

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

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

Разбор структуры payload

Payload состоит из нескольких частей, каждая из которых выполняет свою роль:

  • ')))) — последовательность закрывающих скобок и кавычек, предназначенная для завершения оригинального SQL-запроса и внедрения собственного кода. Количество скобок зависит от структуры уязвимого запроса.
  • AND — логический оператор, который соединяет оригинальное условие с внедрённым.
  • EXTRACTVALUE(5885, CONCAT(0x7e, ((SELECT (ELT(5885=5885,1)))), 0x7e)) — вызов функции EXTRACTVALUE с двумя аргументами. Первый аргумент — произвольное число (5885), второй — строка, сформированная через CONCAT.
  • -- - — комментарий, который игнорирует оставшуюся часть оригинального запроса.

Функция EXTRACTVALUE

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

Функция CONCAT и шестнадцатеричные литералы

CONCAT объединяет несколько строк в одну. В нашем payload используется CONCAT(0x7e, ((SELECT ...)), 0x7e). Здесь 0x7e — это шестнадцатеричное представление символа тильды (~). Тильда добавляется в начало и конец для того, чтобы отделить результат подзапроса от остального текста ошибки и облегчить его извлечение. Часто в качестве разделителей используют и другие символы, например, двоеточие или пробел, но тильда удобна тем, что редко встречается в обычных данных.

Подзапрос с ELT

ELT(N, str1, str2, ...) — функция MySQL, которая возвращает N-ю строку из списка. В нашем случае используется ELT(5885=5885, 1). Выражение 5885=5885 всегда истинно (возвращает 1), поэтому ELT(1, 1) вернёт строку '1'. Это простейший пример, демонстрирующий работу механизма. В реальных атаках вместо этого подзапроса может быть любой другой, например, извлекающий имена таблиц или пароли пользователей.

Как работает атака

Предположим, что веб-приложение выполняет следующий SQL-запрос:

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

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

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

Тогда итоговый запрос примет вид:

SELECT * FROM users WHERE id = '')))) AND EXTRACTVALUE(5885,CONCAT(0x7e,((SELECT (ELT(5885=5885,1)))),0x7e))-- -';

MySQL выполнит функцию EXTRACTVALUE. Поскольку второй аргумент содержит символ тильды, который не является допустимым XPath-выражением, возникнет ошибка. В сообщении об ошибке будет отображено значение, возвращённое подзапросом, обрамлённое тильдами. Например:

XPATH syntax error: '~1~'

Таким образом, атакующий может извлекать произвольные данные из базы, подставляя вместо ELT(5885=5885,1) другие подзапросы.

Зачем нужны множественные скобки и кавычки?

Количество закрывающих скобок и кавычек в начале payload зависит от того, как построен оригинальный запрос. Если запрос содержит вложенные функции или условия, может потребоваться несколько закрывающих символов, чтобы «выровнять» синтаксис и внедрить свой код. В нашем примере использованы четыре закрывающие скобки и одна кавычка — это типичный случай для запросов с несколькими уровнями вложенности.

Меры защиты от error-based SQL-инъекций

Чтобы предотвратить подобные атаки, необходимо применять комплексный подход:

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

Заключение

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

Источники