Что такое SQL-инъекция через EXTRACTVALUE?

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

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

Разбор запроса AND EXTRACTVALUE(1694,CONCAT(0x7e,((SELECT (ELT(1694=1694,1)))),0x7e))-- -

Рассмотрим детально, что делает каждый элемент этого запроса.

1. Префикс AND

Конструкция AND добавляется к исходному SQL-запросу, чтобы внедрить дополнительное условие. Если исходный запрос был, например, SELECT * FROM users WHERE id = 1, то после инъекции он превращается в SELECT * FROM users WHERE id = 1 AND EXTRACTVALUE(...). Это позволяет выполнить вредоносную функцию только при истинности предыдущего условия.

2. Функция EXTRACTVALUE(1694, CONCAT(...))

Первый аргумент — 1694 — произвольное число (может быть любым). Второй аргумент — результат CONCAT(), который формирует строку, интерпретируемую как XPath-выражение. Поскольку эта строка не является корректным XPath, MySQL выдаст ошибку вида: XPATH syntax error: '~...~', где ~ — разделитель, добавленный через 0x7e (шестнадцатеричное представление тильды).

3. CONCAT(0x7e, ((SELECT (ELT(1694=1694,1)))), 0x7e)

Функция CONCAT объединяет три части:

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

4. ELT(1694=1694, 1)

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

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

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

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

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

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

При выполнении MySQL попытается вычислить EXTRACTVALUE и выдаст ошибку:

XPATH syntax error: '~1~'

Таким образом, атакующий получает подтверждение, что инъекция работает, и может заменить 1 на любой другой подзапрос, например, (SELECT version()), чтобы узнать версию СУБД, или (SELECT password FROM users LIMIT 1) для кражи паролей.

Зачем используется ELT и 1694=1694?

Конструкция ELT(1694=1694,1) — это классический приём в error-based инъекциях. Выражение 1694=1694 всегда истинно, что даёт ELT(1,1). Это позволяет обойти фильтры, которые могут блокировать прямые подзапросы, и продемонстрировать работоспособность инъекции без реального извлечения данных. В реальных атаках вместо 1 подставляется сложный подзапрос, а вместо 1694=1694 может быть условие, зависящее от данных (например, ASCII(SUBSTRING(...))>100).

Меры защиты

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

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

Заключение

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

Источники