FoxHunter — охота на лис (ARDF) на LoRa
Спортивная радиопеленгация (ARDF, «охота на лис») на LoRa: три роли на одинаковом
железе E77-900MBL (STM32WLE5). Лиса — маяк-передатчик (9-байтовый пакет
каждые 300 мс). Охотник — приёмник с зуммером «горячо-холодно» (громкость по
усреднённому RSSI) и опциональным OLED. Фальшлиса — учебный «атакующий» на
СВОЁМ железе в классе, показывающий три классические слабости беспроводной связи.
Исходный код, методика и схема — в firmware/Projects/LORAWAN/FoxHunter.
Проект соединяет два разных курса на одном стенде: сначала физика поиска — ребёнок
находит спрятанный передатчик руками, по громкости, и затухание сигнала перестаёт
быть формулой; затем безопасность протокола — почему сигналу нельзя верить слепо,
как подпись ловит подделку, счётчик кадров — повтор, а длина ключа решает, можно ли
перебрать подпись. Порядок строгий: сначала найти лису руками, только потом лезть
внутрь. Python-стенд foxhunt_sim.py даёт понять «горячо-холодно» до выхода на
охоту — карта зон громкости на этаже с той же логикой усреднения и порогов, что в
прошивке охотника.
Методическое пособие: FoxHunter — охота на лис на LoRa
Стенд: три роли на одинаковом железе E77-900MBL (STM32WLE5), выбираются прошивкой. Лиса — маяк-передатчик, шлёт компактный 9-байтовый пакет каждые 300 мс. Охотник — приёмник с зуммером «горячо-холодно» (громкость по усреднённому RSSI) и опциональным OLED. Фальшлиса — учебный «атакующий» на СВОЁМ железе, который показывает три классические слабости беспроводной связи.
Это спортивная радиопеленгация (ARDF — Amateur Radio Direction Finding, «охота на
лис»), в которую играют десятилетиями. Проект соединяет два разных курса: сначала
физика поиска (ребёнок находит спрятанный передатчик руками, по громкости),
затем безопасность протокола (почему сигналу нельзя верить слепо и зачем нужна
настоящая криптография). Полная методика преподавания — в METODIKA.md, железо и
сборка — в README.md. Python-стенд foxhunt_sim.py даёт понять «горячо-холодно»
до выхода на охоту — карта зон громкости на этаже, физика RSSI и та же логика
усреднения и порогов, что в прошивке охотника.
Порядок уроков строгий: сначала найти лису руками, и только потом лезть внутрь. Магия — в находке, а не в CMAC.
Кто чем пользуется
- Инженер отвечает за стенд: прошивки ролей, приглушение лисы под площадку,
зуммер через резистор 100 Ом, замер шума эфира (
[NOISE]в мониторе). - Учитель прячет лису и ведёт три урока по сценарию.
- Методист привязывает физику пеленгации и слабости протокола к программе.
Модуль 1. Физика пеленгации: «горячо-холодно»
Урок 1. Громкость вместо направления: почему в здании ищут так
- Тема: логарифмическая шкала (дБм), затухание сигнала с расстоянием.
- Стенд:
foxhunt_sim.py. Параметры:ZONES[],rssi_at, показатель n.
Ход работы. Запустите uv run foxhunt_sim.py. Двигайте мышь над картой этажа —
это «ходьба с охотником». Внизу справа — «зуммер»: зона RYADOM/GORYACHO/TEPLO/
HOLODNO и частота пиков. Найдите спрятанную лису, ориентируясь только на зону.
На графике:
Зоны громкости на этаже Профиль RSSI(расстояние)
RYADOM ▓ (сплошной тон) RSSI│╲
GORYACHO ▒ (частые пики) │ ╲___ RYADOM −55
TEPLO ░ (редкие) │ ╲___ TEPLO −85
HOLODNO · (очень редкие) │ ╲___
└──────────────► расстояниеРазбор. В здании радиоволна отражается от стен и арматуры — приходит со всех
сторон, поэтому направление по антенне работает плохо, а дальность по громкости
— отлично: ближе к лисе → выше RSSI → чаще пики зуммера. RSSI падает по
лог-дистанционной модели RSSI(d) = P_tx − PL(d0) − 10·n·lg(d/d0), где n≈3 в
здании. Прошивка охотника делит эту непрерывную величину на зоны (ZONES[]) и
озвучивает их разной частотой пиков. Это игра «горячо-холодно» — и она честная:
за ней стоит настоящая физика затухания.
Практическое задание. По профилю RSSI в стенде определите, на каком расстоянии проходит граница RYADOM (−55 дБм) при мощности лисы 2 дБм. Сверьте с реальной охотой: в какой примерно комнате зуммер перейдёт на сплошной тон?
Урок 2. Приглушить лису: почему мощная лиса ломает охоту
- Тема: динамический диапазон, насыщение, соотношение сигнал/масштаб.
- Стенд:
foxhunt_sim.py(ползунок мощности). Параметр:FOX_TX_PWR_DBM.
Ход работы. В стенде поставьте мощность лисы 14 дБм и походите по этажу: почти везде горит RYADOM — искать нечем. Теперь убавьте до 2 дБм: зоны стали контрастными, к лисе ведёт явный градиент.
На графике:
Лиса 14 дБм Лиса 2 дБм
RYADOM почти на весь этаж RYADOM ▓ у самой лисы
(96% площади — «горячо везде») GORYACHO ▒ вокруг, дальше TEPLO/HOLODNO
искать нечем явный градиент к целиРазбор. Чувствительность зуммера-«градусника» ограничена: если лиса мощная, её RSSI насыщает зону RYADOM уже в соседней комнате — весь этаж «горячий», разницы нет. Приглушив лису до 2 дБм, мы сжимаем зоны до масштаба этажа, и «горячо-холодно» снова различимо. Это общий инженерный принцип: измеритель полезен только в своём динамическом диапазоне — под масштаб задачи подстраивают не прибор, а источник. То же в фотографии (экспозиция), в звуке (усиление), в АЦП (диапазон входа).
Практическое задание. В стенде найдите минимальную мощность лисы, при которой на 40-метровом этаже ещё нет зоны тишины (сигнал добивает в углы), но RYADOM не разливается шире одной «комнаты» (~8 м). Это и есть оптимум под площадку.
Урок 3. Несколько лис по очереди: расписание ARDF и усреднение
- Тема: разделение времени (TDMA), скользящее среднее, robustность.
- Параметры:
FOX_COUNT/SLOT_MS,RSSI_AVG_N, «проговор» ID.
Ход работы. По коду лисы и охотника: лисы делят цикл на слоты (SLOT_MS),
вещают по очереди (FOX_ID), охотник «проговаривает» номер активной лисы пиками
(лиса 1 — один пик, лиса 2 — два). В стенде поменяйте окно усреднения RSSI_AVG_N
и посмотрите, как «зуммер» становится плавнее (7) или отзывчивее (3).
Разбор. Несколько передатчиков на одной частоте не мешают друг другу, потому
что разделены во времени (аналог TDMA): каждая лиса вещает свой слот и молчит в
чужой. Позывные MOE/MOI/MOS настоящего ARDF здесь заменены «проговором» числа
пиков. Сырой RSSI LoRa скачет на ±3-5 дБ от пакета к пакету — поэтому охотник
усредняет по окну из RSSI_AVG_N пакетов: среднее гасит скачки и даёт плавную
громкость. Меньше окно — отзывчивее (но дёрганее), больше — плавнее (но ленивее):
тот же компромисс, что в любом сглаживающем фильтре.
Практическое задание. Почему при смене активной лисы охотник СБРАСЫВАЕТ буфер
усреднения (rssiReset()), а не продолжает среднее? Что было бы со стрелкой
громкости в первые секунды после переключения, если бы буфер не сбрасывался?
Модуль 2. Безопасность протокола: почему сигналу нельзя верить
Только после того, как дети уверенно ищут лис. Нужна прошивка FoxHunt_FakeFox —
учебный «атакующий» на СВОЁМ железе в классе. Кнопка переключает три атаки.
Урок 4. Подпись против подмены (spoofing)
- Тема: аутентификация сообщений, контрольная подпись, целостность.
- Параметры:
foxCalcSignature(), атака ATK_SPOOF.
Ход работы. Фальшлиса (атака 1) шлёт пакет с верным fox_id и растущим fcnt,
но НАМЕРЕННО испорченной подписью. Охотник печатает [SEC] REJECT ... SIG:FAIL,
на экране [FAKE], зуммер молчит.
Разбор. Каждый пакет несёт подпись — байт, вычисленный из всех полей и
секретного ключа (foxCalcSignature). Кто не знает ключа, не подделает подпись под
свои данные. Охотник пересчитывает подпись сам и сравнивает: не сошлось — пакет
отвергнут, «лиса» признана фальшивой. Так приёмник отличает подделку, не видя
отправителя — только по математике. Это и есть аутентификация сообщения, основа
защиты любого протокола.
Практическое задание. Вопрос классу: охотник понял, что пакет поддельный, хотя
fox_id был правильный и fcnt рос. Какое единственное поле его выдало и почему
атакующий не смог его подделать?
Урок 5. Счётчик кадров: replay-атака против ребута лисы
- Тема: защита от повтора, монотонность, различение схожих причин.
- Параметры:
fcnt, логика RESYNC vs REPLAY вprocessBeacon.
Ход работы. Учитель заранее ловит реальный пакет лисы (строка [RAW] в
мониторе охотника → байты в CAPTURED_PACKET). Фальшлиса (атака 2) шлёт этот
пакет снова и снова БЕЗ ИЗМЕНЕНИЙ. Подпись верна, но fcnt СТОИТ. Охотник:
[SEC] REJECT ... SIG:OK FCNT:REPLAY. Затем перезагрузите настоящую лису — её
fcnt тоже низкий, но РАСТЁТ, и охотник сам ресинхронизируется ([RESYNC]).
На графике:
Настоящая лиса (ребут) Replay-атака
fcnt: 1,2,3,... (растёт) fcnt: 127,127,127,... (застыл)
→ RESYNC, лиса принята → REJECT, атака отбитаРазбор. Подпись ловит подделку, но НЕ ловит повтор: атакующий может записать
чужой валидный пакет и переиграть его. Защита — монотонный счётчик кадров
fcnt: охотник помнит последний и принимает только больший. Красивый момент: и
у replay-атаки, и у перезагруженной лисы fcnt низкий — но у атаки он ЗАСТЫЛ, а у
ребута РАСТЁТ. Один и тот же механизм (динамика счётчика) отличает «честная лиса
перезагрузилась» от «злоумышленник переигрывает старое»: три растущих подряд →
ребут (ресинк), застывший → атака (отказ). Так работает защита от replay в реальных
протоколах (LoRaWAN, TLS, IPsec).
Практическое задание. Почему нельзя просто «принимать любой fcnt, если подпись
верна»? И почему одного растущего пакета мало для ресинка — зачем требовать три
подряд (RESYNC_N)?
Урок 6. Брутфорс подписи: почему 1 байт — не защита, а 4 байта — защита
- Тема: пространство ключей, вычислительная стойкость, экспонента.
- Параметры: атака ATK_BRUTE, мостик к AES-CMAC (4-байтовый MIC).
Ход работы. Фальшлиса (атака 3) перебирает все 256 значений однобайтовой
подписи для одного пакета, раз в секунду шлёт следующее. Рано или поздно совпадёт —
и охотник примет фальшивку как настоящий [RX]! Наблюдайте счётчик перебора в
мониторе фальшлисы.
На графике:
Подпись 1 байт = 256 вариантов Подпись 4 байта (MIC) = 2³² вариантов
перебор за ~минуты на 1 Гц ~4.3 млрд — перебор нереален
█ пробита 🔒 держитРазбор. Наша подпись — намеренно слабая: 1 байт = всего 256 вариантов, перебор совпадёт в среднем за 128 попыток. Это не баг, а учебный материал: он показывает, ЗАЧЕМ настоящие системы берут 4-байтовый MIC (Message Integrity Code) на базе AES-CMAC — 2³² ≈ 4.3 млрд вариантов, перебор физически нереален. Каждый добавленный байт умножает стойкость на 256 (экспонента) — вот почему длина ключа решает. Это прямой мостик к «взрослой» LoRaWAN-ветке курса, где подпись честная.
Практическое задание. Если однобайтовую подпись перебирают за ~2 минуты (1 Гц), сколько времени займёт перебор 4-байтового MIC при той же скорости? (Ответ в годах переведите в понятную величину.) Почему в реальности атакующий не может слать «быстрее» без ограничений?
Приложение: таблица переноса концепций в индустрию
| Концепция из проекта | Где встречается за пределами лаборатории |
|---|---|
| Лог-дистанционная модель RSSI | Site survey, планирование покрытия, локализация |
| Динамический диапазон измерителя | Фотография, АЦП, аудио, любые сенсоры |
| Скользящее среднее (сглаживание) | Обработка сигналов, датчики, финансы |
| Разделение времени (TDMA) | Сотовые сети, промышленные шины, ARDF |
| Аутентификация сообщения (подпись/MIC) | TLS, LoRaWAN, банковские протоколы |
| Защита от replay (счётчик кадров) | LoRaWAN, TLS, IPsec, платёжные системы |
| Стойкость ключа, пространство перебора | Вся криптография; выбор длины ключа |
Заключение
FoxHunter ведёт ученика от осязаемого к абстрактному: сначала он находит спрятанный
передатчик руками, по громкости зуммера, — и физика затухания перестаёт быть
формулой, становится игрой «горячо-холодно». Затем на том же железе он видит, как
легко подделать сигнал, если протокол наивен, и как три механизма (подпись, счётчик
кадров, длина ключа) по очереди эту наивность лечат — вплоть до понимания, зачем
существует настоящая криптография. Python-стенд foxhunt_sim.py даёт прожить первую
половину — почему мощную лису не найти и как приглушение возвращает контраст, — а
фальшлиса на своём железе честно, безопасно и наглядно показывает вторую. Главный
принцип курса тут звучит буквально: сигналу нельзя верить слепо — ни его громкости
(мощная лиса «горячо везде»), ни его содержимому (подделка и повтор).