Введение

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

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

SQL-инъекция (SQL injection) — один из самых распространённых способов взлома веб-сайтов. Суть метода в том, что злоумышленник передаёт в поля ввода или параметры запроса специально сконструированную строку, которая «вклинивается» в SQL-запрос, выполняемый на сервере. Если приложение не проверяет входные данные должным образом, база данных воспринимает часть введённой строки как исполняемый код.

Существует несколько разновидностей SQL-инъекций:

  • Union-based — объединение результатов легального запроса с данными из других таблиц.
  • Error-based — извлечение информации через сообщения об ошибках, которые генерирует сама СУБД.
  • Blind — когда данные извлекаются по косвенным признакам (истина/ложь, задержки времени).
  • Stacked queries — выполнение нескольких запросов подряд.

Рассматриваемая строка относится именно к error-based типу. Она заставляет MySQL выдать сообщение об ошибке, в текст которого подставляются данные из базы.

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

Давайте разберём payload поэтапно.

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

Символ % — это URL-кодирование, за ним обычно следует шестнадцатеричный код. Далее идут кавычка, закрывающие скобки и апострофы. Их задача — «закрыть» легальный запрос приложения и подготовить почву для внедрения собственного кода. Конкретное количество скобок подбирается методом проб и ошибок, чтобы синтаксис стал корректным.

2. AND EXTRACTVALUE(...)

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

3. CONCAT(0x7e, ..., 0x7e)

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

4. (SELECT (ELT(5742=5742,1)))

ELT() возвращает N-й элемент из списка. Выражение 5742=5742 всегда истинно, поэтому возвращается первый элемент — число 1. В реальной атаке вместо этого простого условия подставляется подзапрос, извлекающий, например, имя пользователя, версию СУБД или хеш пароля. Число 5742 — это просто «заглушка», которая может меняться от запроса к запросу, чтобы избежать сигнатурных фильтров.

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

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

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

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

SELECT * FROM users WHERE id = '$input';

Если в $input подставить рассматриваемую строку, запрос превратится в нечто подобное:

SELECT * FROM users WHERE id = '%")))) AND EXTRACTVALUE(5742,CONCAT(0x7e,((SELECT (ELT(5742=5742,1)))),0x7e))-- -';

MySQL попытается выполнить EXTRACTVALUE с некорректным XPath (потому что CONCAT возвращает строку, не являющуюся валидным XPath). В результате возникнет ошибка, и в её тексте появится что-то вроде:

XPATH syntax error: '~1~'

Если вместо 1 подставить подзапрос, например (SELECT version()), в ошибке отобразится версия MySQL. Так злоумышленник может постепенно извлекать любые данные: имена таблиц, логины, пароли.

Зачем нужны тильды и ELT

Символ ~ (0x7e) выбран не случайно: он редко встречается в обычных данных и легко находится в тексте ошибки. ELT с всегда истинным условием — это способ вернуть конкретное значение, не прибегая к сложным конструкциям. В более продвинутых payload'ах вместо ELT могут использоваться UPDATEXML, EXTRACTVALUE с другими аргументами или функции GTID_SUBSET, JSON_KEYS и т.п.

Чем опасна такая инъекция

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

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

Даже если база данных не содержит критичной информации, успешная инъекция подрывает доверие к сервису и может привести к блокировкам со стороны поисковых систем и хостинг-провайдеров.

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

Основной способ борьбы с SQL-инъекциями — параметризованные запросы (prepared statements). Они разделяют код и данные, поэтому введённая строка никогда не интерпретируется как SQL-код. Дополнительные меры:

  1. Использовать ORM и библиотеки, которые автоматически экранируют данные.
  2. Проверять и фильтровать все входные данные на стороне сервера.
  3. Ограничить права пользователя базы данных: приложение должно работать с минимально необходимыми привилегиями.
  4. Отключить вывод подробных ошибок СУБД в production-окружении.
  5. Регулярно обновлять СУБД и фреймворки.
  6. Проводить аудит безопасности и использовать сканеры уязвимостей.

Заключение

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

Источники