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

20 KiB
Raw Permalink Blame 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 является заглушкой и возвращает пустой вектор без выполнения реальных запросов:

    /// 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 верификация только логируется, но не выполняется и не блокирует запуск:
        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");
  1. Сеть запускается без реальной верификации
  2. AddrMan загружается из addresses.dat без проверки консенсуса
  3. Все исходящие соединения идут к адресам из 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 сообщений нет проверки разнообразия подсетей. Атакующий может отправить множество адресов из одной подсети:

            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:

    /// 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. Это может быть использовано для вытеснения легитимных адресов:

        // 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() выбирает адреса случайным образом без проверки разнообразия подсетей:

    /// 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 (Высокий):

  1. Улучшить bucket collision handling:

    • Не перемещать существующие адреса из TRIED при коллизии
    • Использовать более сложную стратегию вытеснения
  2. Добавить проверку разнообразия в select():

    • Отслеживать уже выбранные подсети
    • Приоритизировать адреса из новых подсетей

Приоритет 3 (Средний):

  1. Усилить rate limiting:

    • Добавить проверку разнообразия подсетей в rate limiter
    • Ограничить количество адресов из одной подсети от одного источника
  2. Добавить мониторинг:

    • Логировать предупреждения при низком разнообразии подсетей
    • Алерты при подозрительных паттернах заполнения AddrMan

Заключение

Сетевой слой Montana содержит критические уязвимости, которые позволяют злоумышленнику выполнить успешную Eclipse Attack. Основная проблема заключается в том, что startup verification не выполняется, что полностью обходит защиту от Eclipse Attack.

Дополнительные уязвимости позволяют заполнить AddrMan вредоносными адресами и контролировать все исходящие соединения жертвы.

Рекомендуется немедленное исправление всех обнаруженных уязвимостей.


Приложение: Код уязвимостей

Уязвимость #1: Startup Verification не выполняется

// 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 заполняется без проверки разнообразия

// Montana ACP/montana/src/net/protocol.rs:998
let added = addresses.write().await.add_many(to_process, peer.addr);
// ❌ Нет проверки разнообразия подсетей

Уязвимость #3: Netgroup diversity только для outbound

// Montana ACP/montana/src/net/connection.rs:272-277
pub async fn can_connect(&self, addr: &SocketAddr) -> bool {
    // ⚠️ Проверяется только при outbound соединениях
    // ❌ Не защищает от заполнения AddrMan через inbound
}

Конец отчета