Что означает строка OR EXTRACTVALUE(1100,CONCAT(0x7e,((SELECT (ELT(1100=1100,1)))),0x7e))-- -?

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

Внешне выражение выглядит как часть SQL-запроса, которая добавляется к легитимному запросу через оператор OR. Если приложение не экранирует специальные символы, база данных выполнит внедрённый код и вернёт результат в виде ошибки, которую атакующий может прочитать.

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

1. OR

Логический оператор OR используется для присоединения вредоносного условия к исходному запросу. Например, если исходный запрос был SELECT * FROM users WHERE id = 1, то после подстановки получится SELECT * FROM users WHERE id = 1 OR EXTRACTVALUE(...). Поскольку OR возвращает истину, если хотя бы одно из условий истинно, внедрённая функция будет выполнена.

2. EXTRACTVALUE(1100, CONCAT(0x7e, ((SELECT (ELT(1100=1100,1)))), 0x7e))

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

В нашем случае первым аргументом идёт число 1100 — это не XML, но MySQL попытается его интерпретировать. Второй аргумент — CONCAT(0x7e, ((SELECT (ELT(1100=1100,1)))), 0x7e) — конструирует строку, которая будет вставлена в сообщение об ошибке.

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

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

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

ELT() — функция MySQL, которая возвращает N-й элемент из списка. Синтаксис: ELT(N, str1, str2, ...). В нашем случае ELT(1100=1100, 1): выражение 1100=1100 истинно, то есть равно 1 (в MySQL истина — это 1). Значит, ELT(1, 1) вернёт первый элемент списка — число 1. Подзапрос SELECT (ELT(...)) просто возвращает это значение.

Таким образом, вся конструкция CONCAT(0x7e, (SELECT (ELT(1100=1100,1))), 0x7e) создаст строку ~1~.

5. -- -

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

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

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

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

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

1 OR EXTRACTVALUE(1100,CONCAT(0x7e,((SELECT (ELT(1100=1100,1)))),0x7e))-- -

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

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

MySQL выполняет EXTRACTVALUE. Поскольку первый аргумент не является корректным XML, функция выдаёт ошибку. Но перед этим она вычисляет второй аргумент — строку ~1~. В тексте ошибки появится что-то вроде:

XPATH syntax error: '~1~'

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

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

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

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

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

Вывод

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

Источники