13 KiB
Модель: Gemini 3 Pro Компания: Google Дата: 07.01.2026 14:55 UTC
CRITICAL SECURITY REPORT: Eclipse Protection Bypass
1. Резюме (Summary)
Заявленная защита от Eclipse Attack в сети Montana полностью неактивна. Несмотря на утверждения в документации и комментариях о том, что "Full Bootstrap Verification" выполняется при каждом запуске, код, отвечающий за эту проверку (StartupVerifier), никогда не вызывается в точке входа приложения (main.rs) или в сетевом контроллере (Network::start).
Дополнительно, сама логика верификации содержит "заглушку" (stub), которая привела бы к невозможности запуска узла, если бы она была вызвана.
2. Детали уязвимости (Vulnerability Details)
A. Отсутствие вызова защиты (Critical)
Файлы: src/main.rs, src/net/protocol.rs
Файл main.rs инициализирует узел и сеть, логируя информацию о типе верификации ("Startup verification: full_bootstrap"). Однако затем он немедленно запускает сеть без вызова StartupVerifier::verify().
В src/net/protocol.rs, метод connection_loop содержит обширные комментарии, описывающие "Phase 1: Startup Verification". Однако код немедленно переходит к логике "Phase 2: Peer Selection", пропуская первую фазу.
Код (src/main.rs):
// Информация о верификации логируется...
info!("Startup verification: {} ...", verify_type);
// ...но сеть запускается сразу, без проверки
let (network, event_rx) = Network::new(net_config).await?;
network.start().await?; // Начинает подключения немедленно
B. Реализация-заглушка (High)
Файл: src/net/startup.rs
Даже если бы StartupVerifier был вызван, метод query_hardcoded_tips является заглушкой, возвращающей пустой список.
async fn query_hardcoded_tips(&self, addrs: &[SocketAddr]) -> Vec<PeerChainInfo> {
// ...
// Placeholder: in production, this would make actual network requests
Vec::new() // Возвращает пустой вектор
}
Так как логика требует MIN_HARDCODED_RESPONSES (15), проверка responses.len() < MIN_HARDCODED_RESPONSES всегда будет провалена, возвращая ошибку StartupError::InsufficientHardcoded.
3. Вектор атаки (Eclipse)
- Подготовка: Атакующий использует ботнет (50+ IP в разных подсетях /16).
- Flooding: Атакующий отправляет
Addrсообщения жертве, чтобы заполнить "New" таблицы вAddrManвредоносными адресами. - Триггер: Узел жертвы перезапускается (или принудительно перезагружается через DoS).
- Исполнение:
- Жертва запускается.
- Bypass: Проверка
StartupVerifierпропускается. Networkначинает подключения.AddrManвыбирает IP атакующего из заполненных бакетов.- Жертва подключается к узлам атакующего.
- Так как проверка "Hardcoded Node Consensus" пропущена, жертва принимает изолированную версию цепи от атакующего.
- Влияние: Двойная трата, цензура, кража средств.
4. Рекомендации (Remediation)
- Реализовать
query_hardcoded_tips: Заменить заглушку вsrc/net/startup.rsна реальные сетевые запросы (подключение, рукопожатие, получение заголовков, отключение). - Принудительная верификация: В
src/main.rsвызватьStartupVerifier::verify()перед запуском основного сетевого цикла, или внутриNetwork::startперед разрешением общих подключений. - Fail-Safe: Гарантировать, что узел откажется работать, если верификация не пройдена.
ОПРОВЕРЖЕНИЕ: Claude Opus 4.5 (Adversarial Mode)
Дата: 07.01.2026 15:30 UTC Модель: Claude Opus 4.5 Компания: Anthropic
Вердикт: ОТЧЁТ GEMINI ОШИБОЧЕН
Gemini 3 Pro допустил критическую ошибку в анализе кодовой базы. Он читал устаревший/неиспользуемый файл (startup.rs) вместо реально вызываемого кода (verification.rs).
Детальное опровержение
Ошибка 1: "StartupVerifier не вызывается"
Утверждение Gemini: Код логирует информацию о верификации, но сеть запускается сразу.
Факт: main.rs:124-167 содержит BLOCKING вызов верификации:
// main.rs:123-167
} else {
// Run bootstrap verification (BLOCKING)
info!("Running bootstrap verification...");
info!("Requirements: 100 peers, 25+ /16 subnets, hardcoded consensus");
let verifier = VerificationClient::new(testnet, port, genesis.clone());
match verifier.verify().await { // <-- BLOCKING CALL
Ok(result) => {
info!("Bootstrap verification PASSED");
// ...success handling
}
Err(e) => {
error!("CRITICAL: Bootstrap verification FAILED");
return Err(format!("Bootstrap verification failed: {}", e).into());
// ^^^^ NODE STARTUP ABORTED
}
}
}
// Network starts ONLY AFTER verification passes:
let (network, event_rx) = Network::new(net_config).await?; // Line 185
network.start().await?; // Line 186
Код Network::new() вызывается на строке 185, ПОСЛЕ завершения verifier.verify().await.
Ошибка 2: "query_hardcoded_tips — заглушка"
Утверждение Gemini: Метод query_hardcoded_tips в startup.rs возвращает пустой вектор.
Факт: main.rs использует VerificationClient, а не StartupVerifier.
VerificationClient находится в verification.rs и имеет полную реализацию с реальными сетевыми запросами:
// verification.rs:344-403 — РЕАЛЬНАЯ реализация
async fn query_hardcoded_nodes(
&self,
addrs: &[SocketAddr],
) -> (Vec<PeerChainInfo>, Vec<SocketAddr>) {
let responses = Arc::new(Mutex::new(Vec::new()));
let discovered = Arc::new(Mutex::new(HashSet::new()));
let mut handles = Vec::new();
for addr in addrs {
let handle = tokio::spawn(async move {
let _permit = sem.acquire().await.ok()?;
// РЕАЛЬНЫЙ сетевой запрос:
match query_single_node(addr, listen_port, true, testnet).await {
Ok((info, peer_addrs)) => {
responses.lock().await.push(info);
// ...
}
Err(e) => { /* error handling */ }
}
});
handles.push(handle);
}
// Wait for ALL queries to complete
for handle in handles {
let _ = handle.await;
}
// Return collected responses
(responses, discovered)
}
Функция query_single_node() (verification.rs:507-711) выполняет:
- TCP connect с таймаутом
- AuthChallenge (криптографический вызов)
- AuthResponse с ML-DSA-65 подписью
- Верификацию подписи против hardcoded pubkey
- Version/Verack handshake
- GetAddr для обнаружения P2P пиров
Ошибка 3: "Network начинает подключения немедленно"
Факт: Последовательность в main.rs:
1. verifier.verify().await — BLOCKING, может занять 30+ секунд
2. Network::new() — только если verify() вернул Ok
3. Network::start() — только после new()
Если verify() возвращает Err, узел завершается с ошибкой (main.rs:163-164):
return Err(format!("Bootstrap verification failed: {}", e).into());
Причина ошибки Gemini
Gemini читал файл startup.rs, который содержит альтернативную/старую реализацию StartupVerifier. Но main.rs импортирует и использует VerificationClient из verification.rs:
// main.rs:16-18
use crate::net::{
NetConfig, NetEvent, Network, VerificationClient, NODE_FULL, NODE_PRESENCE,
verification_type,
};
Gemini не проследил цепочку импортов и проанализировал неправильный файл.
Реальный Adversarial Review: Eclipse Attack на Montana
Attack Surface
| Input | Trust Level | Protection |
|---|---|---|
| Hardcoded nodes | Cryptographically verified (ML-DSA-65) | Challenge-response auth |
| P2P peers | Consensus-verified | 100 peers, 25+ subnets |
| AddrMan (peers.dat) | Untrusted candidates | Cryptographic bucketing |
| System clock | Local | Verified vs network median |
Attempted Attacks
| # | Attack Vector | Result |
|---|---|---|
| 1 | BGP/ISP MITM on hardcoded nodes | PROTECTED — ML-DSA-65 signature verification (verification.rs:557-559) |
| 2 | Sybil flood into AddrMan | PROTECTED — Startup verification ignores peers.dat, queries live network |
| 3 | DDoS hardcoded nodes | PROTECTED — Requires 75% failure; node refuses to start otherwise (verification.rs:213-230) |
| 4 | Clock manipulation | PROTECTED — Median time from 100 peers, >10min divergence = abort (bootstrap.rs:283-346) |
| 5 | Runtime connection takeover | PROTECTED — Netgroup limits (2 per /16), eviction diversity (28 protected peers) |
| 6 | ADDR message poisoning | PROTECTED — Rate limiting (0.1/sec), cryptographic bucket assignment |
Critical Protection Chain
+-------------------------------------------------------------+
| Node Startup |
+-------------------------------------------------------------+
| 1. VerificationClient::verify() [BLOCKING] |
| +-- query_hardcoded_nodes() [ML-DSA-65 auth] |
| +-- query_p2p_peers() [100 peers target] |
| +-- verify_subnet_diversity() [25+ /16 required] |
| +-- verify_network_time() [median consensus] |
| +-- verify_hardcoded_consensus() [+/-1% agreement] |
| |
| 2. IF verify() fails -> ABORT (node does not start) |
| |
| 3. Network::new() + Network::start() [only on success] |
+-------------------------------------------------------------+
Findings
| Severity | Finding | Status |
|---|---|---|
| CRITICAL | None | - |
| HIGH | None | - |
| MEDIUM | Single hardcoded node (current testnet) | Known limitation, planned expansion |
| LOW | startup.rs contains stale code | Should be removed to prevent confusion |
Verdict
[X] GEMINI REPORT INVALID — Analysis based on wrong file
[X] MONTANA ECLIPSE PROTECTION VERIFIED — Full implementation exists and is called
Montana's eclipse resistance is correctly implemented in verification.rs:
- Cryptographic hardcoded node authentication (ML-DSA-65)
- 100 peer queries with 25+ /16 subnet diversity
- Blocking verification before network start
- Node refuses to run if verification fails
Recommendation: Remove or clearly deprecate startup.rs to prevent future analysis confusion.
Reviewed by: Claude Opus 4.5 (Adversarial Mode) Date: 2026-01-07 15:30 UTC