Type Juggling: Magic Hash Collision
API-логин через токен использует loose comparison (==) между md5-хэшами. Magic hash вида 0e[0-9]+ интерпретируется как научная нотация (0.0), что приводит к коллизии хэшей и обходу аутентификации.
easyphpPro
Задача
# Lab: Type Juggling — Magic Hash Collision
## Сценарий
В SecureShop есть «легаси»-эндпоинт `/api/token-login`, оставшийся от старых внутренних интеграций. Он принимает JSON вида `{"username": "...", "token": "..."}`, считает `md5()` от присланного токена и сравнивает результат со значением в базе. При совпадении сервер выдаёт обычный `session_token` cookie — тот же, что и форма `/login`, — и клиент получает полный доступ под этим пользователем.
Реальный токен администратора хранится только в виде md5-хэша и нигде в коде не фигурирует. Но разработчик сравнил хэши через `==` вместо `===`. В PHP это классическая «magic hash»-ловушка: строки вида `0e[0-9]+` интерпретируются как число в научной нотации (`0 * 10^N = 0`), поэтому любые два таких значения считаются равными при loose-сравнении. Если сохранённый хэш попал в класс `0e[0-9]+`, обойти проверку можно любым plaintext, чей md5 тоже попадает в этот класс, — сам секрет знать не нужно.
## Цели
1. Обойти аутентификацию `/api/token-login` для пользователя `admin`, не зная его реального токена.
2. Получить `session_token` cookie, принадлежащий admin-сессии.
3. Зайти с этой cookie на `/profile` и увидеть содержимое, относящееся к администратору.
## Данные
| Параметр | Значение |
|----------|----------|
| Уязвимый эндпоинт | `POST /api/token-login` |
| Формат тела | `{"username": "admin", "token": "<plaintext>"}` |
| Целевой пользователь | `admin` |
| Обычный пользователь | `demo` / `demo` (для сравнения обычного логина) |
## Как понять, что атака удалась
- Ответ сервера: HTTP 200 и тело `{"status":"ok", "username":"admin", ...}`.
- В ответе пришла cookie `session_token=<uuid>`.
- С этой cookie `GET /profile` возвращает 200 и страницу, относящуюся к `admin`.