montana/Русский/Совет/Anthropic/враждебный_аудит_сети_08.01.2026_12:00.md

20 KiB
Raw Permalink Blame History

Security Audit: Montana Network Layer — Adversarial Analysis

Модель: Claude Opus 4.5 Компания: Anthropic Дата: 08.01.2026 12:00 UTC Scope: montana/src/net/ (21 файлов, ~12,000 LOC Rust)


1. Понимание архитектуры

ACP vs Traditional Consensus

Montana использует Atemporal Coordinate Presence (ACP) — модель консенсуса, основанную на:

  1. Физическая упорядоченность (Layer -1) — фундаментальное ограничение энтропии, требующее реального времени для накопления присутствия. Нельзя ускорить.

  2. Слайсы вместо блоков — каждый слайс представляет фиксированный интервал времени (τ₂ = 5 минут), а не произвольный набор транзакций.

  3. Presence Proofs — узлы подтверждают своё присутствие в момент времени τ₂, накапливая вес.

  4. Fork Choice через Cumulative Weight — не PoW/PoS, а сумма весов presence proofs за всё время существования цепи.

Отличия от традиционных систем

Аспект Bitcoin/Ethereum Montana
Единица консенсуса Блок Слайс (τ₂ = 5 min)
Право на создание Mining/Staking Любой узел с presence
Fork resolution Longest chain / Finality Cumulative weight
Time model Block timestamps Physically derived coordinate time
Sybil resistance PoW/PoS Presence age + subnet diversity

Следствия для безопасности

  1. Атаки на майнинг не применимы — нет mining power
  2. Nothing-at-stake не применим — нет staking
  3. Критична синхронизация времени — физические инварианты привязывают к реальному времени
  4. Bootstrap особенно критичен — начальный вектор состояния определяет всё

2. Изученные файлы

Файл LOC Ключевые компоненты
mod.rs ~50 Module exports
types.rs ~200 Constants, NetAddress, InvItem
message.rs ~300 Wire protocol messages
peer.rs ~250 Peer state, rate limits
connection.rs ~510 Connection manager, bans, netgroup
addrman.rs ~740 Cryptographic bucket system
rate_limit.rs ~150 Token bucket rate limiting
eviction.rs ~200 Peer eviction strategy
discouraged.rs ~180 Bloom filter for misbehavior
startup.rs ~300 Bootstrap orchestration
bootstrap.rs ~400 Chain verification protocol
verification.rs ~850 Bootstrap verification client
hardcoded_identity.rs ~205 ML-DSA-65 hardcoded nodes
noise.rs ~895 Hybrid Noise XX + ML-KEM-768
encrypted.rs ~435 Encrypted stream wrapper
subnet.rs ~390 Subnet reputation tracking
feeler.rs ~260 Feeler connections, addr cache
sync.rs ~670 Headers-first sync
protocol.rs ~1650 Main network protocol
inventory.rs ~595 Relay cache, LRU eviction
dns.rs ~270 DNS seeds, fallback IPs

Всего: ~8,500 LOC анализированного кода


3. Attack Surface

External Inputs (Точки входа для атакующего)

Категория Источник Trust Level
TCP connections Any IP Untrusted
Noise handshake Post-TCP Transport-secure
P2P messages Post-handshake Partially trusted
Addr gossip Any peer Untrusted
DNS seeds Hardcoded domains Semi-trusted
Hardcoded nodes Embedded in binary Trusted
Bootstrap data Network consensus Verified

Trust Boundaries

Internet → TCP → Noise Handshake → Montana Protocol → Consensus
          ↑        ↑                  ↑                ↑
         DoS    Crypto attacks    Protocol abuse    Fork manipulation

Critical Assets (Что защищаем)

  1. Consensus state — cumulative_weight, canonical chain
  2. Private keys — Noise keypair, wallet keys
  3. Peer set — защита от eclipse
  4. Network connectivity — защита от DoS

4. Найденные уязвимости

[CRITICAL] V-001: Single Point of Failure — One Hardcoded Node

Файл: hardcoded_identity.rs:59-68

Уязвимый код:

pub static MAINNET_HARDCODED: LazyLock<Vec<HardcodedNode>> = LazyLock::new(|| {
    vec![HardcodedNode {
        addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(176, 124, 208, 93)), 19333),
        pubkey: TIMEWEB_MOSCOW_PUBKEY,
        name: "timeweb-moscow-1",
        region: "eu-east",
    }]
});

