Что такое '))) AND EXTRACTVALUE(5251,CONCAT(0x7e,((SELECT (ELT(5251=5251,1)))),0x7e))-- -

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

Строка '))) AND EXTRACTVALUE(5251,CONCAT(0x7e,((SELECT (ELT(5251=5251,1)))),0x7e))-- - состоит из нескольких частей, каждая из которых выполняет свою задачу. Разберём её по элементам.

Разбор элементов полезной нагрузки

1. Закрывающие скобки и кавычки: ')))

В начале строки идут символы '))). Они нужны, чтобы «закрыть» ранее открытые в уязвимом запросе кавычки и скобки, тем самым сделав внедряемый код синтаксически корректным. Количество закрывающих символов зависит от структуры исходного SQL-запроса, который атакует злоумышленник. Это типичный приём при ручном поиске уязвимостей или при использовании автоматизированных инструментов (например, sqlmap).

2. Оператор AND

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

3. Функция EXTRACTVALUE(5251, ...)

EXTRACTVALUE() — это встроенная функция MySQL (до версии 8.0.17 включительно, в более новых версиях она удалена), предназначенная для работы с XML. Она принимает два строковых аргумента: фрагмент XML-разметки и XPath-выражение. Функция возвращает текст первого текстового узла, который является дочерним для элемента или элементов, соответствующих XPath-выражению.

В нашем случае первым аргументом передаётся число 5251. Это не случайное число — оно используется как часть условия в подзапросе (ELT(5251=5251,1)). Само по себе число не является корректным XML-документом, но MySQL пытается его интерпретировать. Второй аргумент — сложное выражение CONCAT(0x7e,((SELECT (ELT(5251=5251,1)))),0x7e).

4. CONCAT(0x7e, ..., 0x7e)

CONCAT() объединяет строки. Здесь 0x7e — это шестнадцатеричное представление символа ~ (тильда). Тильда используется как маркер, чтобы в сообщении об ошибке было легко найти внедрённые данные. Между двумя тильдами вставляется результат подзапроса ((SELECT (ELT(5251=5251,1)))).

5. Подзапрос с ELT и условием 5251=5251

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

В реальной атаке вместо 1 могло бы быть имя базы данных, таблицы, логин администратора или хеш пароля. Например, злоумышленник мог бы использовать SELECT database() или SELECT user(), чтобы получить эти данные. Но в данном примере показан «безопасный» вариант с константой, который просто демонстрирует работу техники.

6. Комментарий -- -

Символы -- - — это комментарий в SQL. Всё, что идёт после них, игнорируется базой данных. Это нужно, чтобы «отрезать» оставшуюся часть исходного запроса, которая могла бы помешать выполнению внедрённого кода. Пробел после двух дефисов обязателен в некоторых СУБД (включая MySQL), поэтому часто пишут -- - или --+.

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

Механизм следующий:

  1. Злоумышленник находит параметр, который попадает в SQL-запрос без должной обработки.
  2. Он внедряет конструкцию, которая заставляет СУБД выполнить подзапрос, возвращающий нужные данные.
  3. Эти данные передаются в функцию EXTRACTVALUE() в составе XPath-выражения. Поскольку данные не являются корректным XPath, MySQL генерирует ошибку.
  4. В тексте ошибки MySQL отображает переданное значение (например, XPATH syntax error: '~1~').
  5. Атакующий видит результат в ответе сервера и может извлекать данные посимвольно или целыми строками.

Аналогичные функции, которые могут использоваться для error-based инъекций: UPDATEXML(), GTID_SUBSET(), EXP() (в некоторых версиях), а также extractvalue() в комбинации с concat().

Пример уязвимого запроса

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

SELECT * FROM products WHERE id = '$id'

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

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

В ответе сервера появится ошибка вида:

XPATH syntax error: '~имя_базы_данных~'

Таким образом, атакующий узнает имя текущей базы данных. Далее он может извлекать имена таблиц, столбцов и сами данные.

Зачем злоумышленники используют именно EXTRACTVALUE

Функция EXTRACTVALUE() удобна для error-based инъекций по нескольким причинам:

  • Она гарантированно вызывает ошибку при некорректном XPath, а текст ошибки содержит переданные данные.
  • Она доступна в большинстве версий MySQL (до 8.0.17) и MariaDB.
  • Она позволяет извлекать данные в удобном виде, ограничиваясь лишь длиной сообщения об ошибке (обычно 32 символа, но можно обойти через substring или mid).

Стоит отметить, что в MySQL 8.0.17 и выше функции EXTRACTVALUE() и UPDATEXML() были удалены, поэтому error-based инъекции через них перестали работать на новых версиях. Однако многие серверы до сих пор используют старые версии MySQL или MariaDB, где эти функции доступны.

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

Основные меры защиты:

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

Важно понимать, что error-based инъекция — лишь один из многих типов SQL-инъекций. Существуют также union-based, blind (boolean и time-based), out-of-band. Поэтому защита должна быть комплексной.

Заключение

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

Источники