Init. Commit
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<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}`
|
||||
Reference in New Issue
Block a user