montana/Русский/Совет/Google/критическое_затмение_07.01.2026_14:55.md

13 KiB
Raw Blame History

Модель: 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)

  1. Подготовка: Атакующий использует ботнет (50+ IP в разных подсетях /16).
  2. Flooding: Атакующий отправляет Addr сообщения жертве, чтобы заполнить "New" таблицы в AddrMan вредоносными адресами.
  3. Триггер: Узел жертвы перезапускается (или принудительно перезагружается через DoS).
  4. Исполнение:
    • Жертва запускается.
    • Bypass: Проверка StartupVerifier пропускается.
    • Network начинает подключения.
    • AddrMan выбирает IP атакующего из заполненных бакетов.
    • Жертва подключается к узлам атакующего.
    • Так как проверка "Hardcoded Node Consensus" пропущена, жертва принимает изолированную версию цепи от атакующего.
  5. Влияние: Двойная трата, цензура, кража средств.

4. Рекомендации (Remediation)

  1. Реализовать query_hardcoded_tips: Заменить заглушку в src/net/startup.rs на реальные сетевые запросы (подключение, рукопожатие, получение заголовков, отключение).
  2. Принудительная верификация: В src/main.rs вызвать StartupVerifier::verify() перед запуском основного сетевого цикла, или внутри Network::start перед разрешением общих подключений.
  3. 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) выполняет:

  1. TCP connect с таймаутом
  2. AuthChallenge (криптографический вызов)
  3. AuthResponse с ML-DSA-65 подписью
  4. Верификацию подписи против hardcoded pubkey
  5. Version/Verack handshake
  6. 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