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

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

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

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

1. Одинарная кавычка (')

Символ ' в начале строки предназначен для «разрыва» исходного SQL-запроса. Если уязвимый код подставляет пользовательский ввод в запрос без должной обработки, эта кавычка закрывает строковый литерал, и всё, что идёт дальше, интерпретируется как часть SQL-выражения.

2. AND

Логический оператор AND добавляет наше условие к исходному запросу. Чтобы исходный запрос остался истинным (и приложение продолжило работу), внедряемое выражение тоже должно быть истинным.

3. EXTRACTVALUE(3767, CONCAT(...))

Функция EXTRACTVALUE() в MySQL извлекает значение из XML-фрагмента. Если переданный XML-документ содержит синтаксическую ошибку, MySQL генерирует сообщение об ошибке, в котором отображается часть переданных данных. Именно это и используется для вывода результата подзапроса.

Первый аргумент 3767 — произвольное число (может быть любым), оно не влияет на логику, но должно быть допустимым XML-фрагментом. Второй аргумент — выражение CONCAT(...), которое формирует строку, содержащую результат вложенного запроса.

4. CONCAT(0x7e, (SELECT ...), 0x7e)

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

Внутри CONCAT находится подзапрос (SELECT (ELT(3767=3767,1))). Он возвращает значение, которое мы хотим извлечь. В данном случае это просто число 1, но в реальной атаке на месте ELT(...) может быть обращение к таблицам, например (SELECT password FROM users LIMIT 1).

5. ELT(3767=3767, 1)

ELT() возвращает N-й элемент из списка. Первый аргумент — условие 3767=3767, которое всегда истинно (1). Второй аргумент — 1. Таким образом, ELT(1, 1) вернёт 1. Это простейшая проверка работоспособности инъекции: если ошибка появится, значит, внедрение сработало.

В более сложных атаках вместо 3767=3767 может быть условие, проверяющее, например, первый символ имени базы данных, и тогда ELT вернёт разные значения в зависимости от истинности условия. Это позволяет действовать «слепым» методом, но в данном случае используется именно error-based подход.

6. -- -

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

Как это работает целиком

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

SELECT * FROM articles WHERE id = '1'

После подстановки нашего ввода запрос станет:

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

MySQL выполняет запрос. Сначала проверяется условие id = '1' (истинно), затем вычисляется EXTRACTVALUE. Второй аргумент — строка ~1~. EXTRACTVALUE пытается разобрать её как XML и терпит неудачу, потому что ~1~ не является корректным XML. MySQL возвращает ошибку вида:

XPATH syntax error: '~1~'

В сообщении об ошибке мы видим содержимое, которое вернул подзапрос (в данном случае 1). Если бы вместо ELT(3767=3767,1) стоял подзапрос, извлекающий пароль, мы бы увидели его в тексте ошибки.

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

Error-based инъекции — мощный инструмент, потому что они позволяют получать данные напрямую, без необходимости угадывать символы (как в blind SQL-инъекциях). Однако для их успешного применения необходимо, чтобы приложение выводило сообщения об ошибках базы данных пользователю. В противном случае атакующий не увидит результат.

Подобные конструкции часто встречаются в автоматизированных инструментах, таких как sqlmap, которые автоматически подбирают работающий метод инъекции.

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

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

Заключение

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

Источники