Что это за строка?
Строка OR EXTRACTVALUE(7974,CONCAT(0x7e,((SELECT (ELT(7974=7974,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции (инъекции на основе ошибок) для СУБД MySQL. Такие конструкции используют для извлечения данных из базы через сообщения об ошибках, которые возвращает сервер. Внешне это выглядит как бессмысленный набор символов, но на деле каждый элемент имеет строгое назначение.
Подобные запросы часто встречаются в логах веб-серверов, в системах обнаружения вторжений (IDS) и в отчётах об уязвимостях. Понимание их структуры помогает разработчикам и специалистам по безопасности правильно оценивать риски и выстраивать защиту.
Разбор по частям
OR
Логический оператор OR присоединяет внедряемое выражение к исходному SQL-запросу. Если исходный запрос был, например, SELECT * FROM users WHERE id = 1, то после подстановки получается SELECT * FROM users WHERE id = 1 OR EXTRACTVALUE(...). Условие id = 1 может быть ложным, но из-за OR запрос всё равно выполнится, и вложенная функция сработает.
EXTRACTVALUE(7974, CONCAT(...))
EXTRACTVALUE() — это функция MySQL, предназначенная для извлечения значения из XML-документа по указанному XPath-выражению. Синтаксис: EXTRACTVALUE(XML_document, XPath_expression). В нашем случае первый аргумент — число 7974, которое интерпретируется как XML-фрагмент (обычно это либо произвольная строка, либо результат подзапроса).
Ключевая особенность: если XPath-выражение синтаксически некорректно, MySQL генерирует ошибку XPATH syntax error и включает в текст ошибки фрагмент переданного выражения. Именно на этом строится вся инъекция — злоумышленник заставляет СУБД «выкрикнуть» нужные данные в сообщении об ошибке.
CONCAT(0x7e, ..., 0x7e)
CONCAT склеивает несколько строк. Здесь используются шестнадцатеричные литералы 0x7e — это символ тильды ~. Тильды служат маркерами-разделителями: они помогают легко найти извлечённые данные в тексте ошибки. Между ними вставляется результат вложенного подзапроса.
(SELECT (ELT(7974=7974,1)))
Это сердце запроса. Разберём по шагам:
7974=7974— сравнение числа с самим собой, всегда возвращаетTRUE(в числовом контексте — 1).ELT(N, str1, str2, ...)— функция MySQL, возвращающая N-ю строку из списка. Если N=1, вернётся первая строка. В нашем случае список состоит из одного элемента —1.- Таким образом,
ELT(7974=7974, 1)возвращает1. - Внешний
SELECTпросто оборачивает это значение в подзапрос.
На первый взгляд конструкция кажется бессмысленной: она всегда возвращает 1. Но это тестовый пример. В реальной атаке вместо ELT(7974=7974,1) подставляется подзапрос, извлекающий, например, имя пользователя или хэш пароля из системных таблиц.
-- -
Два дефиса и пробел — это комментарий в SQL. Всё, что идёт после -- , игнорируется парсером. Это нужно, чтобы «отрезать» остаток оригинального запроса, который мог бы помешать выполнению инъекции. Символ - после пробела добавлен для надёжности: некоторые СУБД требуют, чтобы после -- был пробел, а дефис гарантирует, что комментарий не «съест» лишнего.
Как это работает на практике
Представим уязвимый запрос: SELECT * FROM articles WHERE id = $_GET['id']. Злоумышленник передаёт в параметр id строку:
1 OR EXTRACTVALUE(7974,CONCAT(0x7e,((SELECT (ELT(7974=7974,1)))),0x7e))-- -
Сервер формирует итоговый SQL:
SELECT * FROM articles WHERE id = 1 OR EXTRACTVALUE(7974,CONCAT(0x7e,((SELECT (ELT(7974=7974,1)))),0x7e))-- -
MySQL выполняет EXTRACTVALUE, пытается разобрать строку ~1~ как XPath. Поскольку ~1~ — невалидный XPath, возникает ошибка вида:
XPATH syntax error: '~1~'
Веб-приложение, не настроенное на подавление ошибок, возвращает эту ошибку пользователю. Атакующий видит ~1~ и понимает, что инъекция работает. Далее он заменяет ELT(7974=7974,1) на подзапрос, например, (SELECT version()), и получает в тексте ошибки версию СУБД.
Зачем это нужно злоумышленнику
Error-based инъекции — один из самых быстрых способов извлечения данных, когда приложение выводит сообщения об ошибках. С помощью EXTRACTVALUE и аналогичной функции UPDATEXML можно посимвольно вытащить:
- имя текущей базы данных (
database()); - версию MySQL (
version()); - имена таблиц и столбцов из
INFORMATION_SCHEMA; - логины и пароли пользователей.
Ограничение — длина выводимой строки. MySQL обрезает сообщение об ошибке примерно до 64 символов, поэтому данные извлекают по частям с помощью SUBSTRING или LIMIT.
Как защититься
Главное правило — никогда не подставлять пользовательский ввод напрямую в SQL-запросы. Используйте подготовленные выражения (prepared statements) с параметризацией. Это делает любые инъекции бессмысленными, потому что ввод передаётся как данные, а не как код.
Дополнительные меры:
- Отключите вывод ошибок в production-среде. Настройте
display_errors = Offв PHP или аналогичные параметры в других языках. Ошибки должны писаться в лог, а не показываться пользователю. - Ограничьте права пользователя БД. Учётная запись веб-приложения не должна иметь доступ к
INFORMATION_SCHEMAбез необходимости и тем более к системным таблицам. - Используйте WAF (Web Application Firewall), который распознаёт шаблоны вроде
EXTRACTVALUE,UPDATEXML,CONCAT(0x7eи блокирует подозрительные запросы. - Регулярно обновляйте MySQL. В новых версиях (начиная с 5.7) функция
EXTRACTVALUEпомечена как устаревшая, а в MySQL 8.0 удалена. Это снижает риск, но не отменяет необходимость параметризации.
Итог
Запрос OR EXTRACTVALUE(7974,CONCAT(0x7e,((SELECT (ELT(7974=7974,1)))),0x7e))-- - — это учебный пример error-based SQL-инъекции. Он демонстрирует, как через намеренно вызванную ошибку MySQL можно извлечь произвольные данные. Понимание механики таких атак — первый шаг к написанию безопасного кода и защите веб-приложений.
Комментарии
—Войдите, чтобы оставить комментарий