Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2024-20154 — Технический разбор CVE-2024-20154 | Kitploit
Инструменты/GitHubGitHub/sneakid/cve-2024-20154
Безопасность встроенных системБезопасность IoTАнализ уязвимостейЭксплуатацияОбратная инженерияМобильная безопасностьСтатьи и ИсследованияОбучение и ОбразованиеАнализ ПрошивокЭксплуатация Бинарных Файлов
GitHubsneakid/cve-2024-20154
212 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2024-20154

Технический разбор CVE-2024-20154

Репозиторий

CVE-2024-20154: Переполнение стека в NB-IoT SIB1-NB в модеме MediaTek MT6769

Классификация: CWE-121 — переполнение буфера на основе стека
Серьёзность: Critical (бюллетень MediaTek) · 8.8 High, вектор атаки: Adjacent (CISA-ADP)
Тип: Удалённое выполнение кода — без взаимодействия с пользователем, без предварительной ассоциации
Раскрытие: Бюллетень безопасности MediaTek, 6 января 2025 г. https://corp.mediatek.com/product-security-bulletin/January-2025 Проанализированная цель: Samsung Galaxy A14 SM-A145R — семейство MT6769 (Helio G80), входит в список затронутых чипсетов MediaTek — прошивка была эмулирована в безопасных условиях. Статус: Исправлено.


Предпосылки и мотивация

Это моё первое опубликованное исследование модема. Мой опыт далёк от телекоммуникационной инфраструктуры, слоёв посредничества для законного перехвата, анализа стингреев и IMSI-ловушек, а также от безопасности встраиваемых устройств — ранее я не занимался глубоким реверс-инжинирингом прошивки сотового модема. Я хотел доказать себе, что структурированная аналитическая методология адаптируется к разным целям и что знакомство с конкретной платформой можно заменить строгим отслеживанием цепочек. NB-IoT выделялся тем, что находится на по-настоящему опасном пересечении: протокол предназначен для ограниченных IoT-устройств, поверхность атаки расположена до установления ассоциации, а стек модема обрабатывает его независимо от того, что делает пользователь телефона.

Когда была проанализирована исправленная прошивка и подтверждено отсутствие уязвимого паттерна, ИИ-система, использовавшаяся для массового анализа прошивки перед нацеливанием на конкретные функции

независимо сопоставила реконструированный класс ошибки, условия и затронутое семейство прошивок с описанием CVE-2024-20154.

Технические выводы принадлежат самому аналитику.


1. Введение

Телефон в вашем кармане содержит как минимум два отдельных компьютера. Тот, с которым вы взаимодействуете, работает под управлением Android. Другой — модем — работает полностью независимо, обрабатывает всю радиосвязь и почти полностью невидим для операционной системы над ним. Android может быть полностью пропатчен. Браузер может быть изолирован в песочнице. Пользователь может никогда не нажать на вредоносную ссылку. Всё это не имеет значения, если уязвимый код находится в прошивке модема, обрабатывающей радиосигналы до того, как в процесс задействуется прикладной процессор.

CVE-2024-20154 — именно такая уязвимость.

Некорректная широковещательная передача системной информации NB-IoT заставляет прошивку модема MediaTek принять контролируемое атакующим значение счётчика планирования, провести его через путь конфигурации RRC-to-L1 без какого-либо ограничения и в конечном итоге использовать его как границу цикла для записи в стек внутри обработчика широковещательного канала NB-IoT. Когда счётчик превышает ёмкость целевых массивов, цикл выходит за их пределы, достигает сохранённых регистров в стеке и перезаписывает сохранённый обратный адрес. Затем функция восстанавливает повреждённое значение в регистре обратного адреса и переходит по нему.

