Предисловие
Приветствую всех, давно не виделись
Рад, что вся шумиха вокруг форума немного улеглась — теперь могу снова приносить уникальный контент. Но сегодня речь не об этом.
Меня уже давно интересуют атаки на сотовые сети. Однако в современных реалиях большинство таких атак потеряли актуальность: 2G везде отключается, а именно с ним было связано большинство векторов атак. Я долго исследовал эту тему, и чего только не пробовал: side-channel атаки на SIM-карты по замерам потребления тока и дифференциальному анализу, атаки на операторские femtocell для получения доступа к внутренней сети оператора и многое другое. Но всё упирается в один ключевой элемент — злополучный ключ Ki.
Ключ Ki — это суть всей безопасности и настоящий «грааль» современных сотовых сетей. Его записывают на SIM-карту так, чтобы даже физически извлечь его было почти невозможно, в защитные меры входит: рандомизация напряжения во время операций, защита от лазерного считывания и другие меры. Брутфорс и криптоанализ этого ключа через посыл рандомных чисел не имеет смысла: во-первых, SIM-карта просто блокируется после определённого количества неверных запросов, а во-вторых, даже квантовые алгоритмы будут подбирать его слишком долго.
По замыслу архитекторов сети, этот ключ никогда не покидает SIM-карту. Он используется для связывания с случайным числом, которое присылает базовая станция, имеющая доступ к HSS. Сеть выполняет ту же операцию у себя, сравнивает результат, и если они совпадают — аутентификация успешна, сеть считается доверенной. В отличие от GSM, обойти такую аутентификацию невозможно: без знания Ki нельзя заставить телефон подключиться к своей eNodeB. Соответственно, перехват SMS и звонков для «обычного исследователя» невозможен. И если у государственных структур с доступом к Diameter ещё есть возможность извлечь ключ KASME (один из сеансовых ключей), то для обычногодрочилы энтузиаста, даже с дорогим SDR, трафик остаётся полностью недоступным.
Но нам этот Ki не так то больно и нужен, если нужда только в пассивном перехвате траффика то будет хватать и session KASME ключа, и к нашему ограниченому счатью его вполне можно достать, если попасть куда надо.
Зачем нужен KASME:
KASME — это корневой сеансовый ключ LTE, из которого выводятся ключи KeNB (для защиты радиоканала), KNASenc/KNASint (для шифрования и целостности NAS) и ключи для дальнейших хэндоверов. Получив KASME, атакующий может:
Срок действия ключа:
KASME генерируется при каждой процедуре аутентификации (Attach, TAU, периодическая re-authentication) и обычно действует до следующего обновления сеанса или до выхода устройства из сети. В среднем ключ остаётся валидным до нескольких часов (в зависимости от политики оператора и настроек таймеров T3412/T3402). Это означает, что успешное считывание KASME даёт атакующему «окно возможностей» на всё время жизни текущей сессии, пока телефон не выполнит повторный AKA и не получит новый KASME.
Самое прекрасное это то что после аунтефикации, этот ключ сидит в памяти бейсбенда, и имея к нему доступ нам достаточно просто записивать разшифрованый траффик и любоватсяпереписками жены которая вам изменяет важной для вас информацией.
Целью этой серии статтей является разработка и апробация методики удалённого чтения сеансового ключа KASME из памяти baseband без знания Ki и без завершённой AKA, воздействуя на обработчики, которые принимают кадры/сообщения до включения защиты.
В общем надо думать причем довольно нестандартно, как в известной цитате:
Глава 0.1 Почему именно low-level и модем как вектор?
В 3G/4G аутентификация двухсторонняя, однако сигнальные уязвимости сохранялись: ошибки в NAS/RRC-процедурах (Attach/TAU, RRC Setup/Reconfiguration), приводившие к утечке идентификаторов/DoS на реализациях отдельных вендоров. Эти аспекты хорошо документируются стандартами 3GPP (например, TS 36.331 для RRC и TS 24.301 для NAS), но конкретные реализации расходятся и в деталях могут «спотыкаться»
Нас именно интересуют уязвимости на низких уровнях протокола (L1/L2). На это довольно много причин, эти уровни не шифруются и не аутентифицируются, модем также обязан обрабатывать фреймы ещё до того, как сеть решит, доверять ли источнику. Значит, атакующий может сформировать один "правильный" единственный радиопакет, который вызовет краш модема — или, при удачном стечении обстоятельств, RCE.
Исследование KAIST (2025) показало, что специально сформированный пакет может полностью «уронить» коммуникационный процессор смартфона.
В 2024-м был продемонстрирован рабочий RCE на модемах Samsung через баг в RLC reassembly, уязвимость классифицирована как переполнение буфера при сборке данных.
Модем (baseband) является привлекательным вектором атаки, потому что именно он первым обрабатывает радиосигнал, ещё до включения шифрования и аутентификации, что позволяет злоумышленнику доставить некорректный кадр напрямую в парсер протокола без участия пользователя. Атака возможна полностью «по воздуху», без взаимодействия жертвы, а радиус действия может варьироваться от сантиметров в экранированной лаборатории до сотен метров в реальных условиях. Baseband работает с высокими привилегиями, имеет доступ к памяти и управляет связью, поэтому его компрометация открывает путь к эскалации на application-процессор или как минимум к перехвату и саботажу связи. Кодовая база модема огромна, сложна и разнородна у разных вендоров, что повышает вероятность ошибок обработки границ, переполнений и рассинхронизаций состояния, а защитные механизмы (ASLR, NX, stack canaries) исторически внедрены неполностью или слабо. Логи baseband труднодоступны, EDR и антивирусы их не видят, а сбои часто воспринимаются как «глюки сети», что усложняет детекцию атак. Дополнительно усугубляет ситуацию медленный цикл обновлений — патчи зависят от вендора чипсета, OEM и оператора, а миллиарды устройств остаются уязвимыми годами. Даже без RCE атака на модем может приводить к DoS, трекингу или даунгрейду связи, что уже серьёзно для жертвы. Всё это делает baseband одним из самых мощных и опасных векторов атаки
Но также стоит обсудить ограничения и сложности которые мы сейчас имеем:
1. Разнообразие архитектур модемов
Baseband-процессоры от разных вендоров (Qualcomm, Samsung, MediaTek, HiSilicon) используют разные RTOS, разные форматы прошивок и разные реализации протоколов. Эксплойт, работающий на одной платформе, почти наверняка не будет переносим на другую — его придётся адаптировать под конкретный SoC. Более того, даже внутри одного вендора разные поколения чипов (Snapdragon 855 vs Snapdragon 8 Gen 3) имеют разные адресные пространства, разные схемы защиты памяти (ASLR/NX/CFI) и различную обработку сигнализации.
2. Сложность поиска уязвимости
Ошибки на L1/L2 редки и сложны для воспроизведения. Требуется глубокое понимание 3GPP-спецификаций, синхронизации состояния протокола и структуры кадров. Случайный фаззинг почти всегда отбрасывается модемом на раннем этапе.
3. Сложность эксплуатации
Даже после нахождения бага нужна полноценная эксплуатация: подготовка ROP-цепочек, обход ASLR, работа с ограниченным временем исполнения. Payload приходится загружать многоэтапно.
4. Риск нестабильности
Некорректные пакеты могут приводить к крашу модема или его soft-brick, что в реальных условиях может «вывести» устройство из строя, а не дать доступ к трафику.
Хотя все перечисленные ограничения выглядят пугающе на практике при достаточном времени, систематичности и усидчивости каждое из них преодолевается, барьеры носят инженерный, а не фундаментальный характер. Всё сводится к методичной работе: сначала стенд, потом воспроизводимый баг, потом PoC. Именно это сочетание сложности и достижимости делает исследования baseband такими увлекательными — они требуют и знаний, и терпения, и творческого подхода.
Глава 0.2 Создание лабораторного стенда
Основная задача стенда — создать среду, в которой можно генерировать, мутировать и отправлять радиокадры на тестовый UE, наблюдать реакцию модема, локализовать баги и перейти от краша к контролируемому чтению памяти.
Это предполагает три направления работы:
В качестве основной SDR-платформы выбран USRP B210 — дуплексный приёмопередатчик с полосой до 56 МГц и поддержкой диапазонов LTE (700–2700 МГц).
Для стабильной работы необходим:
3. Модифицируем стек под наши больные фантазии
Реализации srsRAN написаны на C/C++, чтобы обеспечивать эффективность и использовать оптимизации компилятора и архитектуры. Компиляция занимает от нескольких минут до часов, поэтому по возможности любые модификации PDU лучше делать вне самого стека RAN. Основная идея модификаций — вытащить «сырые» PDU с максимально низкого уровня (уровень MAC), пересылать их в Python через очередь ZeroMQ, а затем — обратно в драйвер SDR через другую очередь ZMQ.
Такой подход позволяет один раз скомпилировать реализацию RAN, а дальше переключаться между:
Чтобы всё заработало, нужно скачать исходный код реализации RAN, которую вы планируете использовать, и найти файлы обработки PDU для eNB/gNB.
В srsRAN они называются:
Два сокета на портах 5550 и 5557 используются для передачи данных в Python и получения обратно модифицированных или «прозрачно» пропущенных данных.
Далее модифицируется функция, которая добавляет MAC-заголовок к финальному пакету перед передачей на PHY и драйвер SDR.
В srsRAN она называется
В
Вся схема должна выглядеть как то так:
После того как мы начали получать полные MAC-PDU и можем их изменять, «мир открыт» — можно делать всё, что угодно, вот базовые примеры для разминки:
На этом пока все, в следущих частях мы займемся реверсом прошивки модема, найдем интересные уязвимости, а потом на основе нашего стенда будем пытатся их эксплуатировать удаленно, а пока я буду рад любым обсуждениям и вопросам.
Приветствую всех, давно не виделись
Меня уже давно интересуют атаки на сотовые сети. Однако в современных реалиях большинство таких атак потеряли актуальность: 2G везде отключается, а именно с ним было связано большинство векторов атак. Я долго исследовал эту тему, и чего только не пробовал: side-channel атаки на SIM-карты по замерам потребления тока и дифференциальному анализу, атаки на операторские femtocell для получения доступа к внутренней сети оператора и многое другое. Но всё упирается в один ключевой элемент — злополучный ключ Ki.
Ключ Ki — это суть всей безопасности и настоящий «грааль» современных сотовых сетей. Его записывают на SIM-карту так, чтобы даже физически извлечь его было почти невозможно, в защитные меры входит: рандомизация напряжения во время операций, защита от лазерного считывания и другие меры. Брутфорс и криптоанализ этого ключа через посыл рандомных чисел не имеет смысла: во-первых, SIM-карта просто блокируется после определённого количества неверных запросов, а во-вторых, даже квантовые алгоритмы будут подбирать его слишком долго.
По замыслу архитекторов сети, этот ключ никогда не покидает SIM-карту. Он используется для связывания с случайным числом, которое присылает базовая станция, имеющая доступ к HSS. Сеть выполняет ту же операцию у себя, сравнивает результат, и если они совпадают — аутентификация успешна, сеть считается доверенной. В отличие от GSM, обойти такую аутентификацию невозможно: без знания Ki нельзя заставить телефон подключиться к своей eNodeB. Соответственно, перехват SMS и звонков для «обычного исследователя» невозможен. И если у государственных структур с доступом к Diameter ещё есть возможность извлечь ключ KASME (один из сеансовых ключей), то для обычного
Но нам этот Ki не так то больно и нужен, если нужда только в пассивном перехвате траффика то будет хватать и session KASME ключа, и к нашему ограниченому счатью его вполне можно достать, если попасть куда надо.
Зачем нужен KASME:
KASME — это корневой сеансовый ключ LTE, из которого выводятся ключи KeNB (для защиты радиоканала), KNASenc/KNASint (для шифрования и целостности NAS) и ключи для дальнейших хэндоверов. Получив KASME, атакующий может:
- Расшифровывать весь пользовательский трафик LTE-сессии в реальном времени.
- Подделывать сигнальные сообщения (NAS/RRC) и отправлять их от имени абонента.
- Проводить MitM-атаки, изменяя или блокируя пакеты до того, как они поступят на application-уровень.
Срок действия ключа:
KASME генерируется при каждой процедуре аутентификации (Attach, TAU, периодическая re-authentication) и обычно действует до следующего обновления сеанса или до выхода устройства из сети. В среднем ключ остаётся валидным до нескольких часов (в зависимости от политики оператора и настроек таймеров T3412/T3402). Это означает, что успешное считывание KASME даёт атакующему «окно возможностей» на всё время жизни текущей сессии, пока телефон не выполнит повторный AKA и не получит новый KASME.
Самое прекрасное это то что после аунтефикации, этот ключ сидит в памяти бейсбенда, и имея к нему доступ нам достаточно просто записивать разшифрованый траффик и любоватся
Целью этой серии статтей является разработка и апробация методики удалённого чтения сеансового ключа KASME из памяти baseband без знания Ki и без завершённой AKA, воздействуя на обработчики, которые принимают кадры/сообщения до включения защиты.
В общем надо думать причем довольно нестандартно, как в известной цитате:
Глава 0.1 Почему именно low-level и модем как вектор?
В 3G/4G аутентификация двухсторонняя, однако сигнальные уязвимости сохранялись: ошибки в NAS/RRC-процедурах (Attach/TAU, RRC Setup/Reconfiguration), приводившие к утечке идентификаторов/DoS на реализациях отдельных вендоров. Эти аспекты хорошо документируются стандартами 3GPP (например, TS 36.331 для RRC и TS 24.301 для NAS), но конкретные реализации расходятся и в деталях могут «спотыкаться»
Нас именно интересуют уязвимости на низких уровнях протокола (L1/L2). На это довольно много причин, эти уровни не шифруются и не аутентифицируются, модем также обязан обрабатывать фреймы ещё до того, как сеть решит, доверять ли источнику. Значит, атакующий может сформировать один "правильный" единственный радиопакет, который вызовет краш модема — или, при удачном стечении обстоятельств, RCE.
Исследование KAIST (2025) показало, что специально сформированный пакет может полностью «уронить» коммуникационный процессор смартфона.
В 2024-м был продемонстрирован рабочий RCE на модемах Samsung через баг в RLC reassembly, уязвимость классифицирована как переполнение буфера при сборке данных.
Модем (baseband) является привлекательным вектором атаки, потому что именно он первым обрабатывает радиосигнал, ещё до включения шифрования и аутентификации, что позволяет злоумышленнику доставить некорректный кадр напрямую в парсер протокола без участия пользователя. Атака возможна полностью «по воздуху», без взаимодействия жертвы, а радиус действия может варьироваться от сантиметров в экранированной лаборатории до сотен метров в реальных условиях. Baseband работает с высокими привилегиями, имеет доступ к памяти и управляет связью, поэтому его компрометация открывает путь к эскалации на application-процессор или как минимум к перехвату и саботажу связи. Кодовая база модема огромна, сложна и разнородна у разных вендоров, что повышает вероятность ошибок обработки границ, переполнений и рассинхронизаций состояния, а защитные механизмы (ASLR, NX, stack canaries) исторически внедрены неполностью или слабо. Логи baseband труднодоступны, EDR и антивирусы их не видят, а сбои часто воспринимаются как «глюки сети», что усложняет детекцию атак. Дополнительно усугубляет ситуацию медленный цикл обновлений — патчи зависят от вендора чипсета, OEM и оператора, а миллиарды устройств остаются уязвимыми годами. Даже без RCE атака на модем может приводить к DoS, трекингу или даунгрейду связи, что уже серьёзно для жертвы. Всё это делает baseband одним из самых мощных и опасных векторов атаки
Но также стоит обсудить ограничения и сложности которые мы сейчас имеем:
1. Разнообразие архитектур модемов
Baseband-процессоры от разных вендоров (Qualcomm, Samsung, MediaTek, HiSilicon) используют разные RTOS, разные форматы прошивок и разные реализации протоколов. Эксплойт, работающий на одной платформе, почти наверняка не будет переносим на другую — его придётся адаптировать под конкретный SoC. Более того, даже внутри одного вендора разные поколения чипов (Snapdragon 855 vs Snapdragon 8 Gen 3) имеют разные адресные пространства, разные схемы защиты памяти (ASLR/NX/CFI) и различную обработку сигнализации.
2. Сложность поиска уязвимости
Ошибки на L1/L2 редки и сложны для воспроизведения. Требуется глубокое понимание 3GPP-спецификаций, синхронизации состояния протокола и структуры кадров. Случайный фаззинг почти всегда отбрасывается модемом на раннем этапе.
3. Сложность эксплуатации
Даже после нахождения бага нужна полноценная эксплуатация: подготовка ROP-цепочек, обход ASLR, работа с ограниченным временем исполнения. Payload приходится загружать многоэтапно.
4. Риск нестабильности
Некорректные пакеты могут приводить к крашу модема или его soft-brick, что в реальных условиях может «вывести» устройство из строя, а не дать доступ к трафику.
Хотя все перечисленные ограничения выглядят пугающе на практике при достаточном времени, систематичности и усидчивости каждое из них преодолевается, барьеры носят инженерный, а не фундаментальный характер. Всё сводится к методичной работе: сначала стенд, потом воспроизводимый баг, потом PoC. Именно это сочетание сложности и достижимости делает исследования baseband такими увлекательными — они требуют и знаний, и терпения, и творческого подхода.
Глава 0.2 Создание лабораторного стенда
Основная задача стенда — создать среду, в которой можно генерировать, мутировать и отправлять радиокадры на тестовый UE, наблюдать реакцию модема, локализовать баги и перейти от краша к контролируемому чтению памяти.
Это предполагает три направления работы:
- Инфраструктурное: железо + софт (SDR, eNB, EPC, мониторинг).
- Реверсное: анализ прошивки, поиск интересных функций и структур.
- Динамическое: фаззинг и последующая эксплуатация.
В качестве основной SDR-платформы выбран USRP B210 — дуплексный приёмопередатчик с полосой до 56 МГц и поддержкой диапазонов LTE (700–2700 МГц).
Для стабильной работы необходим:
- ПК с USB 3.0, 4+ ядерным CPU (Ryzen 5/Intel i5), 16 ГБ ОЗУ;
- аттенюаторы (например, 30 dB), чтобы избежать перегрузки входов при прямом подключении модема;
- экранированная среда (Faraday cage) или направленные антенны, чтобы не мешать сетям оператора нашими кривыми попытками.
- тестовый телефон с инженерной SIM (известный Ki), подключённый через кабель в экранированной коробке.
- Внешний OCXO/GPSDO, для длительного слежения без дрифта частоты.
2. Выбор стека
srsRAN (бывший srsLTE) остаётся оптимальным решением для ресёрча:- поддерживает полный стек LTE (eNodeB + EPC + UE);
- легко компилируется из исходников и модифицируется;
- имеет понятные конфигурационные файлы и API для автоматизации.
Bash:
git clone https://github.com/srsRAN/srsRAN_4G.git
cd srsRAN_4G
mkdir build
cd build
cmake ../
make
make test
sudo make install
srsran_install_configs.sh user
3. Модифицируем стек под наши больные фантазии
Реализации srsRAN написаны на C/C++, чтобы обеспечивать эффективность и использовать оптимизации компилятора и архитектуры. Компиляция занимает от нескольких минут до часов, поэтому по возможности любые модификации PDU лучше делать вне самого стека RAN. Основная идея модификаций — вытащить «сырые» PDU с максимально низкого уровня (уровень MAC), пересылать их в Python через очередь ZeroMQ, а затем — обратно в драйвер SDR через другую очередь ZMQ.
Такой подход позволяет один раз скомпилировать реализацию RAN, а дальше переключаться между:
- прозрачной пересылкой трафика (pass-through),
- и любыми изменениями PDU на любом из уровней OSI.
Чтобы всё заработало, нужно скачать исходный код реализации RAN, которую вы планируете использовать, и найти файлы обработки PDU для eNB/gNB.
В srsRAN они называются:
- pdu.h (
/lib/include/srsran/mac/) - pdu.cc (
/lib/src/mac/)
4. Модифицируем pdu.h
В начало заголовочного файла добавляется новая функция:
C++:
int init_zmq();
5. Модифицируем pdu.cc
В начало файла добавляются контекстные переменные и реализация функцииinit_zmq:
C++:
namespace srsran {
zmq::context_t zmq_ctx_push;
zmq::socket_t zmq_sock_push(zmq_ctx_push, zmq::socket_type::push);
static const char* zmq_args_push = "tcp://127.0.0.1:5550";
zmq::context_t zmq_ctx_pull;
zmq::socket_t zmq_sock_pull(zmq_ctx_pull, zmq::socket_type::pull);
static const char* zmq_args_pull = "tcp://127.0.0.1:5557";
int init_zmq()
{
zmq_sock_push.bind(zmq_args_push);
zmq_sock_pull.connect(zmq_args_pull);
return 0;
}
}
Два сокета на портах 5550 и 5557 используются для передачи данных в Python и получения обратно модифицированных или «прозрачно» пропущенных данных.
Далее модифицируется функция, которая добавляет MAC-заголовок к финальному пакету перед передачей на PHY и драйвер SDR.
В srsRAN она называется
sch_pdu::write_packet. В конце функции добавляется:
C++:
zmq::message_t zmq_msg;
zmq_sock_push.send(zmq::message_t((void**)buffer_tx->msg, buffer_tx->N_bytes), zmq::send_flags::dontwait);
zmq_sock_pull.recv(zmq_msg, zmq::recv_flags::none);
return static_cast<uint8_t*>(zmq_msg.data());
6. Инициализация ZMQ
В
main.cc нужно инициализировать очереди ZMQ:
C++:
if (srsran::init_zmq()) {
cout << "Error INITIALIZING ZEROMQ" << endl << endl;
}
else {
cout << "ZMQ Fuzzing socket created" << endl << endl;
}
Вся схема должна выглядеть как то так:
После того как мы начали получать полные MAC-PDU и можем их изменять, «мир открыт» — можно делать всё, что угодно, вот базовые примеры для разминки:
RRC ConnectionSetup
RRC ConnectionSetup — одно из критических начальных сообщений, которое содержит настройки DCCH и позволяет UE перейти в RRC Connected.
Python:
#Fuzzing RRC ConnectionSetup package
if b'\x60\x12\x9b' in message:
loc = message.find(b'\x60\x12\x9b')
pdu = message[:loc]
sdu = message[loc:]
fuzzed = rad.fuzz(sdu) # опционально seed
p1 = pdu[0:2]
pduLength = len(pdu+fuzzed)
p2 = pdu[3:]
assembled = p1+pduLength.to_bytes(1,'little')+p2+fuzzed[0:1]+len(fuzzed).to_bytes(1,'little')+fuzzed[2:]
pushSocket.send(assembled)
fh.write(f"{now} | rd | {assembled} \r\n")
fh.flush()
print(now, "Fuzzed packet sent")
DLInformationTransfer, Security Mode Command
Python:
#Fuzzing DLInformationTransfer, Security Mode Command
if b'\x08\x00\x81' in message:
loc = message.find(b'\x08\x00\x81')
pdu = message[:loc]
sdu = message[loc:]
fuzzed = rad.fuzz(sdu)
p1 = pdu[0:1]
pduLength = len(pdu+fuzzed)
p2 = pdu[2:]
assembled = p1+pduLength.to_bytes(1,'little')+p2+fuzzed
pushSocket.send(assembled)
fh.write(f"{now} | rd | {assembled} \r\n")
fh.flush()
print(now, "Fuzzed packet sent")
DLInformationTransfer, Auth Request
Python:
#Fuzzing DLInformationTransfer, Auth request package
if b'\x08\x01\x20' in message:
loc = message.find(b'\x08\x01\x20')
pdu = message[:loc]
sdu = message[loc:]
fuzzed = rad.fuzz(pdu)
p1 = fuzzed[0:1]
pduLength = len(fuzzed+sdu)
p2 = fuzzed[2:]
assembled = p1+pduLength.to_bytes(1,'little')+p2+sdu
pushSocket.send(assembled)
fh.write(f"{now} | rd | {assembled} \r\n")
fh.flush()
print(now, "Fuzzed packet sent")
На этом пока все, в следущих частях мы займемся реверсом прошивки модема, найдем интересные уязвимости, а потом на основе нашего стенда будем пытатся их эксплуатировать удаленно, а пока я буду рад любым обсуждениям и вопросам.
Последнее редактирование: