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

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

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

Разбор компонентов инъекции

  • AND — логический оператор, который добавляется к исходному SQL-запросу, чтобы условие выполнилось только при истинности выражения. Если исходный запрос был, например, SELECT * FROM users WHERE id = 1, то после подстановки получится SELECT * FROM users WHERE id = 1 AND EXTRACTVALUE(...).
  • EXTRACTVALUE(9998, CONCAT(...)) — функция MySQL, извлекающая значение из XML-фрагмента. Она принимает два аргумента: первый — XML-документ (здесь просто число 9998), второй — XPath-выражение. Если XPath некорректен, MySQL выдаёт ошибку, в тексте которой отображается переданное выражение. Это и есть основа error-based инъекции.
  • CONCAT(0x7e, ((SELECT (ELT(9998=9998,1)))), 0x7e) — конкатенация символа тильды (0x7e — шестнадцатеричный код символа ~), результата подзапроса и ещё одной тильды. Тильды нужны как маркеры, чтобы в сообщении об ошибке было легко найти выведенные данные.
  • SELECT (ELT(9998=9998,1)) — подзапрос, возвращающий число 1. ELT() — функция, возвращающая N-й элемент из списка. Здесь 9998=9998 всегда истинно, поэтому ELT возвращает первый элемент — 1. Это простейшая проверка, что инъекция работает: если в ответе появится ошибка с числом 1, значит, уязвимость есть.
  • -- - — комментарий в SQL. Два дефиса и пробел (или дефис) заставляют СУБД игнорировать остаток исходного запроса, что позволяет обойти синтаксические ограничения.

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

Предположим, что веб-приложение формирует запрос следующим образом:

SELECT * FROM articles WHERE id = $_GET['id']

Злоумышленник передаёт в параметр id значение 1 AND EXTRACTVALUE(9998,CONCAT(0x7e,((SELECT (ELT(9998=9998,1)))),0x7e))-- -. Итоговый запрос становится:

SELECT * FROM articles WHERE id = 1 AND EXTRACTVALUE(9998,CONCAT(0x7e,((SELECT (ELT(9998=9998,1)))),0x7e))-- -

MySQL выполняет функцию EXTRACTVALUE. Поскольку второй аргумент не является корректным XPath (он начинается с тильды), СУБД генерирует ошибку вида:

XPATH syntax error: '~1~'

В этом сообщении мы видим ~1~ — это результат выполнения подзапроса, обрамлённый тильдами. Если бы вместо ELT(9998=9998,1) стоял, например, SELECT version(), то в ошибке отобразилась бы версия MySQL. Таким образом, атакующий может извлекать любые данные: имена таблиц, столбцов, логины, пароли и т.д.

Зачем нужна такая инъекция?

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

Конкретно эта строка с ELT(9998=9998,1) часто используется как тестовая: она проверяет, уязвим ли параметр, и не несёт большой смысловой нагрузки. Если сайт возвращает ошибку с ~1~, значит, можно переходить к более сложным запросам.

Ограничения EXTRACTVALUE

Важно отметить, что функция EXTRACTVALUE возвращает не более 32 символов. Если нужно вывести больше данных, приходится использовать SUBSTR() или LIMIT для посимвольного извлечения. Это несколько замедляет атаку, но не делает её невозможной.

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

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

Лучший способ предотвратить подобные атаки — использовать параметризованные запросы (prepared statements). Они разделяют код SQL и данные, поэтому введённая строка никогда не будет интерпретирована как часть запроса. Также рекомендуется:

  • Отключить вывод ошибок СУБД на продакшене, чтобы злоумышленник не видел текст ошибок.
  • Проводить валидацию всех входных данных, особенно числовых параметров.
  • Использовать ORM или query builder, которые автоматически экранируют значения.
  • Регулярно обновлять СУБД и фреймворки, чтобы закрыть известные уязвимости.

Если вы встретили такую строку в логах, это сигнал о попытке взлома. Стоит проверить, не была ли атака успешной, и принять меры по усилению безопасности.

Заключение

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

Источники