URL Case Bypass: обход проверки пути с помощью регистра
Middleware проверяет путь с учётом регистра (strings.HasPrefix). Замена /admin на /Admin позволяет обойти проверку роли администратора.
mediumgolangPro
Задача
# URL Path Bypass: ненадёжная нормализация при проверке доступа
## Сценарий
Вы зарегистрированы в интернет-магазине **SecureShop**. Команда защитила административные маршруты кастомным middleware, проверяющим начало URL-пути на префикс `/admin` и роль пользователя. Команда уверена, что защита работает корректно — обычные пользователи получают 403 при обращении к admin-маршрутам. По данным внутреннего аудита, среди защищённых эндпоинтов есть один, возвращающий JSON с секретными данными системы; его требуется получить от обычной учётной записи.
## Цель
1. Изучите, как именно middleware определяет «admin-маршрут»: какое сравнение применяется к URL-пути, нормализуется ли путь перед сравнением.
2. Найдите способ записать тот же URL-путь в форме, которая семантически эквивалентна, но отличается **по строковой представлению** — так, чтобы строковое сравнение не сработало.
3. Используйте обнаруженный обход и извлеките флаг из защищённого эндпоинта.
## Теория
Безопасная авторизационная проверка по URL должна работать с **нормализованным** путём — приведённым к канонической форме (lowercased, без дублирующих слэшей, без `..`, с decodeом URL-encoded символов). Любая «оптимизация» через прямое строковое сравнение (`strings.HasPrefix(path, "/admin")`, `path == "/admin/users"`, regex без флагов нечувствительности) создаёт side-channel: в HTTP/URL спецификациях есть множество эквивалентных записей одного пути, и роутер обычно их разрешает (Go `http.ServeMux` 1.22+ обрабатывает регистр чувствительно — `/Admin/data` и `/admin/data` это разные маршруты на уровне роутинга, но семантически могут вести к одному обработчику или разрешаться одинаково на уровне ОС/сервиса).
**Уязвимый паттерн:**
```go
// Регистрозависимое сравнение строки пути — обходится альтернативной записью
if strings.HasPrefix(r.URL.Path, "/admin") && user.Role != "admin" {
http.Error(w, "Access Denied", 403); return
}
```
Реальный пример класса — **CVE-2022-22978** в Spring Security: regex-based ACL обходился через `%0a` (newline) в URL, который декодировался ядром, но не учитывался regex-проверкой. Защита от такого класса атак — **системная нормализация** URL до любых проверок ACL.
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Учётные данные | `demo` / `demo` |
| Известный admin-эндпоинт (заблокирован для demo) | `GET /admin/data` |
| Цель | обнаружить альтернативную форму пути, которая обходит middleware-проверку, и извлечь флаг из JSON-ответа |