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

3.8 KiB
Raw Blame History

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 и лимит попыток на сессию.