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

8.3 KiB
Raw Permalink Blame History

Модель: GPT-5.2 Компания: OpenAI Дата: 07.01.2026 18:11 UTC

Задача

Найти практический вектор Eclipse Attack на сеть Montana (P2P), опираясь на код в /Montana ACP/montana/src/net/.

TL;DR (главная уязвимость)

Заявленная защита “full bootstrap verification (100 peers, 25+ /16 subnets, hardcoded median check)” фактически не исполняется в текущей реализации:

  • main.rs только логирует «Startup verification … Full bootstrap…», но не вызывает StartupVerifier / BootstrapVerifier.
  • Network::start() запускает listener/connector/maintenance и сразу добавляет user-supplied seeds в AddrMan, после чего connection_loop начинает диалить адреса без какого-либо гейта “verification passed”.
  • net/startup.rs содержит заглушку query_hardcoded_tips()Vec::new(), то есть даже если verifier вызывать, он не сможет набрать MIN_HARDCODED_RESPONSES.

Следствие: Eclipse сводится к классике — poisoning AddrMan + перехват outbound.

Доказательства по коду (ключевые места)

1) Startup verification не выполняется

montana/src/main.rs:

  • Есть лог о “Startup verification … Full bootstrap…”, но дальше код сразу делает Network::new() и network.start() (без вызова verifier).

montana/src/net/protocol.rs:

  • Network::start() спаунит listener_loop, connection_loop, maintenance_loop, затем добавляет seeds через add_seed() и возвращает Ok(()).
  • Никакой проверки, что “startup verification passed”, нет.

2) StartupVerifier — заглушка

montana/src/net/startup.rs:

  • query_hardcoded_tips() возвращает Vec::new() (placeholder), а total_peers в результате = responses.len() с комментарием “Would be 100 in full implementation”.

3) Addr poisoning реально влияет на выбор outbound

montana/src/net/protocol.rs:

  • connection_loop выбирает адрес через addrman.select() (50/50 NEW vs TRIED) и затем коннектится.

4) TRIED заполняется после handshake (это хорошо), но это делает eclipse ещё проще при отсутствии bootstrapping

montana/src/net/protocol.rs:

  • На Message::Verack вызывается addresses.write().await.mark_connected(&peer.addr); — перевод адреса в TRIED происходит после успешного handshake.

5) Addr rate-limit легко обходится Sybilом (лимит per-connection)

montana/src/net/rate_limit.rs:

  • AddrRateLimiter: burst 1000, sustained 0.1 addr/sec.
  • Лимитер хранится в Peer → лимит на соединение, а не глобальный.
  • Значит атакующий открывает много соединений (входящих/исходящих) и с каждого отправляет по 1000 адресов → быстро забивает NEW таблицу.

Практическая схема Eclipse Attack (эксплуатация)

Предпосылки

  • Жертва запускает узел и имеет хотя бы 12 канала к атакующему (например, через --seeds или просто подключившись к атакующему узлу).
  • Атакующий контролирует набор IPов, желательно распределённых по разным /16 (или IPv6-префиксам так, как считает get_netgroup).

Шаг 1 — “засорить NEW” адресной книгой атакующего

  1. Атакующий устанавливает соединение с жертвой и доводит handshake до Verack (иначе нельзя слать Addr).
  2. Сразу после handshake отправляет Addr с максимумом адресов (до 1000 в сообщении).
  3. Повторяет через множество Sybil-соединений: каждый Peer имеет свой AddrRateLimiter → снова 1000 burst.

Результат: AddrMan::new_table (1024 buckets × 64) — до ~65k слотов — может быть существенно заполнена адресами атакующего.

Шаг 2 — перевести атакующие адреса в TRIED

  1. Т.к. connection_loop выбирает адреса из AddrMan (50/50 NEW/TRIED) и нет гейта на bootstrap-verification, жертва начнёт диалить адреса из отравленного AddrMan.
  2. Атакующие узлы принимают соединение и корректно отвечают handshake.
  3. На Verack адрес переводится в TRIED (mark_connected).

Результат: со временем TRIED (256×64 = 16384 слота) тоже становится “атакующий-доминант”.

Шаг 3 — рестарт жертвы и «полный eclipse»

После рестарта жертва снова будет выбирать peers из AddrMan (частично TRIED) и практически все outbound уйдут на атакующего.

Ограничения и как атакующий их обходит

  • MAX_OUTBOUND = 8, MAX_PEERS_PER_NETGROUP = 2 (т.е. максимум 2 исходящих на один /16).
    • Для полного перехвата 8 outbound нужно иметь ≥4 разных netgroup (/16) и по 2 адреса в каждом.
  • MAX_CONNECTIONS_PER_IP = 2 — не даёт одному IP занять много слотов.
    • Но атакующий использует несколько IP.
  • Факт отсутствия “100 peers / 25+ subnets / hardcoded median check” делает стоимость атаки на порядки ниже, чем заявлено в комментариях.

Почему это именно Eclipse (а не просто Sybil)

Потому что цель — монополизировать видимость сети жертвы за счёт контроля всех/почти всех outbound + доминирования адресной книги, а не просто “иметь много узлов”. Здесь это достигается через AddrMan poisoning и отсутствие обязательной startup-верификации.

Рекомендации (high level)

  1. Сделать startup verification реальным гейтом:
    • до запуска connection_loop собрать 100 ответов, проверить 25+ /16, проверить hardcoded-median, и только затем разрешать outbound.
  2. Убрать/жёстко ограничить доверие к --seeds:
    • сейчас add_seed() bypassит часть проверок и фактически даёт атакующему якорь.
  3. Глобальный и per-IP/per-netgroup лимит на Addr ingestion:
    • текущий лимит per-peer легко обходится множеством соединений.
  4. (Если включать feelers) Feeler должен проходить protocol handshake, иначе “TCP-only reachability” снова откроет прямой путь к TRIED poisoning.

Приложение: ключевые файлы

  • montana/src/net/protocol.rs — выбор outbound (AddrMan::select), обработка Addr, перевод в TRIED на Verack.
  • montana/src/net/addrman.rs — NEW/TRIED таблицы, bucket logic.
  • montana/src/net/startup.rs и montana/src/net/bootstrap.rs — заявленная модель защиты, но сейчас не интегрирована/частично заглушена.
  • montana/src/net/rate_limit.rs — per-peer токенбакеты.