Введение
Встречая в логах или в поле ввода строку вида `))) AND EXTRACTVALUE(4343,CONCAT(0x7e,((SELECT (ELT(4343=4343,1)))),0x7e))-- -, многие задаются вопросом: что это такое? Это не случайный набор символов, а целенаправленная попытка эксплуатации уязвимости SQL-инъекции типа error-based (основанной на ошибках) в СУБД MySQL. В данной статье мы подробно разберём, как работает этот запрос, какие функции задействованы и как защититься от подобных атак.
Что такое error-based SQL-инъекция?
SQL-инъекция — это один из самых распространённых способов взлома веб-приложений, при котором злоумышленник внедряет свой SQL-код в запросы, выполняемые приложением. Error-based инъекция — это разновидность, при которой атакующий заставляет сервер базы данных выдать сообщение об ошибке, содержащее полезные данные (например, имя базы данных, версию, имена таблиц).
В MySQL для этого часто используются функции EXTRACTVALUE() и UPDATEXML(). Они предназначены для работы с XML, но при передаче некорректных данных вызывают ошибку, в тексте которой отображается переданное значение. Если в это значение подставить результат подзапроса, можно извлечь произвольную информацию.
Разбор запроса `))) AND EXTRACTVALUE(4343,CONCAT(0x7e,((SELECT (ELT(4343=4343,1)))),0x7e))-- -
Давайте разберём этот payload по частям:
`)))— закрывающие символы, которые, вероятно, завершают оригинальный SQL-запрос и его условия. Символ обратного апострофа (`) используется для экранирования идентификаторов в MySQL. Три закрывающие скобки могут закрывать вложенные конструкции исходного запроса.AND— логический оператор, добавляющий условие к запросу.EXTRACTVALUE(4343, CONCAT(...))— вызов функцииEXTRACTVALUEс двумя аргументами: первый — произвольное число (4343), второй — результат конкатенации. Функция ожидает, что второй аргумент будет корректным XPath-выражением. Если это не так, генерируется ошибка с текстом переданного значения.CONCAT(0x7e, ((SELECT (ELT(4343=4343,1)))), 0x7e)— конкатенация символа тильды (0x7e— шестнадцатеричный код символа~), результата подзапроса и ещё одной тильды. Тильды служат маркерами, чтобы в сообщении об ошибке легко было выделить извлечённые данные.SELECT (ELT(4343=4343,1))— подзапрос, возвращающий результат функцииELT().ELT(N, str1, str2, ...)возвращает N-ю строку из списка. Здесь4343=4343— это логическое выражение, которое всегда истинно (1). Таким образом,ELT(1,1)вернёт строку '1'. Это простейший пример; в реальной атаке вместо этого подзапроса может быть запрос к системным таблицам, например,SELECT database()илиSELECT table_name FROM information_schema.tables.-- -— комментарий, который игнорирует оставшуюся часть оригинального запроса. В MySQL комментарий начинается с--(два дефиса и пробел) или#. Здесь используется-- -, где второй дефис отделён пробелом, чтобы гарантировать корректное распознавание комментария.
Таким образом, данный payload пытается внедрить в оригинальный запрос вызов EXTRACTVALUE, который должен вызвать ошибку с текстом, содержащим результат подзапроса. В приведённом примере результат — просто '1', но в реальной атаке здесь были бы конфиденциальные данные.
Как работает EXTRACTVALUE для извлечения данных?
Функция EXTRACTVALUE(XML_document, XPath_expression) извлекает значение из XML-документа по заданному XPath-выражению. Если XPath-выражение некорректно, MySQL возвращает ошибку вида:
XPATH syntax error: '~результат~'
Именно этот текст ошибки и видит атакующий. Подставляя в XPath-выражение результаты подзапросов, можно посимвольно или целиком извлекать имена баз данных, таблиц, колонок и даже хеши паролей.
Современные версии MySQL (начиная с 5.7.9) и MariaDB содержат исправления, но во многих устаревших системах эта уязвимость всё ещё эксплуатируется.
Примеры реальных атак
Вот как может выглядеть запрос для извлечения имени текущей базы данных:
`))) AND EXTRACTVALUE(4343,CONCAT(0x7e,(SELECT database()),0x7e))-- -
А для получения версии MySQL:
`))) AND EXTRACTVALUE(4343,CONCAT(0x7e,(SELECT version()),0x7e))-- -
Для извлечения имён таблиц из системной схемы information_schema:
`))) AND EXTRACTVALUE(4343,CONCAT(0x7e,(SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),0x7e))-- -
И так далее, с помощью LIMIT можно перебирать строки одну за другой.
Меры защиты
Чтобы предотвратить подобные атаки, необходимо:
- Использовать подготовленные выражения (prepared statements) с параметризацией запросов. Это самый надёжный способ, так как SQL-код и данные передаются раздельно.
- Применять ORM (например, Hibernate, Entity Framework), которые автоматически экранируют опасные символы.
- Проводить валидацию и фильтрацию входных данных. Особенно это касается полей, которые передаются в SQL-запросы.
- Ограничить права пользователя базы данных, от имени которого работает приложение. Не давайте ему доступ к системным таблицам без необходимости.
- Регулярно обновлять СУБД и веб-приложения. В новых версиях многие уязвимости закрыты.
- Использовать WAF (Web Application Firewall) для фильтрации подозрительных запросов.
Также рекомендуется проводить аудит кода и пентесты для выявления уязвимостей.
Заключение
Запрос `))) AND EXTRACTVALUE(4343,CONCAT(0x7e,((SELECT (ELT(4343=4343,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции в MySQL. Понимание механики таких атак помогает разработчикам и администраторам лучше защищать свои системы. Помните, что безопасность — это процесс, а не одноразовое действие.
Комментарии
—Войдите, чтобы оставить комментарий