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

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

Функция ExtractValue() предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Однако при передаче некорректного XPath-выражения MySQL генерирует сообщение об ошибке, в которое попадает часть переданной строки. Это позволяет злоумышленнику «вытащить» данные из базы, подставив их в XPath и вызвав ошибку, которая будет отображена на странице.

Разбор конкретного запроса

Рассмотрим запрос, который часто встречается в отчётах об уязвимостях и на форумах по информационной безопасности:

%" OR EXTRACTVALUE(1877,CONCAT(0x7e,((SELECT (ELT(1877=1877,1)))),0x7e))-- -

Этот запрос представляет собой попытку эксплуатации error-based SQL-инъекции. Разберём его по частям.

1. Начало: %"

Символ % в SQL часто используется как шаблон для поиска (например, в операторе LIKE). Кавычка " закрывает строковый литерал в исходном запросе приложения. Таким образом, злоумышленник пытается «разорвать» изначальный SQL-запрос и добавить свой код.

2. OR EXTRACTVALUE(...)

Оператор OR используется для того, чтобы внедрённое условие выполнилось, даже если первая часть запроса ложна. Далее вызывается функция EXTRACTVALUE() с двумя аргументами:

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

3. Подзапрос SELECT (ELT(1877=1877,1))

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

Фактически это простейший пример: злоумышленник мог бы написать SELECT 1, но использование ELT и сравнения 1877=1877 — это демонстрация техники, которая в реальной атаке заменяется на извлечение данных, например, SELECT version() или SELECT password FROM users LIMIT 1.

4. Формирование XPath и ошибка

Второй аргумент EXTRACTVALUE после вычисления CONCAT будет выглядеть как ~1~. Функция EXTRACTVALUE попытается интерпретировать эту строку как XPath-выражение. Строка ~1~ не является корректным XPath (тильда недопустима в начале выражения), поэтому MySQL сгенерирует ошибку вида:

ERROR 1105 (HY000): XPATH syntax error: '~1~'

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

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

Двойной дефис -- в SQL обозначает начало комментария. Пробел после него и дефис в конце (-- -) используются для обхода возможных фильтров и гарантируют, что остальная часть исходного запроса будет проигнорирована.

Зачем это нужно злоумышленнику?

Основная цель — получить доступ к данным, которые не должны быть видны. С помощью error-based инъекций можно извлекать:

  • версию СУБД;
  • имена таблиц и колонок;
  • логины и пароли пользователей;
  • другую конфиденциальную информацию.

В приведённом примере извлекается просто число 1, но это лишь демонстрация уязвимости. В реальной атаке вместо 1 подставляются подзапросы, возвращающие ценные данные.

Как защититься от таких атак?

Чтобы предотвратить SQL-инъекции, необходимо следовать следующим рекомендациям:

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

Заключение

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

Помните: безопасность — это процесс, а не одноразовое действие. Регулярный аудит кода и тестирование на проникновение помогают выявлять уязвимости до того, как ими воспользуются злоумышленники.

Источники