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

155 lines
11 KiB
Markdown
Raw Permalink Normal View History

# 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