# Security Audit: Lottery Grinding & Bootstrap DoS **Модель:** Gemini 3 Pro **Компания:** Google **Дата:** 08.01.2026 16:30 UTC --- ## 1. Понимание архитектуры Montana ACP (Atemporal Coordinate Presence) — это сеть, где консенсус достигается не через PoW/PoS, а через "накопление присутствия" (время). Узлы подписывают временные слоты (таймслайсы), доказывая своё существование. Победитель раунда (каждые 10 минут, τ₂) выбирается через детерминированную лотерею. Ключевые механизмы защиты: 1. **Детерминированная лотерея**: Должна зависеть только от *предыдущего* состояния сети (хеш прошлого слайса), чтобы исключить манипуляции (grinding) в текущем раунде. 2. **Adaptive Cooldown**: Защита от Sybil через временнУю стоимость входа (1-180 дней). 3. **Adaptive Subnet Limiter**: Защита от сетевых атак (Erebus/DoS) через двухуровневые лимиты подсетей. Я изучил архитектуру и обнаружил критическую уязвимость в реализации консенсуса. --- ## 2. Изученные файлы | Файл | LOC | Ключевые компоненты | |------|-----|---------------------| | `montana/src/consensus.rs` | 271 | Логика лотереи, расчет seed, проверка победителя | | `montana/src/net/rate_limit.rs` | 1183 | Реализация лимитеров, AdaptiveSubnetLimiter | | `montana/src/net/protocol.rs` | 1653 | Основной сетевой протокол, обработка сообщений | | `montana/src/net/bootstrap.rs` | 1254 | Логика начальной загрузки и верификации | | `montana/src/cooldown.rs` | 262 | Реализация адаптивного кулдауна | --- ## 3. Attack Surface Я определил следующие векторы атак: 1. **Манипуляция лотереей (Grinding)**: Возможность влиять на выбор победителя через изменение содержимого блока. 2. **Блокировка запуска (Bootstrap DoS)**: Манипуляция медианой сети для принудительного отказа в обслуживании новым узлам. --- ## 4. Найденные уязвимости ### [CRITICAL] Lottery Grinding (Манипуляция лотереей) **Файл:** `montana/src/consensus.rs:23` **Уязвимый код:** ```rust pub fn compute_lottery_seed(prev_hash: &Hash, tau2_index: u64, presence_root: &Hash) -> Hash { let mut data = Vec::with_capacity(72); data.extend_from_slice(prev_hash); data.extend_from_slice(&tau2_index.to_le_bytes()); data.extend_from_slice(presence_root); // <--- КРИТИЧЕСКАЯ ОШИБКА sha3(&data) } ``` **Описание:** В документации (`layer_1.md`) явно указано, что `seed = SHA3-256(prev_slice_hash ‖ τ₂_index)`. Это гарантирует, что победитель определен *до* формирования блока. Однако в коде в расчет `seed` включен `presence_root` *текущего* блока. Поскольку `presence_root` зависит от набора подписей, включенных в блок, а блок формирует сам победитель, это создает циклическую зависимость, которую атакующий может эксплуатировать. **Вектор атаки:** 1. Атакующий (даже с минимальным весом) собирает подписи присутствия (presence signatures) от других узлов. 2. Вместо публикации всех подписей, атакующий перебирает различные подмножества подписей. 3. Для каждого подмножества вычисляется новый `presence_root`. 4. Новый `presence_root` дает новый `seed` лотереи. 5. Новый `seed` меняет победителя (функция `find_winner`). 6. Атакующий повторяет перебор (Grinding), пока не найдет такой `presence_root`, при котором `seed` делает **его** победителем. 7. Атакующий публикует валидный блок, где он — законный победитель. **Импакт:** Атакующий с минимальным весом может выигрывать лотерею практически в каждом раунде, просто перебирая комбинации подписей. Это полностью ломает модель консенсуса, основанную на времени/весе, и превращает её в PoW-гонку (где "работа" — это хеширование комбинаций подписей). Захват сети возможен с одним слабым узлом. **Сложность:** Низкая. Требуется только CPU для хеширования. **PoC сценарий:** ```rust // Псевдокод атаки let signatures = collect_mempool_signatures(); let my_pubkey = my_keypair.public; for subset in signatures.powerset() { let root = compute_merkle_root(subset); let seed = compute_lottery_seed(prev_hash, index, root); let (winner, _) = find_winner(seed, all_participants); if winner == my_pubkey { publish_block(subset); // PROFIT! break; } } ``` --- ### [MEDIUM] Bootstrap DoS via Consensus Manipulation **Файл:** `montana/src/net/bootstrap.rs:326` (verify_hardcoded_consensus) **Описание:** При запуске узел опрашивает 100 пиров (из которых ~20 hardcoded). Он вычисляет медиану высоты цепи по всем ответам. Затем он требует, чтобы *каждый* hardcoded узел соответствовал этой медиане (с допуском 1%). Если hardcoded узлы отклоняются (потому что медиана смещена атакой), загрузка прерывается с ошибкой CRITICAL. **Вектор атаки:** Атакующий окружает новый узел своими пирами (Eclipse) и сообщает ложную высоту (например, сильно большую или малую). Медиана по всем 100 пирам смещается в сторону атакующего. Честные hardcoded узлы (которые сообщают реальную высоту) оказываются "несогласными" с медианой. Узел считает, что hardcoded узлы скомпрометированы, и аварийно останавливается. **Импакт:** Полный отказ в обслуживании (DoS) для новых узлов. Они не могут присоединиться к сети. **Сложность:** Средняя (требуется контроль входящих соединений жертвы). --- ## 5. Атаки, которые НЕ работают 1. **Erebus / Subnet Flood**: Код `GlobalSubnetLimiter` в `rate_limit.rs` корректно реализует двухуровневую защиту (Fast/Slow tiers) и правильно интегрирован в `protocol.rs` (вызовы `subnet_limiter.check()`). Это защищает от атак с использованием множества IP из одной подсети. 2. **Sybil (регистрация)**: `AdaptiveCooldown` реализован корректно в `cooldown.rs`. Спам регистрациями действительно приведет к увеличению кулдауна до 180 дней. 3. **Fake Hardcoded Nodes**: `HardcodedNode` аутентификация через ML-DSA-65 реализована и работает. Подделать hardcoded узел без приватного ключа нельзя. 4. **Inventory Exhaustion**: `BoundedInvSet` использует FIFO удаление старых элементов, что защищает память даже при флуде уникальными инвентарными хешами. --- ## 6. Рекомендации 1. **Исправить Lottery Grinding (СРОЧНО)**: Исключить `presence_root` из расчета `seed` в `consensus.rs`. Seed должен зависеть *только* от `prev_hash` и `index`. ```rust // Было: // data.extend_from_slice(presence_root); // Стало: // (удалить эту строку) ``` Это сделает лотерею честной: победитель определяется до того, как он сможет манипулировать содержимым блока. 2. **Улучшить логику Bootstrap**: Вместо аварийной остановки при несогласии hardcoded узлов с медианой сети, следует использовать "Trusted Core" подход: 1. Собрать ответы от всех hardcoded узлов. 2. Вычислить медиану ТОЛЬКО среди hardcoded узлов (`hardcoded_median`). 3. Проверить консенсус внутри hardcoded группы (сколько узлов в пределах ±1% от `hardcoded_median`). 4. Если большинство (>50%) hardcoded узлов согласны → считать `hardcoded_median` истинной. 5. P2P узлы проверять относительно этой доверенной медианы (warning при расхождении, но не блокировка). 6. Hardcoded узлы, которые не согласны с `hardcoded_median` (меньшинство), игнорируются, но не вызывают падения. Это сделает bootstrap устойчивым к Eclipse-атакам, так как атакующий не может подделать подписи hardcoded узлов. --- ## 7. Вердикт [x] CRITICAL — есть уязвимости, позволяющие уничтожить сеть (Lottery Grinding позволяет захватить контроль над блокчейном). [ ] HIGH [ ] MEDIUM [ ] LOW [ ] SECURE