Введение

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

В данной статье мы детально разберём каждый элемент этого запроса, объясним его назначение и покажем, как он работает. Материал будет полезен как специалистам по информационной безопасности, так и разработчикам, желающим понять механизмы защиты.

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

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

MySQL предоставляет несколько функций, которые можно использовать для генерации ошибок с внедрёнными данными. Одной из самых популярных является EXTRACTVALUE() — функция для работы с XML. Если передать ей некорректный XPath-выражение, она выдаст ошибку, в тексте которой будет содержаться переданная строка.

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

Рассмотрим конструкцию "') AND EXTRACTVALUE(3104,CONCAT(0x7e,((SELECT (ELT(3104=3104,1)))),0x7e))-- - поэлементно.

1. Начало: "')

Символы "') предназначены для закрытия предыдущего строкового литерала и круглой скобки в оригинальном запросе. Например, если исходный запрос выглядел как SELECT * FROM users WHERE name = "$input", то подстановка "') закроет кавычку и скобку, позволив внедрить произвольный SQL-код. Это типичный приём для обхода простых фильтров.

2. AND EXTRACTVALUE(3104, ...)

Оператор AND присоединяет наше условие к оригинальному запросу. Функция EXTRACTVALUE(XML_frag, XPath_expr) извлекает значение из XML-фрагмента по заданному XPath. Если XPath содержит недопустимые символы (например, тильду ~), MySQL выдаст ошибку вида: XPATH syntax error: '~...~'. Именно это и нужно атакующему — в тексте ошибки появятся данные, которые он передал во втором аргументе.

Первый аргумент 3104 — это произвольное число, которое не несёт смысловой нагрузки, но должно быть допустимым XML-фрагментом (любая строка).

3. CONCAT(0x7e, ((SELECT (ELT(3104=3104,1)))), 0x7e)

Функция CONCAT объединяет несколько строк. Здесь используется шестнадцатеричный код 0x7e, который соответствует символу тильды ~. Тильда добавляется в начало и конец, чтобы отделить полезные данные в сообщении об ошибке и сделать их легко извлекаемыми.

В середине — подзапрос (SELECT (ELT(3104=3104,1))). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае 3104=3104 — это всегда истинное выражение, которое в MySQL возвращает 1. Таким образом, ELT(1, 1) вернёт строку '1'. Это простейший пример; на практике вместо '1' может быть подставлен другой подзапрос, извлекающий нужные данные (например, имя пользователя или хеш пароля).

Итог: CONCAT собирает строку вида ~1~, которая затем передаётся в EXTRACTVALUE и вызывает ошибку с этим текстом.

4. Завершение: -- -

Два дефиса и пробел (или дефис) — это комментарий в SQL. Всё, что идёт после -- -, игнорируется базой данных. Это позволяет отсечь остаток оригинального запроса, чтобы синтаксис остался корректным.

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

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

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

Если передать в параметр id строку 1' AND EXTRACTVALUE(3104,CONCAT(0x7e,((SELECT (ELT(3104=3104,1)))),0x7e))-- -, то после подстановки получится:

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

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

В реальных атаках вместо '1' подставляются подзапросы, извлекающие, например, версию MySQL, имя текущей базы данных, имена таблиц и колонок, а затем и конкретные данные (логины, пароли).

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

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

С помощью этой техники можно:

  • Определить версию MySQL и операционную систему.
  • Получить список баз данных, таблиц и колонок.
  • Извлечь учётные данные пользователей, хеши паролей, персональные данные.
  • В некоторых случаях — выполнить произвольные команды на сервере (при наличии соответствующих привилегий).

Меры защиты

Чтобы предотвратить подобные атаки, необходимо:

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

Заключение

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

Помните: безопасность — это процесс, а не разовое действие. Регулярно проводите аудит кода, обновляйте зависимости и следите за новостями в области ИБ.

Источники