Что определяет серьёзность:

  • Уязвимый путь кода задействуется во время дежурства в соте — после синхронизации с сотой, но до любого RRC-соединения, аутентификации или взаимодействия с пользователем.
  • Входные данные — это эфирная широковещательная передача. Телефон не может аутентифицировать источник.
  • Прошивка модема в проанализированной сборке работает без ASLR, без канареек стека, без неисполняемого стека и без контроля целостности потока управления. Перезапись сохранённого обратного адреса напрямую приводит к контролю над программным счётчиком.

Уязвимость была опубликована в бюллетене безопасности MediaTek от 6 января 2025 года с критической степенью серьёзности, затрагивая среди прочих семейство модемов LR12A. Samsung включила исправление в свой выпуск обновлений безопасности за февраль 2025 года.

В этом посте не публикуется боевой эксплойт, и он не воспроизводим на основе опубликованного здесь. Цель — показать, где рвётся цепочка, почему каждый уровень не смог её остановить, и что требуется для ответственной проверки ошибки модема, когда невозможно подключить отладчик к работающему модему.


2. Цель и среда

2.1 Устройство и прошивка

Основная цель: Samsung Galaxy A14 (SM-A145R). Радиоподсистема управляется процессором модема MediaTek из семейства чипсетов MT6769 (Helio G80). Семейство MT6769 явно указано в списке затронутых чипсетов MediaTek для CVE-2024-20154.``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18

root@kitploit:~
Прошивка baseband — это не код Android. Это отдельная встроенная система в радиоподсистеме SoC с собственным CPU, собственной RTOS и собственным адресным пространством, вне песочницы процессов Android.

### 2.2 Архитектура модема

Анализ извлечённого бинарного файла показывает, что процессор модема работает на MIPS32 со сжатыми инструкциями MIPS16e2 в режиме little-endian. MIPS16e2 — это 16-битное расширение кодирования для уменьшения размера кода во встраиваемых системах — что согласуется с подходом MediaTek для модемов поколения Helio и подтверждается независимыми опубликованными исследованиями baseband этого семейства SoC.

Операционная система — Nucleus RTOS, обеспечивающая планирование задач, очереди сообщений IPC и распределитель памяти на основе пулов. Здесь нет разделения привилегий ядро/пользователь, нет принудительного применения модуля защиты памяти (MPU) между задачами и нет аппаратного механизма защиты стека.

Все адреса в этом посте являются виртуальными адресами, как они загружены в Ghidra по базе `0x90000000`.

### 2.3 Механизмы защиты (наблюдаемые в проанализированной сборке)

| Механизм защиты | Статус | Эффект |
|---|---|---|
| ASLR | Отсутствует | Адреса прошивки статичны и предсказуемы из образа |
| Stack canary | Отсутствует | `SAVE`/`RESTORE` сохраняют регистры вызываемой функции без контрольного значения |
| NX / W^X | Отсутствует | Память стека исполняемая |
| CFI | Отсутствует | Адреса возврата не проверяются на соответствие какой-либо политике |

### 2.4 Методика анализа

Три параллельных направления:

**Статический анализ.** Пакет прошивки Samsung → извлечение раздела CP → `md1img.img` → Ghidra (MIPS LE 32-bit, база `0x90000000`) с инженерными символами MediaTek, восстановленными из отладочной секции прошивки с помощью набора инструментов NCC Group `mtk_bp`.

**Динамическая проверка.** Unicorn Engine (эмуляция MIPS32) использовался для изолированного выполнения конкретных подпрограмм прошивки в два этапа. Этап 1 пытался доказать неограниченное копирование `si_count` в контекст канала через нативную пару инструкций. Этап 2 выполнял уязвимый цикл на реальных байтах прошивки и подтвердил, что собственные инструкции прошивки повреждают сохранённый адрес возврата. Там, где Этап 1 не мог быть выполнен полностью нативно — поскольку среда сервисных объектов RTOS, требуемая путём диспетчеризации CPHY, не была восстановлена — побочный эффект моделировался напрямую и помечался как таковой во всех выводах.