Вектор атаки:

  1. Атакующий получает контроль над сервером 176.124.208.93 (TimeWeb Moscow)
  2. Bootstrap verification (verification.rs:140) требует ответа от hardcoded nodes
  3. С одним узлом атакующий контролирует 100% hardcoded ответов
  4. Атакующий может поставить любой cumulative_weight и head_hash
  5. Все новые узлы синхронизируются с поддельной цепью

Импакт: Полный контроль над консенсусом всех новых узлов

Сложность:

  • Компрометация одного VPS (~$1000-10000 через социальную инженерию или уязвимость хостинга)
  • Или DDoS на один IP для отказа в обслуживании bootstrap

PoC сценарий:

# Вариант 1: Compromise
ssh root@176.124.208.93  # После компрометации
systemctl stop montana
./fake-bootstrap-server --cumulative-weight 999999999

# Вариант 2: DDoS
hping3 -S --flood -p 19333 176.124.208.93
# Все новые узлы не могут пройти bootstrap

[CRITICAL] V-002: Unencrypted Private Key Storage

Файл: encrypted.rs:274-316

Уязвимый код:

pub fn load_or_generate_keypair(data_dir: &Path) -> io::Result<StaticKeypair> {
    let key_path = data_dir.join("noise_key.bin");
    // ...
    // Save to file
    std::fs::write(&key_path, &keypair.secret)?;  // PLAINTEXT!

    #[cfg(unix)]
    {
        perms.set_mode(0o600);  // Only owner read/write
    }

Вектор атаки:

  1. Атакующий получает read access к data_dir (через malware, physical access, backup leak)
  2. Читает noise_key.bin — 32 байта plaintext private key
  3. Импортирует keypair и выдаёт себя за легитимный узел
  4. Если это hardcoded node — полная компрометация bootstrap

Импакт:

  • Обычный узел: возможность MITM его соединений
  • Hardcoded узел: полная компрометация сети

Сложность: Средняя (требуется доступ к файловой системе)

PoC сценарий:

# Атакующий на скомпрометированной машине
cat /home/node/.montana/noise_key.bin | xxd
# 00000000: 7a8b...  (32 bytes secret key)

# Импорт в другой узел
cp noise_key.bin /attacker/.montana/
./montana --impersonate

[HIGH] V-003: Empty DNS Seeds — No Redundancy

Файл: dns.rs:8-21

Уязвимый код:

pub const DNS_SEEDS: &[&str] = &[
    // Primary seeds (to be populated with actual domains)
    // "seed1.efir.org",
    // ...
];

pub const FALLBACK_IPS: &[(u8, u8, u8, u8)] = &[
    // TimeWeb primary (Moscow)
    (176, 124, 208, 93),
    // Additional fallback IPs (to be populated)
];

Вектор атаки:

  1. DNS_SEEDS пуст — DNS discovery отключен
  2. FALLBACK_IPS содержит только один IP (тот же TimeWeb)
  3. Сеть полностью зависит от одного сервера
  4. DDoS или компрометация = сеть мертва для новых узлов

Импакт: Denial of Service для всех новых узлов

Сложность: Низкая (DDoS одного IP)


[HIGH] V-004: Eclipse via Cloud Provider Subnet Diversity Bypass

Файл: subnet.rs:16-17, verification.rs:200-250

Уязвимый код:

pub const MAX_NODES_PER_SUBNET: usize = 5;
pub const MIN_DIVERSE_SUBNETS: usize = 25;

Вектор атаки:

  1. Bootstrap требует 25 уникальных /16 подсетей
  2. Атакующий арендует VPS у 25+ провайдеров (AWS, GCP, Azure, DigitalOcean, Vultr, Linode, OVH, Hetzner, ...)
  3. Каждый провайдер = другая /16 подсеть
  4. Атакующий контролирует 125 IP (5 × 25) в разных подсетях
  5. Bootstrap verification проходит успешно с поддельными данными

Импакт: Eclipse attack на новые узлы

Сложность:

  • 125 VPS × $5/month = $625/month
  • Один раз настроить автоматизацию
  • Долгосрочная атака экономически выгодна

PoC сценарий:

# terraform/attack.tf
providers = [
    "aws_us-east-1",      # /16: 54.X
    "aws_eu-west-1",      # /16: 52.X
    "gcp_us-central1",    # /16: 35.X
    "azure_eastus",       # /16: 40.X
    # ... 21 more providers
]

for provider in providers:
    for i in range(5):
        create_vm(provider, run="fake-montana-node")

[HIGH] V-005: Orphan Pool Memory Exhaustion

Файл: sync.rs:17-18

Уязвимый код:

pub const MAX_ORPHANS: usize = 100;
// Each orphan can be MAX_SLICE_SIZE = 4MB
// Total: 100 × 4MB = 400MB potential memory

Вектор атаки:

  1. Атакующий генерирует 100 фейковых "orphan" слайсов по 4MB каждый
  2. Слайсы имеют валидный формат, но parent не существует
  3. Узел-жертва хранит их в orphan pool
  4. 400MB памяти заблокировано мусором
  5. Повторить с разных IP для обхода rate limiting

Импакт: Memory exhaustion DoS

Сложность: Низкая (генерация случайных данных)

PoC сценарий:

for i in 0..100 {
    let fake_slice = Slice {
        parent_hash: random_hash(),  // Non-existent parent
        data: vec![0u8; 4_000_000],  // 4MB payload
        // ... valid structure
    };
    send_to_victim(fake_slice);
}
// Victim now holds 400MB of garbage

[MEDIUM] V-006: Flow Control Counts Messages, Not Bytes

Файл: protocol.rs:779-803

Уязвимый код:

// Flow control: pause reading if receive queue is overloaded
if peer.flow_control.should_pause_recv() {
    flow_control_pauses += 1;
    // ...
}
// ...
let msg_size = msg.estimated_size();
peer.flow_control.add_recv(msg_size);

Проблема: should_pause_recv() проверяется ПОСЛЕ чтения сообщения. Атакующий может отправить одно огромное сообщение (MAX_TX_SIZE = 1MB), которое будет полностью прочитано до проверки.

Вектор атаки:

  1. Отправить множество 1MB сообщений подряд
  2. Каждое полностью читается перед pause check
  3. Memory spike до обработки flow control

Импакт: Временные memory spikes

Сложность: Низкая


[MEDIUM] V-007: Self-Connection Nonce Race Condition

Файл: protocol.rs:764-765, 911-915

Уязвимый код:

// Insert nonce
sent_nonces.write().await.insert(version.nonce);
// ...later...
// Check nonce
if sent_nonces.read().await.contains(&version.nonce) {
    return Err(NetError::Protocol("Self-connection detected".into()));
}

Проблема: Между вызовом insert() на одном соединении и contains() на другом есть временное окно. При высокой параллельности возможны false negatives.

Вектор атаки:

  1. Узел инициирует множество параллельных исходящих соединений
  2. Один из них случайно к самому себе
  3. Race condition позволяет обойти проверку

Импакт: Self-connection создаёт петлю сообщений

Сложность: Требует точного timing


[MEDIUM] V-008: Timing Side Channel in ML-DSA-65 Verification

Файл: verification.rs:380-400, криптобиблиотека

Вектор атаки:

  1. Bootstrap verification вызывает ML-DSA-65 signature verification
  2. Время верификации может зависеть от signature content
  3. Атакующий может извлечь информацию о public key через timing

Импакт: Потенциальная утечка криптографических секретов

Сложность: Высокая (требует точных измерений времени)


[LOW] V-009: Unbounded sent_nonces HashSet

Файл: protocol.rs:135, 866-868

Уязвимый код:

sent_nonces: Arc<RwLock<HashSet<u64>>>,
// ...
// Cleanup only on successful disconnect:
if let Some(nonce) = our_sent_nonce {
    sent_nonces.write().await.remove(&nonce);
}

Проблема: Если соединение обрывается до cleanup (crash, timeout), nonce остаётся в HashSet навсегда. При миллионах неудачных соединений — memory leak.

Импакт: Медленный memory leak

Сложность: Требует длительной эксплуатации


[LOW] V-010: Version Information Disclosure

Файл: protocol.rs:904-948

Уязвимый код:

// Record IP vote from peer (addr_recv is how they see us)
let their_view_of_us = version.addr_recv.ip;
if !peer.inbound
    && !their_view_of_us.is_loopback()
    && !their_view_of_us.is_unspecified()
{
    ip_votes.write().await.insert(peer.addr, their_view_of_us);

Вектор атаки:

  1. Sybil-атакующий подключается к жертве с разных IP
  2. Каждое соединение получает Version с addr_recv
  3. Атакующий видит, какой IP жертва считает своим external
  4. Fingerprinting для идентификации узла за NAT

Импакт: Privacy leak, fingerprinting

Сложность: Низкая


5. Атаки, которые НЕ работают

51% Attack

Не применима. Montana не использует PoW/PoS. Консенсус через cumulative weight presence proofs, который накапливается со временем. Нельзя "намайнить" больше веса.

Nothing-at-Stake

Не применима. Нет staking. Presence proofs привязаны к реальному времени через физические ограничения.

Long-Range Attack

Ограниченно применима. Subnet reputation накапливается годами и снапшотится каждые τ₃. Атакующему нужно контролировать репутацию подсетей годами.

Selfish Mining

Не применима. Нет mining. Слайсы создаются по расписанию τ₂.

Transaction Malleability (Classic)

Не проверена. Требует анализа transaction layer (вне scope network audit).

BGP Hijack

Частично защищено. Noise Protocol обеспечивает authenticated encryption. Hijack позволит DoS, но не MITM контента.


6. Рекомендации

CRITICAL Fixes (Требуется немедленно)

# Уязвимость Рекомендация
V-001 Single hardcoded node Добавить минимум 5 hardcoded nodes в разных юрисдикциях
V-002 Plaintext key storage Шифровать ключи через OS keychain или password-derived key
V-003 Empty DNS seeds Настроить DNS seeds на нескольких доменах

HIGH Priority

# Уязвимость Рекомендация
V-004 Cloud subnet bypass Добавить ASN diversity check в дополнение к /16
V-005 Orphan exhaustion Уменьшить MAX_ORPHANS до 20 или добавить size-based limit

MEDIUM Priority

# Уязвимость Рекомендация
V-006 Flow control timing Проверять size limit ДО чтения payload
V-007 Nonce race Использовать атомарный check-and-insert
V-008 Timing side channel Использовать constant-time comparison в crypto

LOW Priority

# Уязвимость Рекомендация
V-009 Nonce leak Добавить periodic cleanup для sent_nonces
V-010 Version disclosure Не включать точный external IP в addr_recv

7. Вердикт

[X] CRITICAL — есть уязвимости, позволяющие уничтожить сеть
[ ] HIGH — есть серьёзные уязвимости
[ ] MEDIUM — есть уязвимости среднего риска
[ ] LOW — только minor issues
[ ] SECURE — уязвимостей не найдено

Обоснование

V-001 (Single Hardcoded Node) и V-003 (Empty DNS Seeds) создают катастрофическую точку отказа. Компрометация или DDoS одного IP (176.124.208.93) полностью парализует bootstrap новых узлов и позволяет навязать поддельную цепь.

V-002 (Plaintext Keys) в сочетании с V-001 означает: если атакующий получит доступ к файловой системе hardcoded node, он получит полный контроль над сетью.

V-004 (Cloud Bypass) показывает, что даже при наличии subnet diversity, экономически мотивированный атакующий может обойти защиту за ~$600/месяц.

Общая оценка

Код сетевого слоя демонстрирует зрелый подход к безопасности (rate limiting, eviction, cryptographic bucketing). Однако инфраструктурные решения (один hardcoded node, пустые DNS seeds, plaintext ключи) создают критические уязвимости уровня сети целиком, а не отдельного узла.

Рекомендация: Не запускать mainnet до исправления V-001, V-002, V-003.


Appendix: Файлы и строки

Уязвимость Файл Строки
V-001 hardcoded_identity.rs 59-68
V-002 encrypted.rs 274-316
V-003 dns.rs 8-32
V-004 subnet.rs 16-17, 169-233
V-005 sync.rs 17-18
V-006 protocol.rs 779-803
V-007 protocol.rs 764-765, 911-915
V-008 verification.rs 380-400
V-009 protocol.rs 135, 866-868
V-010 protocol.rs 904-948