SQL Injection: Обход WAF через mixed case
Case-sensitive blacklist SQL keywords обходится через смешанный регистр (uNiOn, sElEcT)
hardgolang
Задача
# SQL Injection: Обход WAF через смешанный регистр
## Сценарий
Вы проводите аудит безопасности **SecureShop**. После прошлого инцидента команда разработки добавила «защиту» в виде самописного WAF: список SQL-ключевых слов (`UNION`, `SELECT`, `FROM`, `WHERE`...), и любой запрос содержащий хотя бы одно из них блокируется с сообщением «WAF Alert». Архитектор хвастался, что теперь SQLi невозможен. Однако вы помните: blacklist-подход — антипаттерн, всегда найдётся способ записать ключевое слово так, чтобы фильтр его не увидел, а парсер базы — увидел.
## Цель
1. Подтвердите наличие WAF: отправьте классический payload `' UNION SELECT 1,2,3,4,5--` через поиск каталога и убедитесь, что он блокируется.
2. Исследуйте логику фильтра — определите, чувствителен ли он к регистру.
3. Постройте payload, обходящий WAF и одновременно валидный с точки зрения SQLite (5 колонок, корректные типы).
4. Извлеките содержимое таблицы `secrets` и заберите флаг — он лежит в значении ключа `admin_api_key`.
## Теория
**Blacklist-WAF** для SQLi — это попытка перечислить «опасные» строки и заблокировать их. Все такие фильтры разделяют общую слабость: между точкой проверки (приложением) и точкой выполнения (СУБД) лежит толстый слой нормализации. SQL не различает регистр ключевых слов (`SELECT` ≡ `select` ≡ `sElEcT`), допускает inline-комментарии (`UN/**/ION`), пробелы заменяются табами и переводами строк. Любое расхождение в нормализации между фильтром и парсером порождает обход.
**Уязвимый паттерн:**
```go
// case-sensitive blacklist — основа уязвимости:
var sqlBlacklist = []string{"UNION", "SELECT", "INSERT", "FROM", "WHERE", "OR", "AND"}
for _, kw := range sqlBlacklist {
if strings.Contains(search, kw) { // строгое сравнение, без ToUpper
http.Error(w, "WAF Alert: blocked", 400)
return
}
}
// затем тот же search без параметризации улетает в SQL:
query := fmt.Sprintf("SELECT ... FROM products WHERE name LIKE '%%%s%%'", search)
rows, err := h.db.Query(query)
```
В этой лабе SQL-парсер выполняет `SeLeCt`, а blacklist его не видит — классический пример асимметрии.
## Точка входа атаки
* **Эндпоинт:** `GET /catalog?q=<payload>`
* **Обычный пользователь:** `demo` / `demo` (для авторизации и разведки UI)
> Эта лаба — наглядная иллюстрация того, почему **blacklist никогда не должен быть единственной защитой от SQLi**. Финальный фикс — параметризованные запросы, которые архитектурно разделяют код и данные.