**Проверка на радиостороне.** srsRAN 4G с loopback через ZMQ — только программное обеспечение, без радиоизлучения — подтвердил, что тестовая полезная нагрузка корректно проходит кодирование PHY NB-IoT и доставку транспортного блока.

---

## 3. Поверхность атаки: NB-IoT и SIB1-NB

### 3.1 Поверхность атаки до установления соединения

NB-IoT (Narrowband Internet of Things, узкополосный интернет вещей) — это 3GPP Release 13, разработанный для подключения устройств с ограниченными ресурсами с использованием существующего лицензированного LTE-спектра. Он реализован в широком диапазоне современных сотовых SoC, включая те, что находятся в потребительских смартфонах.

Находясь в состоянии RRC_IDLE, до установления любого RRC-соединения, устройство, выполняющее поиск сети, будет:

1. Синхронизироваться с сигналами синхронизации соты (NPSS/NSSS)
2. Декодировать Master Information Block (MIB) через NPBCH (окно передачи 640 мс)
3. Декодировать SIB1-NB из NPDSCH (расписание 2560 мс)
4. Использовать информацию планирования в SIB1-NB для поиска дополнительных блоков системной информации

На шаге 3 модем обрабатывает сообщение от сущности, которую он не аутентифицировал, до установления любого соединения или взаимодействия с пользователем. Недобросовестный передатчик, удовлетворяющий обычным условиям выбора соты, будет обработан.```
+------------------+                   +---------------------+
|  Rogue Base Stn  |                   |  Target UE (Modem)  |
+--------+---------+                   +----------+----------+
         |                                        |
         |   NPSS/NSSS sync                      |
         |--------------------------------------->|
         |   MIB-NB (640 ms cycle)                |
         |--------------------------------------->|
         |   SIB1-NB (malformed, si_count > 8)    |
         |--------------------------------------->|   ← vulnerability triggered
         |   [no RRC connection established]      |

3.2 Поле счётчика планирования

SIB1-NB определён в 3GPP TS 36.331. Его поле schedulingInfoList указывает, сколько сообщений системной информации передаёт сота; спецификация ограничивает максимум до 8 записей (1..maxSI-Message-NB-r13 = 8). Это ограничение уровня протокола. Ограничение безопасности памяти — а именно, что длина списка не должна превышать ёмкость целевых массивов — должно применяться отдельно прошивкой.

Этого не было.


4. Извлечение прошивки и восстановление символов

Прошивка была получена из пакета Samsung CP и извлечена с помощью набора инструментов NCC Group mtk_bp:``` md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image) → 017_md1_dbginfo (XZ-compressed CATI debug symbols)

root@kitploit:~
The CATI debug section was decompressed and parsed with `mtk_dbg_extract.py symbols`, then
imported into Ghidra via `ImportSymbolsScript.py`. The result was full internal function
names throughout the modem stack — ERRC layer, L1 channel management, IPC subsystem, and the
NB-IoT BCCH handler chain — allowing semantics-guided chain reconstruction.

All function names in this post come from MediaTek's own embedded debug symbols extracted
from the firmware image.

---

## 5. Уязвимость

### 5.1 Уязвимый цикл

`el1_ch_nbcch_resume_req` (`0x90213940`) обрабатывает событие возобновления широковещательного канала NB-IoT.
Его пролог функции MIPS16e2:```asm
90213940:  save  0xE8, ra, s0-s1

Инструкция SAVE уменьшает sp на 0xE8 и сохраняет callee-saved регистры вниз:``` old_sp (= new_sp + 0xE8) new_sp + 0xE4 saved ra ← overflow target new_sp + 0xE0 saved s1 new_sp + 0xDC saved s0 new_sp + 0x98 si_sched_arr [34 halfwords = 68 bytes] new_sp + 0x78 si_type_arr [32 bytes] new_sp + 0x00 ← stack pointer after SAVE

