Что это за строка?

Строка OR EXTRACTVALUE(3983,CONCAT(0x7e,((SELECT (ELT(3983=3983,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции (инъекции на основе ошибок) для СУБД MySQL. Такие конструкции используют для извлечения данных из базы через сообщения об ошибках, которые возвращает сервер.

Внешне это выглядит как бессмысленный набор символов, но на самом деле каждый элемент здесь имеет строгое назначение. Давайте разберём его по частям.

Разбор синтаксиса

OR

Логический оператор OR добавляется к исходному SQL-запросу, чтобы изменить его условие. Например, если приложение выполняет запрос SELECT * FROM users WHERE id = '$id', то подстановка 1 OR ... делает условие всегда истинным, что позволяет обойти аутентификацию или получить дополнительные данные.

EXTRACTVALUE()

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

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

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

(SELECT (ELT(3983=3983,1)))

Внутренний подзапрос SELECT (ELT(3983=3983,1)) проверяет условие 3983=3983 (всегда истинно) и возвращает 1. Функция ELT() возвращает N-й элемент из списка. Здесь она используется как заглушка, но в реальных атаках вместо неё подставляют подзапросы, извлекающие имена таблиц, колонок или пароли.

-- -

Комментарий -- - (дефис-дефис-пробел) отсекает остаток оригинального SQL-запроса, чтобы синтаксис оставался корректным.

Как это работает на практике

Предположим, уязвимый запрос выглядит так:

SELECT * FROM articles WHERE id = '1'

Злоумышленник подставляет:

1' OR EXTRACTVALUE(3983,CONCAT(0x7e,((SELECT (ELT(3983=3983,1)))),0x7e))-- -

MySQL выполняет функцию EXTRACTVALUE, которая пытается разобрать строку, начинающуюся с ~, как XML. Поскольку это невалидный XML, возникает ошибка вида:

XPATH syntax error: '~1~'

В сообщении об ошибке отображается результат подзапроса. В данном примере это просто 1, но если вместо ELT(3983=3983,1) подставить, например, SELECT password FROM users LIMIT 1, то в ошибке появится пароль пользователя.

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

Error-based инъекции позволяют извлекать данные посимвольно или целыми строками, если приложение выводит ошибки СУБД на страницу. Это один из самых быстрых способов получить информацию о структуре базы и её содержимом. В отличие от blind-инъекций, где данные угадываются по времени отклика или логическим условиям, здесь результат приходит напрямую в тексте ошибки.

Основные цели:

  • Получение версии MySQL и имени текущей базы.
  • Извлечение имён таблиц и колонок из information_schema.
  • Кража учётных данных пользователей, хешей паролей, токенов.
  • Обход аутентификации (если инъекция в форме входа).

Как защититься

Главное правило — никогда не подставлять пользовательский ввод напрямую в SQL-запрос. Используйте подготовленные выражения (prepared statements) с параметризацией. Это надёжно отделяет данные от кода.

Дополнительные меры:

  • Отключите вывод подробных ошибок СУБД в production. Пользователь должен видеть общее сообщение, а не стек вызовов.
  • Ограничьте права пользователя базы данных: не давайте ему доступ к information_schema без необходимости.
  • Используйте WAF (Web Application Firewall) для фильтрации подозрительных конструкций, но не полагайтесь только на него.
  • Регулярно проводите аудит кода и пентесты.

Частные случаи и вариации

Вместо EXTRACTVALUE часто используют UPDATEXML — ещё одну функцию для работы с XML, которая также генерирует ошибку при неверном XPath. Синтаксис аналогичен: UPDATEXML(1,CONCAT(0x7e,(SELECT ...),0x7e),1). Обе функции считаются устаревшими в новых версиях MySQL, но всё ещё встречаются на старых серверах.

Число 3983 в запросе — это произвольный идентификатор, который может меняться. Он не несёт смысловой нагрузки, кроме того, что участвует в условии 3983=3983 (всегда истинно). В реальных атаках вместо него могут быть другие числа или строки.

Вывод

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

Источники