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

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

В этой статье мы детально разберём каждый элемент запроса, объясним, как работает атака, и покажем, как защитить приложение от подобных вторжений.

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

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

1. Закрывающая скобка и логический оператор `AND`

Строка начинается с ) — закрывающей скобки. В исходном SQL-запросе, вероятно, была незакрытая скобка, и злоумышленник добавляет её, чтобы «уравновесить» синтаксис и внедрить свой код. Затем идёт оператор AND, который позволяет добавить дополнительное условие к существующему запросу. Если исходный запрос был, например, SELECT * FROM users WHERE id = (1), то после подстановки вредоносной строки он превратится в SELECT * FROM users WHERE id = (1) AND EXTRACTVALUE(...).

2. Функция `EXTRACTVALUE`

EXTRACTVALUE(XML_target, XPath_expr) — это встроенная функция MySQL (и MariaDB), предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Однако она имеет особенность: если XPath-выражение некорректно или возвращает не-скалярное значение, функция генерирует ошибку, в тексте которой может содержаться часть переданных данных.

Злоумышленники используют это свойство для «вытаскивания» результатов подзапроса в сообщение об ошибке, которое затем отображается на странице (если приложение не подавляет ошибки).

3. Второй аргумент `CONCAT(0x7e, ..., 0x7e)`

CONCAT объединяет строки. Здесь он собирает строку из трёх частей:

  • 0x7e — шестнадцатеричное представление символа ~ (тильда).
  • Результат подзапроса (SELECT (ELT(7366=7366,1))).
  • Снова 0x7e — закрывающая тильда.

Тильда используется как маркер, чтобы облегчить поиск извлечённых данных в тексте ошибки. Например, ошибка может выглядеть так: XPATH syntax error: '~1~'.

4. Подзапрос `(SELECT (ELT(7366=7366,1)))`

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае ELT(7366=7366, 1) вычисляет логическое выражение 7366=7366 (истина, то есть 1) и возвращает первый элемент — 1. Это простейший тест, который всегда возвращает 1. В реальной атаке вместо этого подзапроса мог бы быть, например, (SELECT password FROM users LIMIT 1), и тогда в ошибке отобразился бы пароль.

Таким образом, данная конструкция — это «разминка» или проверка работоспособности инъекции. Если приложение вернёт ошибку с текстом ~1~, значит, инъекция возможна и можно извлекать произвольные данные.

5. Комментарий `-- -`

Два дефиса с пробелом (или -- -) начинают комментарий в MySQL. Всё, что идёт после них, игнорируется сервером. Это нужно, чтобы «отрезать» оставшуюся часть оригинального запроса, которая могла бы вызвать синтаксическую ошибку или помешать выполнению внедрённого кода.

Как работает атака целиком

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

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

Злоумышленник передаёт параметр id со значением 1) AND EXTRACTVALUE(7366,CONCAT(0x7e,((SELECT (ELT(7366=7366,1)))),0x7e))-- -. Итоговый запрос:

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

Сервер MySQL выполнит его, и при попытке вычислить EXTRACTVALUE возникнет ошибка:

XPATH syntax error: '~1~'

Если приложение выводит эту ошибку пользователю, злоумышленник понимает, что инъекция работает. Затем он заменяет ELT(7366=7366,1) на подзапрос, извлекающий нужные данные (например, имена таблиц, логины, пароли), и повторяет атаку.

Меры защиты

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

  • Использовать подготовленные выражения (prepared statements) с параметризацией запросов. Это самый надёжный способ, так как данные никогда не смешиваются с кодом SQL.
  • Экранировать специальные символы при невозможности использовать подготовленные выражения (например, с помощью функций mysqli_real_escape_string или PDO::quote).
  • Отключать вывод ошибок БД на продакшене. Сообщения об ошибках должны логироваться, но не показываться пользователю.
  • Ограничивать права пользователя БД, от имени которого работает приложение: не давать ему прав на чтение системных таблиц и выполнение опасных функций.
  • Регулярно проводить аудит безопасности и использовать сканеры уязвимостей.

Заключение

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

Источники