root@kitploit:~
Из декомпиляции Ghidra фактического бинарного файла прошивки:```c
for (uVar6 = 0; uVar6 < (byte)param_2[0x40a]; uVar6 = uVar6 + 1) {
    si_type_arr[uVar6]  = /* SI type byte */;          // 1 byte/iter, base new_sp+0x78
    si_sched_arr[uVar6] = /* SI schedule halfword */;  // 2 bytes/iter, base new_sp+0x98
}

param_2[0x40a] — это ch_ctx[+0x40A] — постоянный байт в BSS-структуре контекста канала. Граница цикла используется напрямую, без предварительного сравнения с ёмкостями массивов.

5.2 Арифметика переполнения

Поток A (записи полуслов sh) начинается с new_sp+0x98 и продвигается на 2 байта за итерацию. Он достигает сохранённого RA по адресу new_sp+0xE4 на итерации 38:``` new_sp + 0x98 + i×2 = new_sp + 0xE4 i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38

root@kitploit:~
Поток B (записи байта `sb`) начинается с `new_sp+0x78` и потребует 108-й итерации, чтобы достичь слота RA:```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108

При si_count = 40 (демонстрационное значение, выбранное, чтобы превысить порог переполнения 38) цикл выполняется 40 итераций. Поток B никогда не достигает слота RA. Повреждение RA полностью вызвано потоком A.

После 40 итераций инструкция MIPS16e2 RESTORE перезагружает повреждённое значение из стека в $ra, и jrc ra передаёт управление.

5.3 Копия без ограничений — слой B

ch_ctx[+0x40A] записывается функцией el1_ch_nbcch_start по адресу 0x90213444. Две последовательные инструкции MIPS, между которыми ничего нет:```asm ; el1_ch_nbcch_start @ 0x90213444 lbu v0, 0x99(s0) ; read IPC_msg[+0x99] = si_count from CPHY_CFG_REQ sb v0, 0x40A(s1) ; write to ch_ctx[+0x40A] — no clamp, no mask, no compare

root@kitploit:~
### 5.4 Построитель ERRC — уровень A

Буфер CPHY_CFG_REQ строится в уровне ERRC на основе декодированного SIB1-NB. Функция
`errc_chm_l1_set_bcch_si_reception` записывает `IPC_msg[+0x99]`:```c
// errc_chm_l1_set_bcch_si_reception — Layer A
// Loop bound: decoded schedulingInfoList entry count from SIB1-NB

while (bVar3 < *(byte *)(param_3 + 0x44) && (param_2 != 0)) {
    bVar3++;
    if (uVar2 != param_2) {
        *param_5 = *param_5 + 1;   // CPHY_CFG_REQ[+0x99]++ — no upper bound check
    }
}

Граница цикла — это количество декодированных записей из SIB1-NB. Счётчик увеличивается один раз на каждую декодированную запись, для всех записей, которые были декодированы, без ограничения максимума.

5.5 Путь IPC

Как только буфер CPHY_CFG_REQ заполнен, ERRC отправляет его в L1 с sap_id = 0x501F в качестве ключа маршрутизации:``` el1_ch_rcv_ilm (sap 0x501F) → el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C] → el1_chmgm_nbcch_handler → el1_ch_nbcch_main → el1_ch_nbcch_cphy_cfg_req_process ← validates cell identity, no si_count check → el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp

root@kitploit:~
### 5.6 Отсутствие ограничения на трёх уровнях

| Уровень | Функция | Адрес | Ограничение есть? |
|---|---|---|---|
| A — построитель ERRC | `errc_chm_l1_set_bcch_si_reception` | Диапазон ERRC | **Нет** |
| B — копия L1 | `el1_ch_nbcch_start` | `0x90213444` | **Нет** |
| C — цикл L1 | `el1_ch_nbcch_resume_req` | `0x90213940` | **Нет** |

Любая отдельная проверка на любом из уровней разорвала бы цепочку.

