
Технический разбор CVE-2024-20154
Классификация: 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.
Технические выводы принадлежат самому аналитику.
Телефон в вашем кармане содержит как минимум два отдельных компьютера. Тот, с которым вы взаимодействуете, работает под управлением Android. Другой — модем — работает полностью независимо, обрабатывает всю радиосвязь и почти полностью невидим для операционной системы над ним. Android может быть полностью пропатчен. Браузер может быть изолирован в песочнице. Пользователь может никогда не нажать на вредоносную ссылку. Всё это не имеет значения, если уязвимый код находится в прошивке модема, обрабатывающей радиосигналы до того, как в процесс задействуется прикладной процессор.
CVE-2024-20154 — именно такая уязвимость.
Некорректная широковещательная передача системной информации NB-IoT заставляет прошивку модема MediaTek принять контролируемое атакующим значение счётчика планирования, провести его через путь конфигурации RRC-to-L1 без какого-либо ограничения и в конечном итоге использовать его как границу цикла для записи в стек внутри обработчика широковещательного канала NB-IoT. Когда счётчик превышает ёмкость целевых массивов, цикл выходит за их пределы, достигает сохранённых регистров в стеке и перезаписывает сохранённый обратный адрес. Затем функция восстанавливает повреждённое значение в регистре обратного адреса и переходит по нему.
Что определяет серьёзность:
Уязвимость была опубликована в бюллетене безопасности MediaTek от 6 января 2025 года с критической степенью серьёзности, затрагивая среди прочих семейство модемов LR12A. Samsung включила исправление в свой выпуск обновлений безопасности за февраль 2025 года.
В этом посте не публикуется боевой эксплойт, и он не воспроизводим на основе опубликованного здесь. Цель — показать, где рвётся цепочка, почему каждый уровень не смог её остановить, и что требуется для ответственной проверки ошибки модема, когда невозможно подключить отладчик к работающему модему.
Основная цель: 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
Прошивка 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] |
SIB1-NB определён в 3GPP TS 36.331. Его поле schedulingInfoList указывает, сколько
сообщений системной информации передаёт сота; спецификация ограничивает максимум до 8
записей (1..maxSI-Message-NB-r13 = 8). Это ограничение уровня протокола. Ограничение
безопасности памяти — а именно, что длина списка не должна превышать ёмкость
целевых массивов — должно применяться отдельно прошивкой.
Этого не было.
Прошивка была получена из пакета 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)
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
Из декомпиляции 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-структуре контекста канала.
Граница цикла используется напрямую, без предварительного сравнения с ёмкостями массивов.
Поток 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
Поток 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 передаёт управление.
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
### 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. Счётчик увеличивается один раз на каждую декодированную запись, для всех записей, которые были декодированы, без ограничения максимума.
Как только буфер 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
### 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.
Прослеживание sap_id = 0x501F в errc_com_send_msg позволило определить маршрутизацию к el1_chmgm_errc_cfg_req_in_idle, которая сохраняет указатель CPHY_CFG_REQ по адресу L1_ctx[+0x323C] и запускает последующую диспетчеризацию.
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
---
## 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.
[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
### 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.
Задача 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
`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.
| Build | Modem firmware | Build date |
|---|---|---|
| Vulnerable | A145RXXU1AWD1, MOLY LR12A...V1.P5 | 2023-04-18 |
| Patched | A145RXXUDDZC2, MOLY LR12A...V3.P8 |
Build dates confirmed by extracting md1_dbginfo metadata from both images. Patch ID:
MOLY00720348 · Issue ID: MSV-2392.
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.
Two functions present in the patched binary are absent from the vulnerable binary:``` el1_ch_nbcch_param_check el1_ch_scell_param_check
Однострочная проверка границ выглядела бы как несколько добавленных инструкций внутри существующей функции по тому же адресу. Что показывает пропатченный бинарник — это архитектурное изменение: путь планирования 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–33 | si_sched_arr[0..33] | В границах |
| 34–35 | new_sp+0xDC — saved s0 | s0 повреждён |
| 36–37 | new_sp+0xE0 — saved s1 | s1 повреждён |
| 38 | new_sp+0xE4 — saved ra [15:0] | Младшее полуслово RA |
| 39 | new_sp+0xE6 — saved ra [31:16] | Старшее полуслово RA |
| Gate | Condition | Where checked |
|---|
| NB-IoT active path | cfg_type == 1 | el1_ch_nbcch_cphy_cfg_req_process |
| Channel not complete | done_flag == 0 | ch_ctx[0x438] |
State machine 0x0B | NBCCH in resume state | el1_ch_nbcch_main dispatch |
| si_count nonzero | ch_ctx[0x40A] > 0 | Loop condition |
| Band class ≤ 2 | Valid NB-IoT mode | Entry of el1_ch_nbcch_resume_req |
el1_chmgm_cell_info_get nonzero | Cell in service table | Called in el1_ch_nbcch_start |
| Function | Address | Role | Clamp? |
|---|
errc_chm_l1_set_bcch_si_reception | ERRC range | Writes CPHY_CFG_REQ[+0x99] | None |
el1_ch_nbcch_cphy_cfg_req_process | 0x90213F80 | Routes CPHY config into L1 | N/A — does not read si_count |
el1_chmgm_cell_info_get | 0x9020E0D0 | Validates EARFCN/PCI | N/A |
el1_ch_nbcch_start | 0x90213444 | Copies count to BSS | None |
el1_ch_nbcch_resume_req | 0x90213940 | Uses count as loop bound | None |
| 2025-04-23 |