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

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

Такие конструкции часто встречаются в отчётах пентестеров и в базах эксплойтов. Они эксплуатируют функцию EXTRACTVALUE(), которая предназначена для работы с XML и генерирует ошибку XPATH, если ей передать некорректный XPath-выражение. Злоумышленник использует эту ошибку как канал для извлечения данных.

Разбор по частям

1. Начало: `) OR ...

Символы `) — это попытка закрыть ранее открытую скобку и кавычку в оригинальном SQL-запросе. Часто разработчики пишут что-то вроде SELECT * FROM users WHERE id = ('$id'). Внедряя `) OR ..., атакующий разрывает строку и добавляет своё условие. OR делает условие всегда истинным (если правая часть верна), что позволяет обойти аутентификацию или вытащить данные.

2. Функция EXTRACTVALUE(1918, ...)

EXTRACTVALUE(XML_document, XPath_expression) — встроенная функция MySQL для извлечения значения из XML по заданному XPath. Если XPath-выражение синтаксически неверно, MySQL возвращает ошибку вида XPATH syntax error: '...'. В нашем случае первым аргументом идёт число 1918 — это просто произвольный XML-документ (число преобразуется в строку). Второй аргумент — конкатенация, которая и содержит полезную нагрузку.

3. CONCAT(0x7e, ((SELECT (ELT(1918=1918,1)))), 0x7e)

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

4. ELT(1918=1918,1)

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Если N=1, возвращается первая строка. Выражение 1918=1918 всегда истинно, что в MySQL даёт 1. Таким образом, ELT(1,1) возвращает строку '1'. На первый взгляд это бессмысленно, но в реальных эксплойтах вместо 1918=1918 подставляют условие, зависящее от данных (например, SUBSTRING(version(),1,1)='5'). Тогда ELT вернёт 1 или 0, и по ошибке можно определить, истинно условие или нет. Это слепая инъекция, но с выводом через ошибку.

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

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

Как это работает целиком

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

SELECT * FROM articles WHERE id = ('$id')

Подставляем полезную нагрузку вместо $id:

SELECT * FROM articles WHERE id = ('`) OR EXTRACTVALUE(1918,CONCAT(0x7e,((SELECT (ELT(1918=1918,1)))),0x7e))-- -')

После подстановки запрос превращается в:

SELECT * FROM articles WHERE id = ('`) OR EXTRACTVALUE(1918,CONCAT(0x7e,((SELECT (ELT(1918=1918,1)))),0x7e))-- -')

MySQL выполняет EXTRACTVALUE с аргументом CONCAT('~', '1', '~'), то есть '~1~'. Это не является корректным XPath, поэтому СУБД возвращает ошибку:

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

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

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

  • Обход аутентификации: конструкция OR 1=1 в логине или пароле позволяет войти без учётных данных.
  • Извлечение данных: через ошибки можно получить имена таблиц, колонок, логины, хеши паролей.
  • Автоматизация: существуют инструменты (sqlmap), которые автоматически подставляют подобные payload'ы и парсят ответы сервера.

Error-based инъекции считаются одними из самых удобных для атакующего, потому что результат приходит прямо в тексте ошибки, не требуя слепого перебора.

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

Главная причина успеха таких атак — динамическое построение SQL-запросов с прямым включением пользовательского ввода. Вот основные меры:

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

Важно понимать: даже если сайт написан на PHP с использованием устаревших функций вроде mysql_query, риск инъекций крайне высок. Переход на PDO или mysqli с подготовленными выражениями решает проблему кардинально.

Частые вопросы

Почему используется именно 1918?

Число 1918 — произвольное. Оно может быть любым, главное, чтобы оно преобразовывалось в строку и не ломало синтаксис. В некоторых эксплойтах вместо него ставят 1 или 0x7e.

Что такое 0x7e?

Это шестнадцатеричный код символа ~. Тильда выбрана потому, что редко встречается в обычных данных и легко находится в сообщении об ошибке.

Работает ли это на всех версиях MySQL?

Функция EXTRACTVALUE присутствует в MySQL начиная с версии 5.1. В MariaDB она тоже есть. Однако в последних версиях (MySQL 8.0) поведение может отличаться, но сама уязвимость сохраняется, если приложение не использует параметризацию.

Можно ли использовать UPDATEXML вместо EXTRACTVALUE?

Да, UPDATEXML — аналогичная функция, которая также генерирует ошибку XPATH и часто применяется в error-based инъекциях. Принцип тот же.

Итог

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

Источники

  • SQL Injection — Wikipedia