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

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

Подобные строки часто встречаются в логах веб-серверов, в полях ввода форм, в параметрах URL. Для неподготовленного человека они выглядят как случайный набор символов, но на самом деле это тщательно сконструированная атака.

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

Давайте разберём каждый элемент этого запроса.

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

Как это работает

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

SELECT * FROM articles WHERE id = (1)

Злоумышленник передаёт в параметр id значение:

1) AND EXTRACTVALUE(2177,CONCAT(0x7e,((SELECT (ELT(2177=2177,1)))),0x7e))-- -

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

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

MySQL пытается выполнить EXTRACTVALUE с первым аргументом 2177. Поскольку это не XML, функция выдаёт ошибку. Второй аргумент — XPath-выражение, которое начинается с ~ (тильда), что недопустимо в XPath. MySQL формирует сообщение об ошибке вида:

XPATH syntax error: '~1~'

В этом сообщении мы видим ~1~ — это и есть результат выполнения подзапроса (SELECT (ELT(2177=2177,1))). Если бы вместо 1 подставлялся пароль пользователя, он бы отобразился в ошибке.

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

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

  • Получить версию MySQL (например, SELECT version()).
  • Узнать имя текущей базы данных (SELECT database()).
  • Извлечь имена таблиц и колонок из information_schema.
  • Вытащить логины, пароли, хеши, номера кредитных карт и любые другие данные, хранящиеся в БД.

В приведённом примере 2177=2177 — это демонстрация работоспособности инъекции. Злоумышленник проверяет, что уязвимость существует и что функция EXTRACTVALUE доступна. Если ошибка с тильдами возвращается, значит, можно переходить к реальному извлечению данных.

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

В MySQL есть несколько функций, вызывающих ошибки с контролируемым текстом: EXTRACTVALUE, UPDATEXML, GTID_SUBSET и другие. EXTRACTVALUE долгое время была популярна, потому что:

  • Она доступна во всех версиях MySQL 5.x и многих 8.x.
  • Сообщение об ошибке содержит до 32 символов полезной нагрузки.
  • Синтаксис прост: EXTRACTVALUE(1, CONCAT(0x7e, (SELECT ...), 0x7e)).

Однако начиная с MySQL 8.0.17 функция EXTRACTVALUE была удалена, поэтому современные атаки чаще используют UPDATEXML или другие техники. Но старые системы по-прежнему уязвимы.

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

Главная защита от SQL-инъекций — использование параметризованных запросов (prepared statements). Это означает, что данные пользователя передаются в базу отдельно от SQL-кода и не могут изменить структуру запроса.

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

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

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

Краткий итог

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

Источники