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

Что такое error-based SQL-инъекция?

SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленник внедряет вредоносный SQL-код в параметры запроса, которые приложение передаёт в базу данных. Если приложение не фильтрует входные данные, база выполняет команды атакующего.

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

Разбор строки инъекции

Давайте посмотрим на запрос по частям:

  • %') — попытка закрыть предыдущее выражение в уязвимом запросе. Символ % часто используется в LIKE-запросах, а ') закрывает скобку и кавычку.
  • OR EXTRACTVALUE(1492,CONCAT(0x7e,((SELECT (ELT(1492=1492,1)))),0x7e)) — основная полезная нагрузка. Функция EXTRACTVALUE извлекает значение из XML-строки. Если переданный XML некорректен, MySQL выдаёт ошибку, в которой отображается переданный фрагмент.
  • -- - — комментарий, который отсекает остаток оригинального запроса.

Внутри EXTRACTVALUE используется CONCAT для объединения тильды (0x7e), результата подзапроса и ещё одной тильды. Тильды служат маркерами, чтобы в сообщении об ошибке легко было найти нужные данные. Подзапрос SELECT (ELT(1492=1492,1)) — это простейшая проверка: ELT возвращает строку по номеру. Здесь 1492=1492 всегда истинно (1), поэтому возвращается 1. В реальной атаке вместо этой заглушки подставляют вызовы вроде (SELECT user()) или (SELECT password FROM users LIMIT 1).

Как работает EXTRACTVALUE?

Функция EXTRACTVALUE(XML_document, XPath_expression) появилась в MySQL 5.1. Она извлекает значение из XML-документа по заданному XPath-выражению. Если XPath-выражение некорректно, MySQL генерирует ошибку вида:

XPATH syntax error: '~данные~'

Именно эти «данные» и являются целью атакующего. Передавая в XPath-выражение результат подзапроса, хакер может вытащить любую информацию: версию базы, имя пользователя, хеши паролей и т.д.

Пример более реалистичной инъекции:

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

В ответе сервер вернёт ошибку с версией MySQL, например: XPATH syntax error: '~5.7.33~'.

Пошаговый пример атаки

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

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

После подстановки база выполнит:

  1. Закроет условие id = '%'.
  2. Вычислит EXTRACTVALUE. Поскольку второй аргумент — невалидный XPath (содержит тильды и результат подзапроса), возникнет ошибка.
  3. В тексте ошибки отобразится переданная строка, включая результат подзапроса.

Атакующий может менять подзапрос, чтобы извлекать данные посимвольно или целыми строками. Например, для получения имени пользователя базы:

' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT user()), 0x7e))-- -

Ответ: XPATH syntax error: '~root@localhost~'.

Какие данные можно украсть?

С помощью error-based инъекции через EXTRACTVALUE злоумышленник может получить:

  • Версию СУБД и операционной системы.
  • Имя текущего пользователя базы данных.
  • Имена таблиц и колонок из information_schema.
  • Логины и пароли пользователей приложения (часто в хешированном виде).
  • Персональные данные клиентов: ФИО, телефоны, email, адреса.
  • Данные банковских карт, если они хранятся в базе (что само по себе нарушение PCI DSS).

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

Как защититься от SQL-инъекций?

Основной метод защиты — параметризованные запросы (prepared statements). Они разделяют код и данные, поэтому внедрённый SQL-код не выполняется. Например, в PHP с PDO:

$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
$stmt->execute(['id' => $id]);

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

  • Использовать ORM (Doctrine, Hibernate, Entity Framework), которые автоматически экранируют параметры.
  • Валидировать и фильтровать все входные данные на стороне сервера.
  • Ограничить права пользователя базы данных: приложению не нужны права FILE, DROP или доступ к information_schema без необходимости.
  • Отключить вывод подробных ошибок MySQL в production-окружении. Вместо этого логировать их на сервере.
  • Регулярно обновлять СУБД и фреймворки, чтобы закрыть известные уязвимости.
  • Использовать WAF (Web Application Firewall) для блокировки подозрительных запросов.

Заключение

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

Источники