Files
2026-09-17 00:50:07 +03:00

46 lines
3.5 KiB
Markdown
Raw Permalink 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.
<h1 align="center">Grant Residue</h1>
<p align="center">
<img src="https://img.shields.io/badge/category-Forensic-blueviolet" alt="Forensic"/>
<img src="https://img.shields.io/badge/difficulty-medium-orange" alt="medium"/>
</p>
В архиве `grant_residue_case.zip` находится выгрузка SOC. В материалах инцидента описаны отправка кода финансовому отделу под предлогом передачи встречи и последующий экспорт Microsoft Graph. Пароль не менялся, MFA прошла штатно. По журналам определяем, какой поток авторизации использовался для доступа.
## Решение
Начинаем с рабочей станции, затем идём по облачным журналам:
| Файл | Что ищем |
|---|---|
| `endpoint/powershell_transcript.txt` | Код, который видела жертва |
| `endpoint/defender_device_events.jsonl` | Подтверждение того же кода |
| `entra/signin_logs.jsonl` | Успешный вход и `correlationId` |
| `entra/audit_logs.jsonl` | Выданный OAuth-грант |
| `m365/unified_audit_log.jsonl` | Экспорт с этим грантом |
В транскрипте PowerShell находим `FJQ9-L2RM` — строку формата `[A-Z0-9]{4}-[A-Z0-9]{4}`. Тот же код есть в телеметрии Defender, в `AdditionalFields.UserCodeObserved`.
Теперь фильтруем входы Entra: `authenticationProtocol == "DeviceCode"`, `userCodeEvidence == "FJQ9-L2RM"`, `status.errorCode == 0`. Получаем успешную авторизацию через device code flow и её `correlationId`.
Пароль не менялся, поскольку жертва прошла штатный вход, но подтвердила код чужого запроса. Теперь выясняем, какие права получила эта авторизация.
В `entra/audit_logs.jsonl` находим `Consent to application` с тем же `correlationId` и `result == "success"`. Среди `targetResources[].modifiedProperties[]` читаем `newValue` свойства `OAuth2PermissionGrant.Id`. Сохраняем полный идентификатор для сопоставления событий, а его хвост после последнего дефиса, `grant72`, используем в ответе.
Проверяем последствия в M365. Нужна запись `GraphExportJobCreated`, где одновременно совпадают `CorrelationId` и `OAuth2PermissionGrantId`, а `ResultStatus == "Succeeded"`. Из `ExportId` берём хвост `export18`.
Формат ответа собирается так:
```python
parts = ["dc", "FJQ9-L2RM".replace("-", "").lower(), "grant72", "export18"]
flag = "caplag{" + "_".join(parts) + "}"
```
`dc` обозначает найденный поток. Остальные части связывают наблюдение кода на рабочей станции с успешным входом, выдачей согласия и последующим экспортом. Совпадение идентификаторов на каждом переходе подтверждает эту связь.
[Солвер](solve/solve.py).
## Флаг
`caplag{dc_fjq9l2rm_grant72_export18}`