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

Строка ` AND EXTRACTVALUE(5421,CONCAT(0x7e,((SELECT (ELT(5421=5421,1)))),0x7e))-- - — это типичный пример SQL-инъекции, нацеленной на базу данных MySQL. Она может появиться в логах веб-сервера, в поле ввода формы или в параметрах URL. Её основная цель — заставить сервер выполнить произвольный SQL-код и вернуть информацию об ошибке, которая раскроет структуру базы данных или её содержимое.

Подобные строки часто встречаются в отчётах систем обнаружения вторжений (IDS) и в логах WAF. Они не являются случайным набором символов, а представляют собой тщательно сконструированную полезную нагрузку (payload) для эксплуатации уязвимости типа «SQL-инъекция на основе ошибок» (error-based SQL injection).

Разбор компонентов инъекции

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

1. Обратный апостроф (`) и логический оператор AND

Символ обратного апострофа (`) в MySQL используется для экранирования идентификаторов (имён таблиц, столбцов). В данном случае он, вероятно, закрывает предыдущее выражение в исходном SQL-запросе, которое было сформировано разработчиком. Затем идёт AND — логический оператор, который позволяет добавить дополнительное условие к существующему запросу. Если исходный запрос был, например, SELECT * FROM users WHERE id = '1', то после подстановки инъекции он может превратиться в SELECT * FROM users WHERE id = '1' AND EXTRACTVALUE(...)-- -.

2. Функция EXTRACTVALUE

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

3. CONCAT и шестнадцатеричные литералы

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

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

Тильда используется как разделитель, чтобы облегчить поиск извлечённых данных в сообщении об ошибке.

4. Подзапрос с ELT

ELT(N, str1, str2, ...) — функция, возвращающая N-ю строку из списка. В нашем случае ELT(5421=5421,1) возвращает 1, так как условие 5421=5421 всегда истинно (1). Это простейший случай, но на практике вместо 1 мог бы быть, например, database(), user() или version(). Тогда EXTRACTVALUE вызвал бы ошибку, содержащую имя базы данных или другую полезную информацию.

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

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

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

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

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

Злоумышленник передаёт в параметре id следующее значение:

1' AND EXTRACTVALUE(5421,CONCAT(0x7e,((SELECT (ELT(5421=5421,1)))),0x7e))-- -

После подстановки получается:

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

MySQL выполняет запрос. Функция EXTRACTVALUE получает XPath-выражение, которое начинается с тильды, что является синтаксической ошибкой. MySQL возвращает ошибку вида:

XPATH syntax error: '~1~'

В этом сообщении видно значение, возвращённое подзапросом (в нашем случае 1). Если бы вместо 1 стояла функция database(), в ошибке отобразилось бы имя текущей базы данных. Таким образом, злоумышленник может извлекать произвольные данные посимвольно или целыми строками, если позволяет длина сообщения об ошибке.

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

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

Меры защиты

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

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

Заключение

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

Источники