### 5.7 Корневая причина

Одно нарушенное инвариантное правило:

> Количество записей планирования SI никогда не должно превышать ёмкость массива назначения.

3GPP предоставляет предполагаемую границу протокола (8 записей). Прошивка должна была обеспечивать границу безопасности памяти на каждом уровне, где количество становится индексом или пределом цикла. В уязвимой сборке количество передавалось из широковещательного поля SIB1-NB через декодер ERRC в сообщение CPHY_CFG_REQ, через границу IPC в задачу L1, в контекст канала BSS и в цикл записи в стек — без какого-либо ограничения на этих уровнях.

---

## 6. Цепочка вызовов — как это было найдено

### 6.1 Путаница двух путей

Два структурно похожих, но различных пути могут доставить буфер конфигурации размером 0x760 байт в `el1_ch_nbcch_main`:

| Путь | Источник | `[+0x99]` значение | Значимость |
|---|---|---|---|
| Путь A (ERRC → L1 IPC) | ERRC формирует CPHY_CFG_REQ из декодированного SIB1-NB | `schedulingInfoList.count` из OTA | **Уязвимый путь** |
| Путь B (внутренний L1) | `el1_ch_scs_ind_send` формирует внутреннее тело IPC | Жёстко заданный `1` | Не уязвим |

Путь B подтвердил формат сообщения — байт `+0x99` является количеством SI, потребляемым `el1_ch_nbcch_start`. Поскольку его значение всегда жёстко задано как 1, переполнение невозможно. Путь, подверженный внешнему влиянию, — это путь A.

### 6.2 Поиск записывающей инструкции

Поиск по шаблону в прошивке любой инструкции, записывающей в смещение `+0x99`, дал шум: T1 (прямая `sb`, ~100 совпадений), T2 (раздельная база, 5 совпадений), T3 (вычисленное смещение, 0), T4 (перекрывающиеся `sh`/`sw`, ~465). Функции управления каналом ERRC отсутствовали в списке перекрёстных ссылок `msg_send6`, поскольку ERRC использует `errc_com_send_msg`. Эмуляционный зонд подтвердил, что запись происходит на стороне ERRC: запуск обвязки Unicorn из диспетчера L1 и наблюдение за записью в смещение `+0x99` буфера не зафиксировали ничего со стороны L1.```
[RUN] dispatcher=0x90214418  watching IPC_msg+0x99

NO writes to IPC_msg+0x99 caught from dispatcher.
Write happened before el1_ch_nbcch_main — confirmed ERRC-side.

6.3 Определение через ключ маршрутизации IPC

Прослеживание sap_id = 0x501F в errc_com_send_msg позволило определить маршрутизацию к el1_chmgm_errc_cfg_req_in_idle, которая сохраняет указатель CPHY_CFG_REQ по адресу L1_ctx[+0x323C] и запускает последующую диспетчеризацию.

6.4 Подтверждённая цепочка вызовов```

SIB1-NB schedulingInfoList.count (demonstrator: 40) │ ▼ [ERRC task] errc_chm_ch_ctrl_req_hdlr → errc_chm_call_ctrl → errc_chm_l1_main → errc_chm_l1_call_ctrl → errc_chm_l1_snd_cphy_cfg_req ← allocates 0x760-byte CPHY_CFG_REQ → errc_chm_l1_set_cphy_req_nbcch_cfg → errc_chm_l1_set_bcch_inf → errc_chm_l1_set_bcch_si_reception ← Layer A: CPHY_CFG_REQ[+0x99] = 40 → errc_com_send_msg(sap=0x501F) ← IPC to L1 │ ▼ [L1 task] el1_ch_rcv_ilm (sap 0x501F) → el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C] → el1_chmgm_nbcch_handler → el1_ch_nbcch_main → el1_ch_nbcch_cphy_cfg_req_process ← no si_count validation → el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp │ ▼ ch_ctx[0x40A] = 40 (persists in BSS) │ ▼ [state machine advances to 0x0B, event 0x2C] el1_ch_nbcch_resume_req @ 0x90213940 ← Layer C: loop bound from ch_ctx[0x40A] │ ▼ stack overflow → jrc ra → PC = attacker-controlled

