6.1 KiB
Security Audit: Network Layer / DoS
Модель: Gemini 3 Pro Компания: Google Дата: 08.01.2026 12:00 UTC
1. Понимание архитектуры
Montana ACP — это система, где консенсус достигается не через PoW/PoS, а через "наблюдаемое время" и физические инварианты (Слой -1). Слайсы (Slices) заменяют блоки и упорядочиваются по временным меткам.
Сетевой слой должен защищать этот хрупкий механизм синхронизации. Однако, внедрение пост-квантовой криптографии (ML-DSA, ML-KEM) создает новые векторы атак, связанные с высокой вычислительной стоимостью этих примитивов. Я атакую именно это: стоимость защиты.
2. Изученные файлы
| Файл | LOC | Ключевые компоненты |
|---|---|---|
net/protocol.rs |
1500+ | Основной цикл обработки сообщений, хендшейк, диспетчер. |
net/rate_limit.rs |
880 | TokenBucket реализация, лимитеры для Inv/Addr/Get. |
crypto.rs |
150 | Обертки над Dilithium (ML-DSA-65). |
net/message.rs |
160 | Определения сообщений и их размеров. |
3. Attack Surface
Точки входа:
- Handshake (Noise XX): Потенциально тяжелый, но защищен таймаутами.
- Message Processing: Основной цикл
process_message. - Hardcoded Node Auth: Механизм, позволяющий узлам доказать, что они "официальные".
4. Найденные уязвимости
[CRITICAL] Dilithium Storm (CPU Exhaustion on Bootstrap Nodes)
Файл: Montana ACP/montana/src/net/protocol.rs:1175
Уязвимый код:
1175| Message::AuthChallenge(challenge) => {
1176| if let Some(ref secret_key) = config.hardcoded_secret_key {
1177| // СИНХРОННАЯ ТЯЖЕЛАЯ ОПЕРАЦИЯ БЕЗ RATE LIMIT
1178| let sig = match crate::crypto::sign_mldsa65(secret_key, &challenge) {
// ...
Вектор атаки:
- Атакующий устанавливает TCP-соединение с Seed Node (адрес известен, это публичная инфраструктура).
- Не завершая хендшейк (или сразу после), атакующий отправляет поток сообщений
AuthChallenge. - В
rate_limit.rsструктураPeerRateLimitsне содержит лимитера дляAuthChallenge. - Узел принимает сообщение (оно
allowed_pre_handshake), вызываетsign_mldsa65. - Так как
sign_mldsa65— синхронная функция, выполняющая сложные операции над решетками (Lattice-based cryptography), потокtokioблокируется. - При потоке в 1000 msg/sec процессор узла уходит в 100% Load, переставая обрабатывать легитимные соединения.
Импакт: Полный отказ в обслуживании (DoS) критической инфраструктуры (Bootstrap Nodes). Новые узлы не могут подключиться к сети, так как не могут получить список пиров от сидов. Сеть фрагментируется.
Сложность: Низкая. Требуется 1 CPU атакующего, чтобы положить 1 CPU сервера (асимметрия в пользу защиты отсутствует, так как проверка подписи дешевле генерации, но здесь мы заставляем сервер генерировать).
PoC сценарий:
// Pseudo-code attacker
let stream = TcpStream::connect(seed_ip).await?;
let mut noise = NoiseBuilder::new_initiator()...; // Handshake
// Flood loop
loop {
let challenge = [0u8; 32];
let msg = Message::AuthChallenge(challenge);
noise.write_encrypted(msg).await?;
// No wait for response
}
5. Атаки, которые НЕ работают
-
Memory Exhaustion via Large Messages: В
net/encrypted.rsреализована защита через чанкинг. Даже если я пошлю заголовок 2MB, память аллоцируется постепенно. Глобальный лимит памяти на 117 соединений (~250MB) приемлем. -
Sybil via Subnet Flooding: В
net/rate_limit.rsреализованGlobalSubnetLimiter(Erebus protection) с разделением на Fast/Slow tiers. Это очень надежная защита от захвата слотов с одного провайдера.
6. Рекомендации
- Добавить Rate Limit: В
PeerRateLimitsдобавитьauth_challenge: TokenBucket::new(5.0, 0.1). 5 запросов в берсте, 1 раз в 10 секунд восстановление. - Make it Async: Вынести
sign_mldsa65вtokio::task::spawn_blocking, чтобы не блокировать сетевой цикл. - Disable Pre-Handshake Auth: Запретить
AuthChallengeдо завершения Noise-хендшейка.
7. Вердикт
[ ] CRITICAL — есть уязвимости, позволяющие уничтожить сеть (инфраструктуру) [x] HIGH — есть серьёзные уязвимости [ ] MEDIUM — есть уязвимости среднего риска [ ] LOW — только minor issues [ ] SECURE — уязвимостей не найдено