montana/Русский/Совет/Cursor/атака_затмения_07.01.2026_21:09.md

418 lines
20 KiB
Markdown
Raw Normal View History

# Отчет об анализе уязвимостей Eclipse Attack — Montana Network
**Модель:** Composer 1
**Компания:** Cursor
**Дата:** 07.01.2026 21:09 UTC
---
## Резюме
Проведен глубокий анализ сетевого слоя Montana на предмет уязвимостей Eclipse Attack. Обнаружены **5 критических уязвимостей**, которые позволяют злоумышленнику изолировать узел жертвы и контролировать все его исходящие соединения.
**Критичность:** 🔴 **КРИТИЧЕСКАЯ**
---
## Обнаруженные уязвимости
### 1. 🔴 КРИТИЧЕСКАЯ: Startup Verification не выполняется
**Файл:** `Montana ACP/montana/src/net/startup.rs`
**Проблема:**
Функция `query_hardcoded_tips()` в `startup.rs` является заглушкой и возвращает пустой вектор без выполнения реальных запросов:
```165:179:Montana ACP/montana/src/net/startup.rs
/// Query hardcoded nodes for their chain tips
async fn query_hardcoded_tips(&self, addrs: &[SocketAddr]) -> Vec<PeerChainInfo> {
// This is a simplified implementation
// Real implementation would:
// 1. Connect to each hardcoded node
// 2. Complete handshake
// 3. Get their best slice height
// 4. Disconnect
// For now, return empty - actual network queries would be done
// by the Network module when it starts
info!("Querying {} hardcoded nodes for chain tips", addrs.len());
// Placeholder: in production, this would make actual network requests
// The Network module handles this during start()
Vec::new()
}
```
**Эксплуатация:**
1. Узел запускается и вызывает `verification_type()`, который возвращает строку "full_bootstrap"
2. В `main.rs` верификация только логируется, но не выполняется и не блокирует запуск:
```84:90:Montana ACP/montana/src/main.rs
let verify_type = verification_type(&storage);
let chain_age = storage.chain_age_secs().unwrap_or(u64::MAX);
let head = storage.head().unwrap_or(0);
info!("Startup verification: {} (chain_age={} secs, height={})",
verify_type, chain_age, head);
info!("Full bootstrap: 100 peers, 25+ subnets required");
```
3. Сеть запускается без реальной верификации
4. AddrMan загружается из `addresses.dat` без проверки консенсуса
5. Все исходящие соединения идут к адресам из AddrMan, которые могут быть скомпрометированы
**Последствия:**
- Полный обход защиты от Eclipse Attack
- Узел не проверяет консенсус при запуске
- Атакующий может заполнить `addresses.dat` вредоносными адресами заранее
**Рекомендации:**
1. Реализовать реальные сетевые запросы в `query_hardcoded_tips()`
2. Вызвать `StartupVerifier::verify()` в `main.rs` и заблокировать запуск при неудаче
3. Добавить проверку результата верификации перед запуском сети
---
### 2. 🔴 КРИТИЧЕСКАЯ: AddrMan можно заполнить через Addr сообщения без проверки разнообразия
**Файл:** `Montana ACP/montana/src/net/protocol.rs`
**Проблема:**
При обработке `Addr` сообщений нет проверки разнообразия подсетей. Атакующий может отправить множество адресов из одной подсети:
```984:1000:Montana ACP/montana/src/net/protocol.rs
Message::Addr(addrs) => {
if addrs.len() > MAX_ADDR_SIZE {
return Err(NetError::Protocol("Too many addresses".into()));
}
// Rate limit: process only allowed addresses
let allowed = peer.rate_limits.addr.process(addrs.len());
if allowed == 0 {
debug!("Rate limited addr from {}", peer.addr);
return Ok(false);
}
// Only process up to allowed count
let to_process: Vec<_> = addrs.into_iter().take(allowed).collect();
let added = addresses.write().await.add_many(to_process, peer.addr);
debug!("Added {} addresses from {} (rate limited to {})", added, peer.addr, allowed);
}
```
**Эксплуатация:**
1. Атакующий подключается к жертве (inbound или outbound)
2. Отправляет `Addr` сообщения с адресами из контролируемых подсетей
3. Адреса добавляются в NEW table AddrMan без проверки разнообразия
4. При следующем рестарте (если верификация обойдена), все исходящие соединения идут к атакующему
**Последствия:**
- Заполнение AddrMan вредоносными адресами
- При рестарте узел подключается только к атакующему
- Rate limiting не защищает от постепенного заполнения
**Рекомендации:**
1. Добавить проверку разнообразия подсетей при добавлении адресов
2. Ограничить количество адресов из одной подсети от одного источника
3. Проверять разнообразие подсетей в AddrMan перед выбором пиров
---
### 3. 🔴 КРИТИЧЕСКАЯ: Netgroup diversity работает только для outbound соединений
**Файл:** `Montana ACP/montana/src/net/connection.rs`
**Проблема:**
Проверка `can_connect()` ограничивает только исходящие соединения. Для входящих соединений проверка выполняется, но атакующий может подключиться через inbound и заполнить AddrMan:
```271:277:Montana ACP/montana/src/net/connection.rs
/// Check if we can connect to this address (netgroup diversity)
pub async fn can_connect(&self, addr: &SocketAddr) -> bool {
let netgroup = get_netgroup(addr);
let counts = self.netgroup_counts.lock().await;
let current = counts.get(&netgroup).copied().unwrap_or(0);
current < MAX_PEERS_PER_NETGROUP
}
```
**Эксплуатация:**
1. Атакующий подключается через inbound (до 117 соединений)
2. Каждое соединение может быть из разных IP, но из одной подсети (до 2 соединений на подсеть)
3. Атакующий отправляет `Addr` сообщения с адресами из контролируемых подсетей
4. AddrMan заполняется вредоносными адресами
5. При рестарте все outbound соединения идут к атакующему
**Последствия:**
- Inbound соединения могут заполнить AddrMan без ограничений по разнообразию
- Атакующий может использовать множество IP из одной подсети для обхода ограничений
**Рекомендации:**
1. Применить проверку разнообразия подсетей также для адресов, полученных через inbound соединения
2. Ограничить количество адресов из одной подсети в AddrMan
3. Проверять разнообразие подсетей при добавлении адресов в AddrMan
---
### 4. 🟠 ВЫСОКАЯ: Bucket collision в TRIED table может быть использована для атаки
**Файл:** `Montana ACP/montana/src/net/addrman.rs`
**Проблема:**
При коллизии в TRIED table существующий адрес перемещается обратно в NEW table. Это может быть использовано для вытеснения легитимных адресов:
```210:222:Montana ACP/montana/src/net/addrman.rs
// Add to tried
let bucket = self.get_tried_bucket(addr);
let pos = self.get_bucket_position(addr, bucket, false);
let idx = bucket * BUCKET_SIZE + pos;
// Handle collision
if let Some(existing_idx) = self.tried_table[idx] {
// Move existing back to new
self.move_to_new(existing_idx);
}
self.tried_table[idx] = Some(addr_idx);
self.tried_count += 1;
}
```
**Эксплуатация:**
1. Атакующий вычисляет bucket для легитимного адреса в TRIED table
2. Создает адрес, который попадает в тот же bucket и позицию
3. Устанавливает успешное соединение с этим адресом
4. Легитимный адрес вытесняется из TRIED в NEW
5. При следующем выборе пира вероятность выбрать легитимный адрес снижается
**Последствия:**
- Вытеснение легитимных адресов из TRIED table
- Снижение разнообразия подсетей в TRIED table
- Увеличение вероятности выбора вредоносных адресов
**Рекомендации:**
1. При коллизии в TRIED table не перемещать существующий адрес, а отклонить новый
2. Или использовать более сложную стратегию вытеснения (например, на основе возраста адреса)
3. Добавить проверку разнообразия подсетей при перемещении в TRIED
---
### 5. 🟠 ВЫСОКАЯ: Отсутствие проверки разнообразия подсетей при выборе пиров из AddrMan
**Файл:** `Montana ACP/montana/src/net/addrman.rs`
**Проблема:**
Метод `select()` выбирает адреса случайным образом без проверки разнообразия подсетей:
```233:258:Montana ACP/montana/src/net/addrman.rs
/// Select an address to connect to (50/50 new vs tried)
pub fn select(&mut self) -> Option<NetAddress> {
self.select_inner(false)
}
/// Select an address to connect to with option for new only
pub fn select_with_option(&mut self, new_only: bool) -> Option<NetAddress> {
self.select_inner(new_only)
}
fn select_inner(&mut self, new_only: bool) -> Option<NetAddress> {
let mut rng = ChaCha20Rng::from_entropy();
// 50% chance to try new address (or 100% if new_only)
let use_new = new_only || rng.gen_bool(0.5);
if use_new && self.new_count > 0 {
self.select_from_new(&mut rng)
} else if self.tried_count > 0 {
self.select_from_tried(&mut rng)
} else if self.new_count > 0 {
self.select_from_new(&mut rng)
} else {
None
}
}
```
**Эксплуатация:**
1. Атакующий заполняет AddrMan адресами из ограниченного набора подсетей
2. При выборе пиров `select()` может выбрать несколько адресов из одной подсети подряд
3. `can_connect()` блокирует только после установления соединения
4. Атакующий может контролировать большинство исходящих соединений
**Последствия:**
- Неравномерное распределение соединений по подсетям
- Возможность контроля большинства исходящих соединений при заполнении AddrMan
**Рекомендации:**
1. Добавить проверку разнообразия подсетей в `select()` перед возвратом адреса
2. Отслеживать уже выбранные подсети в текущем цикле выбора
3. Приоритизировать адреса из новых подсетей
---
## Общий вектор атаки
### Сценарий успешной Eclipse Attack:
1. **Подготовка:**
- Атакующий получает доступ к `addresses.dat` жертвы (через malware, компрометацию сервера, или заполнение через Addr сообщения)
- Заполняет NEW table адресами из контролируемых подсетей (1024 buckets × 64 entries = до 65,536 адресов)
2. **Заполнение AddrMan:**
- Подключается к жертве через inbound соединения
- Отправляет `Addr` сообщения с адресами из контролируемых подсетей
- Адреса добавляются в NEW table без проверки разнообразия
3. **Продвижение в TRIED:**
- Устанавливает успешные соединения с вредоносными адресами
- Адреса перемещаются в TRIED table через `mark_connected()`
- Легитимные адреса могут быть вытеснены через bucket collision
4. **Рестарт жертвы:**
- Startup verification не выполняется (уязвимость #1)
- AddrMan загружается из `addresses.dat` с вредоносными адресами
- Все исходящие соединения идут к атакующему
5. **Изоляция:**
- Жертва изолирована от легитимной сети
- Атакующий контролирует всю информацию, получаемую жертвой
- Возможны атаки на консенсус, двойное расходование и т.д.
---
## Защитные механизмы и их обход
### Защита: Full Bootstrap Verification
**Статус:** ❌ **НЕ РАБОТАЕТ**
- Код существует, но не выполняется при запуске
- `query_hardcoded_tips()` возвращает пустой вектор
- Верификация не блокирует запуск сети
### Защита: Netgroup Diversity (MAX_PEERS_PER_NETGROUP=2)
**Статус:** ⚠️ **ЧАСТИЧНО РАБОТАЕТ**
- Работает только для outbound соединений
- Не защищает от заполнения AddrMan через inbound
- Не проверяется при добавлении адресов в AddrMan
### Защита: Rate Limiting на Addr сообщения
**Статус:** ⚠️ **НЕДОСТАТОЧНО**
- Ограничивает количество адресов за раз
- Не защищает от постепенного заполнения
- Не проверяет разнообразие подсетей
### Защита: Bucket System в AddrMan
**Статус:** ⚠️ **СЛАБАЯ**
- Предотвращает предсказуемое размещение адресов
- Но не защищает от заполнения всех buckets вредоносными адресами
- Collision handling может быть использован для вытеснения легитимных адресов
---
## Рекомендации по исправлению
### Приоритет 1 (Критический):
1. **Реализовать реальную startup verification:**
- Выполнять реальные сетевые запросы к hardcoded nodes
- Блокировать запуск сети при неудаче верификации
- Проверять консенсус перед загрузкой AddrMan
2. **Добавить проверку разнообразия подсетей в AddrMan:**
- Ограничить количество адресов из одной подсети
- Проверять разнообразие при добавлении адресов
- Приоритизировать адреса из новых подсетей при выборе
### Приоритет 2 (Высокий):
3. **Улучшить bucket collision handling:**
- Не перемещать существующие адреса из TRIED при коллизии
- Использовать более сложную стратегию вытеснения
4. **Добавить проверку разнообразия в select():**
- Отслеживать уже выбранные подсети
- Приоритизировать адреса из новых подсетей
### Приоритет 3 (Средний):
5. **Усилить rate limiting:**
- Добавить проверку разнообразия подсетей в rate limiter
- Ограничить количество адресов из одной подсети от одного источника
6. **Добавить мониторинг:**
- Логировать предупреждения при низком разнообразии подсетей
- Алерты при подозрительных паттернах заполнения AddrMan
---
## Заключение
Сетевой слой Montana содержит **критические уязвимости**, которые позволяют злоумышленнику выполнить успешную Eclipse Attack. Основная проблема заключается в том, что **startup verification не выполняется**, что полностью обходит защиту от Eclipse Attack.
Дополнительные уязвимости позволяют заполнить AddrMan вредоносными адресами и контролировать все исходящие соединения жертвы.
**Рекомендуется немедленное исправление всех обнаруженных уязвимостей.**
---
## Приложение: Код уязвимостей
### Уязвимость #1: Startup Verification не выполняется
```rust
// Montana ACP/montana/src/net/startup.rs:165-179
async fn query_hardcoded_tips(&self, addrs: &[SocketAddr]) -> Vec<PeerChainInfo> {
// Placeholder: in production, this would make actual network requests
Vec::new() // ❌ Возвращает пустой вектор
}
```
### Уязвимость #2: AddrMan заполняется без проверки разнообразия
```rust
// Montana ACP/montana/src/net/protocol.rs:998
let added = addresses.write().await.add_many(to_process, peer.addr);
// ❌ Нет проверки разнообразия подсетей
```
### Уязвимость #3: Netgroup diversity только для outbound
```rust
// Montana ACP/montana/src/net/connection.rs:272-277
pub async fn can_connect(&self, addr: &SocketAddr) -> bool {
// ⚠️ Проверяется только при outbound соединениях
// ❌ Не защищает от заполнения AddrMan через inbound
}
```
---
**Конец отчета**