Init. commit
This commit is contained in:
50
web-umbrella-bio-access/WRITEUP.md
Normal file
50
web-umbrella-bio-access/WRITEUP.md
Normal file
@@ -0,0 +1,50 @@
|
||||
<h1 align="center">UmbrellaBioAccess</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/category-Web-blueviolet" alt="Web"/>
|
||||
<img src="https://img.shields.io/badge/points-979-critical" alt="979 pts"/>
|
||||
</p>
|
||||
|
||||
Переходим по ссылке и видим перед нами три раздела: `Field Directory`, `Emergency Recovery` и `Partner Access`. Логично предположить, что решение будет состоять из нескольких шагов. Для этого необходим будет эксплуатировать две уязвимости: SQL injection в legacy-поиске и кривой recovery-flow, который позволяет привязать новый passkey к чужому аккаунту, зная только `recovery_code`. Благодаря этому получаем сессию директора и доступ к `BioCore Vault`.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
D(["/directory<br/><i>SQLi UNION</i>"])
|
||||
R(["/recovery<br/><i>bind own passkey</i>"])
|
||||
A(["/access<br/><i>passkey login</i>"])
|
||||
V(["/vault<br/><b>→ flag</b>"])
|
||||
|
||||
D -->|recovery_code| R -->|own passkey linked| A -->|director session| V
|
||||
|
||||
classDef step fill:#e0e7ff,stroke:#6366f1,color:#312e81
|
||||
classDef win fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
|
||||
class D,R,A step
|
||||
class V win
|
||||
```
|
||||
|
||||
## Решение
|
||||
|
||||
Начинаем с `/directory`. Поиск по legacy-справочнику, и прямо там висит подпись `Quote-aware matching enabled.`. Проверяем одинарной кавычкой — параметр поиска улетает внутрь выражения вида `ILIKE '%...%'`, можно попоробовать использовать SQLi. Простая булева инъекция (`OR true`) подтверждает наличие дыры, но к нужным скрытым полям доступа не даст. Идём через `UNION SELECT` и подменяем `displayName` значением `recovery_code`:
|
||||
|
||||
```sql
|
||||
') UNION ALL SELECT codename,recovery_code,division,dossier
|
||||
FROM directory_public_view WHERE role='director' --
|
||||
```
|
||||
|
||||
В ответе появляется запись директора:
|
||||
|
||||
| Поле | Содержимое |
|
||||
|---|---|
|
||||
| `codename` | кодовое имя директора |
|
||||
| `displayName` | 24-символьный hex `recovery_code` |
|
||||
|
||||
Идём в `/recovery`.
|
||||
|
||||
> Здесь не прямо классический [WebAuthn](https://www.w3.org/TR/webauthn-2/), атаку необходимо провести на бизнес-логику восстановления.
|
||||
|
||||
Знание `recovery_code` считается достаточным основанием, чтобы привязать новый passkey к существующему аккаунту. Вводим извлечённый recovery-код, завершаем регистрацию своего passkey, и он оказывается связан с директорским профилем.
|
||||
|
||||
Ну все, мы фактически на финише. На `/access` вводим директорский `codename`, логинимся обычным passkey-флоу уже своим ключом — получаем сессию с ролью `director`. Открываем `/vault` (или напрямую дёргаем `GET /api/vault/biocore`) — сервер отдаёт флаг.
|
||||
|
||||
## Флаг
|
||||
`caplag{read_only_sqli_rebinds_director_passkeys}`
|
||||
Reference in New Issue
Block a user