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

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

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

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

Давайте разложим запрос на составляющие, чтобы понять логику атакующего.

1. AND

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

2. EXTRACTVALUE(9430, CONCAT(...))

EXTRACTVALUE — встроенная функция MySQL, предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(XML_фрагмент, XPath_выражение). В нашем случае первым аргументом передаётся число 9430 (произвольное число, может быть любым), а вторым — результат CONCAT.

Особенность EXTRACTVALUE в том, что если XPath-выражение некорректно, MySQL выдаёт ошибку, в тексте которой содержится переданное выражение. Это и используется для внедрения.

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

CONCAT объединяет строки. Здесь он склеивает:

  • 0x7e — шестнадцатеричное представление символа ~ (тильда). Используется как разделитель, чтобы облегчить извлечение данных из сообщения об ошибке.
  • ((SELECT (ELT(9430=9430,1)))) — подзапрос, возвращающий результат функции ELT.
  • Ещё один 0x7e — закрывающая тильда.

Таким образом, CONCAT формирует строку вида ~<результат>~, которая затем передаётся в EXTRACTVALUE в качестве XPath-выражения.

4. ELT(9430=9430, 1)

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Если N=1, возвращается первая строка. В данном случае 9430=9430 — это логическое выражение, которое всегда истинно (1). Поэтому ELT(1, 1) вернёт 1. Это простейший случай: атакующий мог бы заменить 1 на вызов другой функции, например VERSION() или DATABASE(), чтобы извлечь полезные данные.

Однако в приведённой строке подзапрос возвращает просто число 1. Это тестовый пример, чтобы проверить, выполняется ли инъекция. Если сервер вернёт ошибку с текстом, содержащим ~1~, значит, уязвимость есть.

5. -- -

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

Как это работает вместе

Представим, что исходный запрос был таким:

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

MySQL выполнит EXTRACTVALUE с XPath-выражением ~1~. Это выражение синтаксически некорректно, поэтому СУБД сгенерирует ошибку:

XPATH syntax error: '~1~'

В тексте ошибки появятся данные, которые злоумышленник внедрил в запрос. В данном случае это просто «1», но если заменить ELT(9430=9430,1) на VERSION(), то в ошибке отобразится версия MySQL. Если на DATABASE() — имя текущей базы данных. Если на подзапрос SELECT password FROM users LIMIT 1 — хеш пароля и т.д.

Таким образом, error-based инъекция позволяет извлекать произвольные данные из базы, если приложение выводит сообщения об ошибках MySQL пользователю.

Почему это опасно?

Успешная эксплуатация такой инъекции может привести к:

  • чтению конфиденциальных данных (пароли, персональные данные, номера кредитных карт);
  • обходу аутентификации;
  • изменению или удалению информации в базе;
  • полному захвату сервера в некоторых случаях.

Даже если приложение не показывает ошибки, злоумышленник может использовать слепые методы (blind SQL injection), но error-based считается более простой и быстрой.

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

Основная причина уязвимости — недостаточная фильтрация пользовательского ввода и конкатенация его в SQL-запрос. Вот ключевые меры:

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

В случае с EXTRACTVALUE можно также отключить эту функцию, если она не используется, но обычно проще исправить код.

Вывод

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

Если вы встретили такую строку в логах, это повод проверить свой сайт на уязвимости и усилить меры безопасности.

Источники