281 lines
10 KiB
Markdown
281 lines
10 KiB
Markdown
# Adversarial Review: Montana Network Layer
|
||
|
||
**Модель:** Claude Opus 4.5
|
||
**Компания:** Anthropic
|
||
**Дата:** 07.01.2026 16:45 UTC
|
||
|
||
---
|
||
|
||
## Executive Summary
|
||
|
||
Проведён анализ сетевого слоя Montana (`/Montana ACP/montana/src/net/`) на устойчивость к атакам. Проверены 5 критических векторов из шаблона Council.
|
||
|
||
**Общий вердикт:** NEEDS_FIX — обнаружено 2 уязвимости среднего уровня.
|
||
|
||
---
|
||
|
||
## Роль
|
||
|
||
**Атакующий** с неограниченными ресурсами: ботнеты, множество IP-адресов из разных /16 подсетей, неограниченное время.
|
||
|
||
**Цель:** Eclipse жертвы, исчерпание ресурсов, нарушение консенсуса.
|
||
|
||
---
|
||
|
||
## Attack Surface
|
||
|
||
- **External inputs:** TCP соединения, P2P сообщения, адреса от peers
|
||
- **Trust boundaries:** inbound peers (недоверенные), outbound peers (частично доверенные)
|
||
- **Critical assets:** consensus view, address manager state, connection slots
|
||
|
||
---
|
||
|
||
## TIER 0: КРИТИЧЕСКИЕ ВЕКТОРЫ
|
||
|
||
### 1. Eclipse Attack
|
||
|
||
**Файлы:** `addrman.rs`, `eviction.rs`, `connection.rs`
|
||
|
||
#### Проверенные защиты
|
||
|
||
| Механизм | Статус | Код |
|
||
|----------|--------|-----|
|
||
| Netgroup diversity (/16) | PROTECTED | `connection.rs:253-257` |
|
||
| Cryptographic bucketing | PROTECTED | `addrman.rs:445-475` |
|
||
| Self-connection detection | PROTECTED | `protocol.rs:768-772` |
|
||
| Eviction multi-layer | PROTECTED | `eviction.rs:65-126` |
|
||
| Anchor connections | NOT IMPLEMENTED | — |
|
||
|
||
#### Attempted Attacks
|
||
|
||
| # | Attack | Result |
|
||
|---|--------|--------|
|
||
| 1 | Заполнить NEW table вредоносными адресами | MITIGATED — cryptographic bucketing распределяет по source |
|
||
| 2 | Продвинуть в TRIED через fake connections | MITIGATED — требует реальное TCP соединение |
|
||
| 3 | Occupy all outbound slots from same /16 | PROTECTED — MAX_PEERS_PER_NETGROUP = 2 |
|
||
| 4 | Gaming eviction (fake low latency) | PROTECTED — 6-layer protection (28 slots) |
|
||
| 5 | **Post-restart eclipse** | **VULNERABLE** — нет anchor connections |
|
||
|
||
#### Finding: Anchor Connections Missing
|
||
|
||
**Severity:** MEDIUM
|
||
|
||
**Описание:**
|
||
После рестарта узла все outbound соединения выбираются заново из AddrMan. Если атакующий заранее заполнил NEW/TRIED таблицы вредоносными адресами (даже распределёнными по разным /16), после рестарта жертва может подключиться к 8 узлам атакующего.
|
||
|
||
**Эксплуатация:**
|
||
```
|
||
1. Атакующий получает IPs в 8+ разных /16 подсетях
|
||
2. Заполняет AddrMan жертвы через Addr сообщения (1000 addr/msg)
|
||
3. Ждёт рестарт жертвы (обновление, сбой)
|
||
4. Жертва выбирает 8 outbound из отравленного AddrMan
|
||
5. Все 8 outbound → атакующий, eclipse достигнут
|
||
```
|
||
|
||
**Mitigating factors:**
|
||
- Требует 8+ IPs в разных /16 (дорого, но достижимо)
|
||
- Rate limiting на Addr (0.1/sec sustained) замедляет отравление
|
||
- Жертва должна перезапуститься
|
||
|
||
**Рекомендация:**
|
||
Реализовать anchor connections — сохранять 2 последних успешных outbound peers и подключаться к ним первыми после рестарта. Bitcoin Core: `net.cpp:2098-2150`.
|
||
|
||
---
|
||
|
||
### 2. Memory Exhaustion
|
||
|
||
**Файлы:** `protocol.rs`, `sync.rs`, `rate_limit.rs`
|
||
|
||
#### Проверенные защиты
|
||
|
||
| Механизм | Статус | Код |
|
||
|----------|--------|-----|
|
||
| Flow control BEFORE read | PROTECTED | `protocol.rs:647-658` |
|
||
| Early size check (4MB) | PROTECTED | `protocol.rs:1114-1119` |
|
||
| Bounded deserialize | PROTECTED | `protocol.rs:1138-1141` |
|
||
| OrphanPool bounded | PROTECTED | `sync.rs:38` (100 orphans) |
|
||
| BoundedInvSet | PROTECTED | `peer.rs:35-87` (100k items) |
|
||
| AddrMan file limit | PROTECTED | `addrman.rs:29` (16MB) |
|
||
|
||
#### Attempted Attacks
|
||
|
||
| # | Attack | Result |
|
||
|---|--------|--------|
|
||
| 1 | Send msg with length=2^32 | PROTECTED — early check vs MAX_SLICE_SIZE (4MB) |
|
||
| 2 | Flow control bypass | PROTECTED — check BEFORE read_message() |
|
||
| 3 | Orphan slice flooding | PROTECTED — MAX_ORPHANS=100, FIFO eviction |
|
||
| 4 | Known inventory exhaustion | PROTECTED — BoundedInvSet, FIFO eviction |
|
||
| 5 | Malicious bincode length prefix | PROTECTED — bounded deserialize with_limit() |
|
||
|
||
#### Verdict: SAFE
|
||
|
||
Память защищена на всех уровнях. Flow control исправлен после Gemini audit (комментарий в `protocol.rs:635`).
|
||
|
||
---
|
||
|
||
## TIER 1: ВЫСОКИЕ ВЕКТОРЫ
|
||
|
||
### 3. Connection Slot Exhaustion
|
||
|
||
**Файлы:** `connection.rs`, `eviction.rs`
|
||
|
||
#### Attempted Attacks
|
||
|
||
| # | Attack | Result |
|
||
|---|--------|--------|
|
||
| 1 | Occupy all 117 inbound slots | PARTIAL — eviction может освободить |
|
||
| 2 | Gaming eviction via fake metrics | PROTECTED — 6-layer, 28 protected slots |
|
||
| 3 | Rapid connect/disconnect flooding | **POTENTIAL** — нет per-IP rate limit |
|
||
|
||
#### Finding: Connection Rate Limiting Per-IP
|
||
|
||
**Severity:** LOW
|
||
|
||
**Описание:**
|
||
Нет явного rate limiting на новые TCP соединения от одного IP. Атакующий может быстро открывать и закрывать соединения, создавая нагрузку на listener loop.
|
||
|
||
**Mitigating factors:**
|
||
- Exponential backoff в `connection.rs:139-173` работает только для outbound
|
||
- TCP handshake сам по себе ограничивает скорость
|
||
- OS-level connection limits
|
||
|
||
**Рекомендация:**
|
||
Добавить per-IP connection rate limit в listener_loop: max 5 connections per IP per minute.
|
||
|
||
---
|
||
|
||
### 4. Sync DoS
|
||
|
||
**Файлы:** `sync.rs`, `bootstrap.rs`, `protocol.rs`
|
||
|
||
#### Attempted Attacks
|
||
|
||
| # | Attack | Result |
|
||
|---|--------|--------|
|
||
| 1 | GetSlices amplification | PROTECTED — `count.min(500)` в `protocol.rs:1036` |
|
||
| 2 | GetData abuse | PROTECTED — rate_limits.getdata (1000 burst, 5/sec) |
|
||
| 3 | **Headers flooding** | **POTENTIAL** — нет rate limit на SliceHeaders |
|
||
|
||
#### Finding: Headers Rate Limiting
|
||
|
||
**Severity:** MEDIUM
|
||
|
||
**Описание:**
|
||
Нет явного rate limit на получение SliceHeaders сообщений. Атакующий может слать большие headers responses, вызывая CPU exhaustion на валидации.
|
||
|
||
**Проверка в коде:**
|
||
- `Message::SliceHeaders` не имеет rate limiter в `PeerRateLimits`
|
||
- MAX_HEADERS_SIZE = 512KB (2000 headers × 256 bytes)
|
||
- Обработка headers требует валидации каждого
|
||
|
||
**Эксплуатация:**
|
||
```
|
||
1. Подключиться к жертве
|
||
2. Слать GetHeaders запросы
|
||
3. Отвечать 2000 headers каждый раз
|
||
4. Жертва тратит CPU на валидацию
|
||
5. Повторить с множества соединений
|
||
```
|
||
|
||
**Рекомендация:**
|
||
Добавить HeadersRateLimiter в PeerRateLimits: 5000 headers burst, 10/sec sustained.
|
||
|
||
---
|
||
|
||
### 5. Rate Limit Bypass
|
||
|
||
**Файл:** `rate_limit.rs`
|
||
|
||
#### Attempted Attacks
|
||
|
||
| # | Attack | Result |
|
||
|---|--------|--------|
|
||
| 1 | Multiple connections bypass | CONFIRMED — rate limits per-connection |
|
||
| 2 | Token bucket timing | SAFE — refill() calls Instant::now() |
|
||
| 3 | Message type gaps | PARTIAL — Headers/Presence not rate limited |
|
||
|
||
#### Finding: Per-Connection vs Per-IP
|
||
|
||
**Severity:** LOW
|
||
|
||
**Описание:**
|
||
Rate limits в `PeerRateLimits` применяются per-connection. Атакующий с 10 соединениями получает 10× burst capacity.
|
||
|
||
**Пример:**
|
||
- Addr: 1000 burst per connection
|
||
- 10 connections = 10,000 addr burst
|
||
- Это ускоряет AddrMan poisoning
|
||
|
||
**Mitigating factors:**
|
||
- MAX_INBOUND = 117 ограничивает масштаб
|
||
- Netgroup diversity (/16) ограничивает connections per attacker
|
||
|
||
**Рекомендация:**
|
||
Рассмотреть глобальный per-IP rate tracker для критических message types.
|
||
|
||
---
|
||
|
||
## Checklist Results
|
||
|
||
```
|
||
[x] Eclipse: netgroup diversity работает
|
||
[ ] Eclipse: anchor connections есть ← MISSING
|
||
[x] Memory: flow control до allocation
|
||
[x] Memory: orphan pool bounded
|
||
[x] Memory: все collections bounded
|
||
[x] Slots: eviction защищает diversity
|
||
[ ] Sync: headers rate limited ← MISSING
|
||
[x] Sync: GetSlices rate limited
|
||
[ ] Rate: все messages covered ← PARTIAL
|
||
[x] Rate: per-IP limiting (partial via netgroup)
|
||
```
|
||
|
||
---
|
||
|
||
## Summary of Findings
|
||
|
||
| # | Finding | Severity | Status |
|
||
|---|---------|----------|--------|
|
||
| 1 | Missing anchor connections | MEDIUM | NEEDS_FIX |
|
||
| 2 | Headers not rate limited | MEDIUM | NEEDS_FIX |
|
||
| 3 | Connection rate per IP | LOW | CONSIDER |
|
||
| 4 | Per-connection vs per-IP rate | LOW | CONSIDER |
|
||
|
||
---
|
||
|
||
## Positive Observations
|
||
|
||
1. **Flow control**: Исправлен после Gemini audit, теперь блокирует read ПЕРЕД allocation
|
||
2. **Bounded collections**: Все структуры данных имеют лимиты с FIFO eviction
|
||
3. **Eviction system**: 6-layer protection делает gaming очень сложным
|
||
4. **Cryptographic bucketing**: SipHash24 с секретным ключом предотвращает bucket prediction
|
||
5. **Self-connection detection**: Nonce-based detection работает корректно
|
||
6. **Bounded deserialize**: bincode with_limit() везде где нужно
|
||
|
||
---
|
||
|
||
## Verdict
|
||
|
||
```
|
||
[ ] SAFE — можно продолжать
|
||
[x] NEEDS_FIX — исправить перед продолжением
|
||
|
||
Critical: 0
|
||
High: 0
|
||
Medium: 2 (anchor connections, headers rate limit)
|
||
Low: 2 (connection rate, per-IP rate)
|
||
```
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
- Bitcoin Core anchor connections: `net.cpp:2098-2150`
|
||
- Bitcoin Core headers rate limit: `net_processing.cpp:HEADERS_DOWNLOAD_TIMEOUT_BASE`
|
||
- Erebus attack paper: https://erebus-attack.comp.nus.edu.sg/
|
||
|
||
---
|
||
|
||
*Report generated by Claude Opus 4.5 (Anthropic)*
|
||
*Security Council Review — Montana ACP*
|