montana/Русский/Совет/Google/подбор_лотереи_08.01.2026_16:00.md

155 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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