root@kitploit:~
---

## 7. Проверка

Похоже, что данная конкретная модель SM-A145R не задействует
уязвимый путь кода NB-IoT в обычном заводском режиме работы, поэтому вместо
прямого воспроизведения на оборудовании использовались гибридная эмуляция и статический анализ.

**Доказано статически.** В бинарном файле прошивки присутствует уязвимая пара инструкций. Цепочка
вызовов восстановлена по символам, перекрёстным ссылкам и декомпилированным телам функций.

**Исполнено нативно в эмуляции.** Цикл внутри `el1_ch_nbcch_resume_req` выполнялся на реальных
байтах прошивки MediaTek в Unicorn Engine (MIPS32). Собственная инструкция `sh` прошивки по адресу
`0x90213B02` записывала данные в слот сохранённого обратного адреса. Инструкция `RESTORE` загружала
повреждённое значение в `$ra`, а `jrc ra` передавала управление.

**Явно смоделировано.** Копирование через `lbu`/`sb` в `el1_ch_nbcch_start` не удалось полностью выполнить
нативно, поскольку путь диспетчеризации таблицы обратных вызовов RTOS внутри `el1_ch_nbcch_cphy_cfg_req_
process` ожидал живые объекты кучи Nucleus, которые плоский эмулятор не предоставлял. Обработчик
возобновления (`el1_ch_nbcch_resume_req`) в фазе 2 читает только из размещённого в BSS контекста канала
и не проходит через тот же путь диспетчеризации, поэтому фаза 2 выполнялась нативно без
необходимости в тех же вспомогательных конструкциях. Побочный эффект фазы 1 — один байт из `IPC_msg[+0x99]`,
записанный в `ch_ctx[+0x40A]`, — был смоделирован напрямую и помечен как `[PHASE1-MODEL]`.

**Не заявляется.** Полное сквозное воспроизведение атаки на реальном оборудовании через радиоэфир.

### 7.1 Защита от вмешательства

Тестовая обвязка обеспечивала выполнение одного правила: ни один хук не мог записывать маркер доказательства в слот
сохранённого обратного адреса. Каждая запись в память, выполняемая не прошивкой, отслеживалась.```
[PROOF-W] saved_RA write: pc=0x90213b02  addr=new_sp+0xE4  value=0xbeef
[PROOF-W] saved_RA write: pc=0x90213b02  addr=new_sp+0xE6  value=0xdead
[ANTI-TAMPER] no hook wrote RA=0xDEADBEEF — firmware only
anti_tamper_fail = False

0x90213B02 — это инструкция sh внутри тела цикла. Прошивка разместила эти байты по предсказанному смещению в стеке. При хранении в little-endian полу слова 0xBEEF и 0xDEAD по адресам new_sp+0xE4 и new_sp+0xE6 объединяются в [ef be ad de] = 0xDEADBEEF.

7.2 Результат эмуляции```

[REGS] RA = 0xdeadbeef ← firmware wrote this; decisive proof PC = 0x00000000 ← Unicorn unmapped-fetch artifact, not a hardware exception vector

[STACK] new_sp+0xE4: [ef be ad de] ← little-endian 0xDEADBEEF

[PC-EXPLAIN] PC=0 is an unmapped-fetch artifact; decisive proof is RA=0xDEADBEEF + stack bytes [ef be ad de] + [PROOF-JRC] CONFIRMED: saved RA = 0xDEADBEEF

root@kitploit:~
### 7.3 Доставка ZMQ

