Files
Kubok-Regionov/GAME/narod/writeup.md
2025-12-22 05:19:38 +03:00

92 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NarodUslugi - полный разбор (пошагово)
Этот разбор объясняет, как устроен сервис и как решатель получает флаг.
Ссылки идут на локальные файлы задачи в этой директории.
## 1) Входные данные и их источники
- URL цели, partA и user можно читать из `target.txt` или передать через CLI.
- Поведение сервера описано в `files/server.js`.
- Логика решателя находится в `solver.py`.
- Значения окружения указаны в `web_naroduslugi_6.yml`.
## 2) Формула пароля (на сервере)
В `files/server.js` сервер считает пароль так:
- `PASS = sha1(f"{PWD_PART_A}:{PWD_PART_B}").hexdigest()[:12]`
`partA` у нас есть, но `partB` скрыт.
## 3) Где спрятан partB
Эндпоинт `/assets/app.js.map` отдает sourcemap со строкой:
- `pepper_xor_hex` (hex-строка)
Она вычисляется так:
- `pepper_xor_hex = xorHex(PWD_PART_B, sha1(user)[:6])`
Значит `partB` можно восстановить, если известен `user`.
## 4) Как восстановить partB
Шаги, которые делает `solver.py`:
1. `mask = sha1(user).digest()[:6]`
2. Преобразовать `pepper_xor_hex` в байты.
3. XOR-нуть каждый байт с `mask` (по кругу).
4. Декодировать результат как UTF-8 и получить `partB`.
После этого вычисляется пароль:
- `password = sha1(f"{partA}:{partB}").hexdigest()[:12]`
## 5) Trusted-device логин для доступа к экспорту профиля
Есть альтернативная авторизация, описанная в `/.well-known/`:
- Заголовки: `X-TS` и `X-Trusted-Device`
- `X-Trusted-Device = hex(hmac_sha1(pass, ts))`
- `ts` должен быть в окне 120 секунд
Если заголовки валидны, сессия помечается как `mfa=true`, но
`mfaOtp=false`. Это дает доступ к `/profile` и `/profile/export`.
## 6) Экспорт OTP-секрета отдается с маской
`/profile/export?fmt=ini` возвращает:
- `otp_secret` с заменой последних 2 base32-символов на `??`
Есть CSRF-проверка: нужен `Referer: /profile`.
Решатель выставляет этот заголовок.
## 7) Брут последних 2 base32-символов
Алфавит base32 длиной 32, значит всего 32 * 32 = 1024 вариантов.
Решатель перебирает все кандидаты:
1. Логинится обычным способом (без trusted заголовков).
2. Считает TOTP для кандидата.
3. POST на `/mfa` с `otp`.
4. При успехе открывает `/wallet` и `/wallet/drain`.
## 8) Синхронизация времени
Решатель читает `/__status__`, чтобы получить смещение времени сервера
и учитывать его при генерации TOTP (защита от дрейфа часов).
## 9) Получение флага
Если OTP верный, сессия получает `mfaOtp=true`, и `/wallet/drain`
возвращает флаг.
## 10) Важные ловушки
- Повторный trusted-логин во время активного окна доверия вызывает бан.
- Если trusted-сессия протухла без OTP, при следующем запросе будет бан.
- Решатель использует отдельные cookie-jar и лимит попыток на сессию.