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

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

Как работает эта инъекция?

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

  • ' OR ... — закрывает кавычку в уязвимом SQL-запросе и добавляет условие OR, чтобы запрос выполнился даже если исходное условие ложно.
  • EXTRACTVALUE(2746, CONCAT(0x7e, ..., 0x7e)) — функция MySQL для работы с XML. Она извлекает значение из XML-документа по XPath-выражению. Если XPath-выражение некорректно, MySQL выдаёт ошибку, в тексте которой отображается переданный аргумент.
  • CONCAT(0x7e, ..., 0x7e) — объединяет символы тильды (~, код 0x7e) с результатом подзапроса. Тильда используется как маркер, чтобы потом легко найти данные в сообщении об ошибке.
  • (SELECT (ELT(2746=2746,1))) — подзапрос, который возвращает 1, если 2746=2746 (всегда истина). ELT — функция, возвращающая N-й элемент из списка. Здесь она возвращает 1. В реальной атаке вместо этого подзапроса внедряют запрос к системным таблицам, например, SELECT table_name FROM information_schema.tables.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального SQL-запроса.

В результате MySQL пытается выполнить EXTRACTVALUE с XPath-выражением, содержащим тильды и результат подзапроса. Поскольку XPath-выражение начинается с тильды, оно синтаксически неверно, и MySQL возвращает ошибку вида: XPATH syntax error: '~1~'. Если вместо 1 подставить запрос к таблицам, в ошибке отобразятся имена таблиц или другие данные.

Пример ошибки: XPATH syntax error: '~users~' — так злоумышленник узнаёт имя таблицы.

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

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

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

Основные меры:

  1. Параметризованные запросы (prepared statements) — самый надёжный способ. Данные пользователя передаются отдельно от SQL-кода и не могут изменить структуру запроса.
  2. Отключение вывода ошибок СУБД — на продакшене сообщения об ошибках не должны показываться пользователю. Логирование ошибок в файл, а не в браузер.
  3. Валидация и экранирование — если параметризация невозможна, используйте строгую проверку типов и экранирование специальных символов.
  4. Принцип наименьших привилегий — учётная запись приложения должна иметь доступ только к необходимым таблицам и операциям.
  5. Регулярные сканирования уязвимостей — используйте SAST/DAST-инструменты для поиска SQL-инъекций.

Технические детали

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

Стоит отметить, что подобные инъекции возможны не только в MySQL. В других СУБД есть свои функции для error-based атак, например, CAST в PostgreSQL или UTL_INADDR в Oracle. Однако EXTRACTVALUE — это «классика» именно для MySQL.

Пример реальной атаки

Предположим, есть уязвимый параметр id в URL: http://example.com/product.php?id=1. Запрос в коде: SELECT * FROM products WHERE id = '$id'. Злоумышленник подставляет:

1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))-- -

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

Вывод

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