Чтобы подтвердить, что тестовый payload выдерживает кодирование NB-IoT PHY и доставку транспортных блоков, использовался srsRAN
4G с ZMQ loopback (без радиоизлучения). Payload был намеренно несоответствующим вектором — ограничение ASN.1 SIZE на `schedulingInfoList` было ослаблено, чтобы разрешить 40 записей, а повторное декодирование pycrate подтвердило поле счётчика на байте 14.```
SIB1 received
SIB2 activated
exit 0

Это подтверждает доставку на транспортном уровне. Поведение ASN.1 на стороне прошивки устанавливается статическим анализом Layer A.


8. Механика потока управления

8.1 Две фазы, одна задача, постоянное состояние

Задача el1_ch имеет один стек. Фаза 1 и Фаза 2 — это два отдельных IPC-события, обрабатываемых последовательно одной и той же задачей, при этом стек полностью разворачивается между ними. Счётчик сохраняется в BSS контекста канала, а не в стеке:``` EVENT: CPHY_CFG_REQ (Phase 1) el1_ch_nbcch_start lbu v0, 0x99(s0) sb v0, 0x40A(s1) ← ch_ctx[0x40A] = attacker value, written to BSS returns — stack fully unwound

EVENT: resume (state 0x0B, msg 0x2C) (Phase 2) el1_ch_nbcch_resume_req ← frame 0xE8, reads ch_ctx[0x40A] as loop bound loop × 40 → saved RA corrupted jrc ra → attacker-controlled PC

root@kitploit:~
`ch_ctx[0x40A]` находится в BSS и сохраняет значение атакующего до тех пор, пока модем не перезагрузится или последующая конфигурация канала не перезапишет его.

### 8.2 Стек-кадр```
old_sp  (= new_sp + 0xE8)
new_sp + 0xE4   saved ra
new_sp + 0xE0   saved s1
new_sp + 0xDC   saved s0
new_sp + 0x98   si_sched_arr  [34 halfwords = 68 bytes]
new_sp + 0x78   si_type_arr   [32 bytes]

Frame size confirmed by emulation measurement. Array positions confirmed by the emulation result — RA written at iteration 38, consistent with si_sched_arr starting at new_sp+0x98.


9. Evidence

9.1 Gates before the vulnerable loop

9.2 Functions confirmed not to clamp si_count


10. Patch Analysis

10.1 Versions

BuildModem firmwareBuild date
VulnerableA145RXXU1AWD1, MOLY LR12A...V1.P52023-04-18
PatchedA145RXXUDDZC2, MOLY LR12A...V3.P8

Build dates confirmed by extracting md1_dbginfo metadata from both images. Patch ID: MOLY00720348 · Issue ID: MSV-2392.

10.2 What changed

el1_ch_nbcch_start (0x90213444 in vulnerable binary): The lbu/sb instruction pair is absent. The direct copy of IPC_msg[+0x99] into ch_ctx[+0x40A] is gone.

el1_ch_nbcch_resume_req (0x90213940 in vulnerable binary): The stack-writing loop over ch_ctx[0x40A] is absent. The architecture where an untrusted byte becomes a loop bound over fixed-size stack arrays no longer exists. The function body is replaced with a different dispatch structure.

errc_chm_l1_set_bcch_si_reception: The unbounded counter loop is replaced with validation-oriented helper calls.

10.3 New validation functions

