Перейти к содержимому
Назад к пути
Теория 3 мин чтения

3. Условные операторы и задержки

Условные операторы и задержки: "Если — То — Засни"

Time-based инъекция — это фактически «двоичный код времени». Хакеру недостаточно просто остановить работу базы; ему нужно, чтобы она замирала только при выполнении определенного условия (например, если первая буква пароля администратора — 'A'). Так он получает подтверждение своих догадок через паузы в ответах.

Разберем, как с помощью SQL-операторов CASE или IF злоумышленник управляет временем ответа вашего Go-приложения.


1. Механика: "Если — То — Сон"

Хакер внедряет логическую конструкцию прямо в запрос. Вот как это выглядит на практике:

Пример для PostgreSQL:

1 AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)

  1. Если условие 1=1 (Истина) — база выполняет команду pg_sleep(5). Ответ задержится на 5 секунд.
  2. Если условие 1=2 (Ложь) — выполняется pg_sleep(0). Сервер отвечает мгновенно.

2. Разница синтаксиса в СУБД

Хакеры адаптируют атаку под конкретный движок базы данных:

СУБД Синтаксис условия Пример атак
PostgreSQL CASE WHEN (cond) THEN pg_sleep(5) ELSE pg_sleep(0) END ... WHEN (SUBSTR(pass,1,1)='A') THEN...
MySQL IF(cond, SLEEP(5), 0) ... IF(1=1, SLEEP(5), 0)
SQLite Сложная логика через нагрузку CPU ... CASE WHEN (1=1) THEN r_blob(10) ELSE 0 END

3. Финальный удар: Извлечение данных

Хакер отправляет запрос, который по одному символу проверяет ваш секретный токен: ?id=1 AND (SELECT CASE WHEN (SUBSTRING((SELECT token FROM config LIMIT 1), 1, 1) = 'a') THEN pg_sleep(5) ELSE pg_sleep(0) END)

Если ответ пришел с задержкой в 5 секунд — хакер точно знает, что первая буква секретного значения — это 'a'.


4. Почему Go позволяет это делать?

Проблема в том, что когда разработчик использует fmt.Sprintf или конкатенацию для сборки запроса, вредоносный SQL-код беспрепятственно попадает в базу. Драйвер Go считает это обычной командой и честно ждет её завершения. Всё, что видит приложение — это долгий ответ от СУБД.


5. Точка входа — не только URL и тело запроса

Многие забывают, что HTTP-заголовки — такой же источник пользовательского ввода, как параметры формы. Если backend читает значение заголовка (например, кастомного для аналитики или User-Agent для логов) и подставляет его в SQL через конкатенацию, то заголовок становится точкой инъекции. Это особенно коварно для INSERT-запросов: ответ возвращает 200 OK независимо от данных, и единственный наблюдаемый сигнал — время отклика.

Шаблон INSERT-инъекции через конкатенацию

Уязвимый код приложения часто формирует INSERT через fmt.Sprintf:

// ❌ УЯЗВИМО: значение заголовка вклеивается в строку SQL
query := fmt.Sprintf("INSERT INTO logs (key, ua) VALUES ('%s', 'Go')", header)
db.Exec(query)

Чтобы проверить уязвимость и одновременно встроить условную задержку, payload должен «зашить» оператор конкатенации SQL в значение поля. В SQLite оператор склейки строк — ||:

' || (CASE WHEN (1=1) THEN (SELECT count(hex(randomblob(200000000)))) ELSE 0 END) || '

Структура шаблона:

  1. ' — закрывает текущий строковый литерал в VALUES ('...').
  2. || — оператор конкатенации SQLite (в MySQL это будет CONCAT(...), в PostgreSQL тоже ||).
  3. (CASE WHEN <предикат> THEN <heavy_query> ELSE 0 END) — условная задержка: при истине считаем тяжёлый randomblob, иначе мгновенный 0.
  4. || ' — снова склейка с пустой строкой, чтобы исходный INSERT остался синтаксически корректным.

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

INSERT INTO logs (key, ua) VALUES ('' || (CASE WHEN (1=1) THEN (...) ELSE 0 END) || '', 'Go')

Запрос валиден, ответ всё равно возвращает 200 OK, но при истинности предиката база уйдёт на ~2 секунды считать randomblob. Ровно эта задержка — единственный observable сигнал для INSERT-инъекции, где данные не возвращаются клиенту.


Лабораторная этого модуля строится именно на таком сценарии. Точка входа — обычная страница каталога, без формы и без видимого поля для ввода: payload уходит в HTTP-заголовок запроса, и единственный сигнал для атакующего — задержка ответа сервера:

Чтобы построить условную задержку, в значении заголовка нужно: закрыть строковый литерал, через оператор конкатенации (|| в SQLite) встроить CASE WHEN ... THEN heavy_query ELSE 0 END и снова открыть кавычку, чтобы исходный INSERT остался синтаксически валидным. Конкретные пейлоады в подсказках лабы намеренно не приведены — собрать их студент должен сам, опираясь на разобранную выше теорию CASE WHEN и оракул TRUE = медленный ответ.


Условные задержки превращают базу в «молчаливого свидетеля», который выдает секреты через паузы в разговоре. Это делает атаку крайне незаметной для стандартных систем мониторинга производительности.

Однако у Go есть мощный механизм контроля ресурсов, который может стать серьезной преградой для таких атак. Узнаем, как использование контекстов и таймаутов спасает приложение.

Продолжить чтение

Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу

Когда закончишь — отметь раздел, чтобы продолжить.

🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru