Введение

Встречая в логах или в коде запрос вида ) AND EXTRACTVALUE(1945,CONCAT(0x7e,((SELECT (ELT(1945=1945,1)))),0x7e))-- -, многие задаются вопросом: что это и зачем? Это классический пример SQL-инъекции, основанной на ошибках (error-based SQL injection), targeting MySQL. В данной статье мы разберём, как работает эта конструкция, какие функции задействованы и как защитить своё приложение.

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

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

Разбор запроса

Рассмотрим фрагмент: ) AND EXTRACTVALUE(1945,CONCAT(0x7e,((SELECT (ELT(1945=1945,1)))),0x7e))-- -

  • ) — закрывает ранее открытую скобку в оригинальном запросе, чтобы внедрить свой код.
  • AND — логический оператор, добавляющий условие.
  • EXTRACTVALUE(1945, CONCAT(...)) — функция MySQL для работы с XML. Она извлекает значение из XML-строки по указанному XPath-выражению. Если XPath некорректен, генерируется ошибка, содержащая переданные данные.
  • 1945 — произвольное число, которое не влияет на суть, но используется как первый аргумент (XML-документ).
  • CONCAT(0x7e, ((SELECT (ELT(1945=1945,1)))), 0x7e) — конкатенация символа ~ (0x7e) с результатом подзапроса и ещё одним ~. Это делается для того, чтобы отделить полезную нагрузку в сообщении об ошибке.
  • ELT(1945=1945,1) — функция ELT возвращает N-й элемент из списка. Здесь 1945=1945 — истина (1), поэтому ELT(1,1) вернёт 1. Это простейший пример; в реальных атаках вместо этого подзапроса могут быть вызовы для извлечения имён таблиц, колонок или данных.
  • -- - — комментарий, который обрезает оставшуюся часть оригинального запроса, чтобы избежать синтаксических ошибок.

Таким образом, злоумышленник заставляет базу данных выполнить функцию EXTRACTVALUE с заведомо некорректным XPath (содержащим символ ~, который недопустим в XPath), что приводит к ошибке вида: XPATH syntax error: '~1~'. В этом сообщении содержится результат выполнения подзапроса — в данном случае просто число 1. Меняя подзапрос, атакующий может извлекать любые данные из базы.

Почему это работает?

MySQL до версии 5.7 включительно (и в некоторых сборках) возвращает детализированные сообщения об ошибках, которые могут содержать пользовательские данные. Функция EXTRACTVALUE, как и UPDATEXML, при некорректном XPath генерирует ошибку, в которую попадает переданная строка. Это позволяет атакующему «вытаскивать» информацию посимвольно или целыми строками, если использовать CONCAT и подзапросы.

Важно: в современных версиях MySQL (8.0+) и при правильных настройках такие ошибки не отображаются клиенту, что делает этот тип инъекций менее эффективным.

Пример из практики

Допустим, есть уязвимый параметр id в URL: ?id=1. Оригинальный запрос: SELECT * FROM users WHERE id = 1. Атакующий подставляет: 1) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))-- -. В результате в ошибке вернётся имя текущей базы данных. Далее можно извлекать таблицы, колонки и сами данные.

В нашем случае запрос содержит ELT(1945=1945,1) — это просто демонстрация, показывающая, что инъекция работает и возвращает 1. В реальных атаках вместо этого используется что-то вроде (SELECT table_name FROM information_schema.tables LIMIT 0,1).

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

Основные меры профилактики:

  1. Использовать подготовленные выражения (prepared statements) с параметризацией — это самый надёжный способ.
  2. Экранировать пользовательский ввод с помощью функций типа mysqli_real_escape_string, но это менее надёжно.
  3. Отключить вывод ошибок СУБД в продакшене, чтобы сообщения не попадали к пользователю.
  4. Применять WAF (Web Application Firewall) для фильтрации подозрительных запросов.
  5. Регулярно обновлять MySQL до последних версий, где многие ошибки не детализируются.
  6. Проводить аудит кода и пентесты.

Заключение

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

Источники