Two functions present in the patched binary are absent from the vulnerable binary:``` el1_ch_nbcch_param_check el1_ch_scell_param_check

root@kitploit:~
Однострочная проверка границ выглядела бы как несколько добавленных инструкций внутри существующей функции по тому же адресу. Что показывает пропатченный бинарник — это архитектурное изменение: путь планирования NBCCH был переработан так, что паттерн «`si_count` как граница цикла» больше нигде в этом пути не встречается.

### 10.4 Атрибуция CVE

Описанная здесь уязвимость соответствует CVE-2024-20154, опубликованной MediaTek 6 января 2025 года. Основания для подтверждения:

- Затронутое семейство прошивок (LR12A) соответствует бюллетеню MediaTek.
- Класс уязвимости — переполнение стека, отсутствие проверки границ, RCE с мошеннической базовой станции, без взаимодействия с пользователем — соответствует описанию CVE и записи NVD.
- Пропатченная прошивка удаляет именно те структуры кода, которые были определены как уязвимые.
- Идентификатор патча MOLY00720348 подтверждён бюллетенем MediaTek и Android Security Bulletin (A-376809176).
- Анализ с применением ИИ независимо сопоставил восстановленный паттерн с CVE-2024-20154 до ручного подтверждения.

---

## 11. Этика и ответственное раскрытие информации

### 11.1 Чего нет в этом посте

Никакого боевого эксплойта. Никакого содержимого бинарных файлов прошивки. Никаких байт повреждённой полезной нагрузки. Никакой пошаговой процедуры срабатывания уязвимости на реальном устройстве. Информация, необходимая для воспроизведения рабочей атаки — полная конструкция полезной нагрузки для конкретного декодера модема, каркас heap-объектов RTOS для полной эмуляции Phase 1, конфигурация радиоэфира — намеренно отсутствует.

### 11.2 Почему ZMQ loopback и эмуляция — этичный подход

ZMQ loopback означает, что ни один сигнал никогда не передавался в эфир. Ни одно реальное устройство не было целью. Ни одна сеть оператора не была задействована. Доказательство полностью выполняется в изолированной программной среде на оборудовании, принадлежащем аналитику. Это правильный подход для проверки радиоуязвимости до ассоциации — передача повреждённого широковещательного сообщения затронула бы любое устройство в зоне действия.

Эмуляция Unicorn показывает, что уязвимое поведение находится в самом бинарном файле прошивки, воспроизводимо, независимо от конкретного состояния устройства или радиоокружения. Это технически более сильное утверждение, чем одиночный сбой оборудования, и позволяет избежать развёртывания чего-либо в эфире.

### 11.3 Интеллектуальная собственность MediaTek

Весь анализ выполнялся на прошивке, легально полученной с потребительского устройства и из публично выпущенных пакетов прошивок Samsung. Никакая проприетарная документация не использовалась. Внутренние определения структур MediaTek и форматы IPC-сообщений описаны лишь в той степени, в какой это необходимо для объяснения отказа безопасности памяти. Они не публикуются в качестве спецификаций.

---
Скачать инструмент
ИтерацияКуда пишет shЭффект
0–33si_sched_arr[0..33]В границах
34–35new_sp+0xDC — saved s0s0 повреждён
36–37new_sp+0xE0 — saved s1s1 повреждён
38new_sp+0xE4 — saved ra [15:0]Младшее полуслово RA
39new_sp+0xE6 — saved ra [31:16]Старшее полуслово RA
GateConditionWhere checked
NB-IoT active pathcfg_type == 1el1_ch_nbcch_cphy_cfg_req_process
Channel not completedone_flag == 0ch_ctx[0x438]
State machine 0x0BNBCCH in resume stateel1_ch_nbcch_main dispatch
si_count nonzeroch_ctx[0x40A] > 0Loop condition
Band class ≤ 2Valid NB-IoT modeEntry of el1_ch_nbcch_resume_req
el1_chmgm_cell_info_get nonzeroCell in service tableCalled in el1_ch_nbcch_start
FunctionAddressRoleClamp?
errc_chm_l1_set_bcch_si_receptionERRC rangeWrites CPHY_CFG_REQ[+0x99]None
el1_ch_nbcch_cphy_cfg_req_process0x90213F80Routes CPHY config into L1N/A — does not read si_count
el1_chmgm_cell_info_get0x9020E0D0Validates EARFCN/PCIN/A
el1_ch_nbcch_start0x90213444Copies count to BSSNone
el1_ch_nbcch_resume_req0x90213940Uses count as loop boundNone
2025-04-23