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

Представленная строка:

") OR EXTRACTVALUE(3722,CONCAT(0x7e,((SELECT (ELT(3722=3722,1)))),0x7e))-- -

является классическим примером error-based SQL-инъекции (инъекции, основанной на ошибках) для СУБД MySQL. Такие конструкции используются злоумышленниками для извлечения данных из базы данных путём вызова ошибок, в тексте которых возвращается запрашиваемая информация.

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

Разбор компонентов запроса

Разберём строку по частям:

  • ") — закрывающая кавычка и скобка. Предполагается, что исходный SQL-запрос имел вид SELECT ... WHERE field = ("..."). Злоумышленник закрывает строковый литерал и скобку, чтобы внедрить свой код.
  • OR — логический оператор, который делает условие всегда истинным или позволяет выполнить дополнительное выражение.
  • EXTRACTVALUE(3722, CONCAT(0x7e, ((SELECT (ELT(3722=3722,1)))), 0x7e)) — вызов функции EXTRACTVALUE, которая извлекает значение из XML-фрагмента по XPath-выражению. Если XPath-выражение некорректно, MySQL генерирует ошибку, содержащую переданный аргумент.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального запроса, чтобы синтаксис был корректным.

Функция EXTRACTVALUE

EXTRACTVALUE(XML_frag, XPath_expr) возвращает текст первого текстового узла, найденного по XPath-выражению. Если XPath содержит недопустимые символы (например, тильду ~), MySQL выдаёт ошибку вида:

XPATH syntax error: '~1~'

Именно эту ошибку и использует атакующий: в сообщении об ошибке отображается результат подзапроса.

Функция ELT и условие 3722=3722

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае ELT(3722=3722, 1) — условие 3722=3722 всегда истинно (равно 1), поэтому возвращается первый элемент — 1. Это простейшая проверка работоспособности инъекции. В реальных атаках вместо 1 подставляются подзапросы, извлекающие имена таблиц, колонок или данные пользователей.

CONCAT и 0x7e

CONCAT(0x7e, ..., 0x7e) объединяет строки. 0x7e — это шестнадцатеричный код символа ~ (тильда). Тильда используется как маркер, чтобы в сообщении об ошибке было легко найти внедрённые данные. Например, ошибка примет вид XPATH syntax error: '~1~'.

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

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

SELECT * FROM users WHERE name = ("$input")

Если пользователь передаст строку ") OR EXTRACTVALUE(3722,CONCAT(0x7e,((SELECT (ELT(3722=3722,1)))),0x7e))-- -, итоговый SQL станет:

SELECT * FROM users WHERE name = ("") OR EXTRACTVALUE(3722,CONCAT(0x7e,((SELECT (ELT(3722=3722,1)))),0x7e))-- -")

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

Далее атакующий заменяет 1 на подзапрос, например:

SELECT (SELECT table_name FROM information_schema.tables LIMIT 0,1)

и получает имя первой таблицы в ошибке. Меняя LIMIT, можно перебрать все таблицы и колонки, а затем извлечь данные.

Примеры реальных полезных нагрузок

Вот как выглядят типичные error-based инъекции через EXTRACTVALUE:

  • ' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))-- - — получение имени текущей базы данных.
  • ' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT user()), 0x7e))-- - — получение имени пользователя MySQL.
  • ' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1), 0x7e))-- - — извлечение имени первой таблицы.

Аналогичный подход используется с функциями UPDATEXML и GTID_SUBSET.

Чем опасна error-based SQL-инъекция?

Error-based инъекции позволяют злоумышленнику:

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

Опасность усугубляется тем, что для атаки достаточно лишь выводить сообщения об ошибках СУБД в ответе приложения. Многие фреймворки в режиме отладки делают это по умолчанию.

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

Основные меры защиты:

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

Заключение

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

Источники