
Análise técnica que examina a CVE-2024-20154, um estouro de buffer baseado em pilha no firmware do modem baseband NB-IoT MediaTek MT6769, abordando engenharia reversa e cadeia de exploração.
Classificação: CWE-121 — Estouro de Buffer Baseado em Pilha
Severidade: Crítica (boletim da MediaTek) · 8.8 Alta, Vetor de Ataque: Adjacente (CISA-ADP)
Tipo: Execução Remota de Código — sem interação do usuário, sem associação prévia
Divulgação: Boletim de Segurança da MediaTek, 6 de janeiro de 2025 https://corp.mediatek.com/product-security-bulletin/January-2025
Alvo analisado: Samsung Galaxy A14 SM-A145R — família MT6769 (Helio G80), dentro da lista de chipsets afetados da MediaTek - O firmware foi emulado sob condições seguras.
Status: Corrigido.
Esta foi minha primeira pesquisa publicada sobre baseband. Venho de um background distante de infraestrutura de telecomunicações, camadas de mediação de interceptação legal, análise de stingray e IMSI-catcher, e segurança de dispositivos embarcados — eu não havia feito engenharia reversa profunda de firmware em um modem celular anteriormente. Eu queria provar a mim mesmo que uma metodologia analítica estruturada se adapta entre alvos, e que a familiaridade com uma plataforma específica pode ser substituída por rastreamento rigoroso de cadeia. O NB-IoT se destacou porque está em uma interseção genuinamente perigosa: o protocolo é projetado para dispositivos IoT com recursos limitados, a superfície de ataque é pré-associação, e a pilha do modem o processa independentemente do que o usuário do aparelho esteja fazendo.
Quando o firmware corrigido foi analisado e o padrão vulnerável confirmado como ausente, o sistema de IA usado para análise em massa do firmware antes de direcionar funções específicas
correlacionou independentemente a classe de bug reconstruída, as condições e a família de firmware afetada à descrição da CVE-2024-20154.
As conclusões técnicas são do próprio analista.
O telefone no seu bolso contém pelo menos dois computadores separados. Aquele com o qual você interage roda Android. O outro — o baseband — roda de forma completamente independente, lida com toda a comunicação de rádio, e é quase inteiramente invisível para o sistema operacional acima dele. O Android pode estar totalmente corrigido. O navegador pode estar em sandbox. O usuário pode nunca tocar em um link malicioso. Nada disso importa se o código vulnerável está no firmware do modem que processa sinais de rádio antes que o processador de aplicação esteja envolvido.
A CVE-2024-20154 é exatamente esse tipo de vulnerabilidade.
Uma transmissão de informações de sistema NB-IoT malformada faz com que o firmware do modem MediaTek aceite uma contagem de agendamento controlada pelo atacante, carregue essa contagem pelo caminho de configuração RRC-para-L1 sem nunca limitá-la, e eventualmente a use como limite de laço para um laço de escrita em pilha dentro do manipulador de canal de broadcast do NB-IoT. Quando a contagem excede a capacidade dos arrays de destino, o laço escreve além deles, alcança registradores salvos na pilha, e sobrescreve o endereço de retorno salvo. A função então restaura o valor corrompido no registrador de endereço de retorno e salta para ele.
O que torna a severidade o que ela é:
A vulnerabilidade foi publicada no Boletim de Segurança da MediaTek de 6 de janeiro de 2025 com classificação de severidade Crítica, afetando a família de modems LR12A entre outras. A Samsung incorporou a correção em sua Versão de Manutenção de Segurança de fevereiro de 2025.
Este post não publica um exploit weaponizado e não é reproduzível a partir do que é publicado aqui. O objetivo é mostrar onde a cadeia quebra, por que cada camada falhou em detê-la, e o que é necessário para validar um bug de baseband de forma responsável quando você não pode anexar um depurador ao modem em execução.
Alvo principal: Samsung Galaxy A14 (SM-A145R). O subsistema de rádio é controlado por um processador de baseband MediaTek da família de chipsets MT6769 (Helio G80). A família MT6769 está explicitamente listada na lista de chipsets afetados da MediaTek para a CVE-2024-20154.``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18
O firmware do baseband não é código Android. É um sistema embarcado separado no subsistema de rádio do SoC, com sua própria CPU, seu próprio RTOS e seu próprio espaço de memória, fora do sandbox de processos do Android.
### 2.2 Arquitetura do modem
A análise do binário extraído mostra que o processador do modem executa MIPS32 com instruções comprimidas MIPS16e2 em modo little-endian. MIPS16e2 é uma extensão de codificação de 16 bits para redução de tamanho de código embarcado — consistente com a abordagem da MediaTek para basebands da geração Helio, confirmada por pesquisa independente publicada sobre basebands desta família de SoC.
O sistema operacional é o Nucleus RTOS, fornecendo escalonamento de tarefas, filas de mensagens IPC e um alocador de memória baseado em pool. Não há separação de privilégios kernel/usuário, nem aplicação de unidade de proteção de memória entre tarefas, nem mecanismo de proteção de pilha por hardware.
Todos os endereços neste post são endereços virtuais, conforme carregados no Ghidra na base `0x90000000`.
### 2.3 Mitigações (observadas na build analisada)
| Mitigação | Status | Efeito |
|---|---|---|
| ASLR | Ausente | Os endereços do firmware são estáticos e previsíveis a partir da imagem |
| Stack canary | Ausente | `SAVE`/`RESTORE` armazena registradores salvos pelo chamador sem valor de guarda |
| NX / W^X | Ausente | A memória da pilha é executável |
| CFI | Ausente | Os endereços de retorno não são validados contra nenhuma política |
### 2.4 Abordagem de análise
Três trilhas paralelas:
**Análise estática.** Pacote de firmware Samsung → extração da partição CP → `md1img.img` → Ghidra (MIPS LE 32-bit, base `0x90000000`) com símbolos de engenharia da MediaTek recuperados da seção de debug do firmware usando o conjunto de ferramentas `mtk_bp` do NCC Group.
**Validação dinâmica.** O Unicorn Engine (emulação MIPS32) foi usado para executar rotinas específicas do firmware isoladamente em duas fases. A Fase 1 tentou provar a cópia não limitada de `si_count` no contexto do canal através do par de instruções nativo. A Fase 2 executou o loop vulnerável em bytes reais do firmware e confirmou que as próprias instruções do firmware corrompem o endereço de retorno salvo. Onde a Fase 1 não pôde ser executada totalmente de forma nativa — porque o ambiente de objetos de serviço do RTOS exigido pelo caminho de despacho CPHY não foi reconstruído — o efeito colateral foi modelado diretamente e rotulado como tal em toda a saída.
**Validação pelo lado do rádio.** srsRAN 4G com um loopback ZMQ — apenas software, sem emissão de RF — confirmou que o payload de teste sobrevive à codificação PHY do NB-IoT e à entrega do bloco de transporte.
---
## 3. Superfície de Ataque: NB-IoT e SIB1-NB
### 3.1 Superfície de ataque pré-associação
NB-IoT (Narrowband Internet of Things) é o 3GPP Release 13, projetado para conectar dispositivos IoT restritos usando espectro LTE licenciado existente. É implementado em uma ampla variedade de SoCs celulares modernos, incluindo os presentes em smartphones de consumo.
Enquanto em RRC_IDLE, antes que qualquer conexão RRC seja estabelecida, um dispositivo procurando serviço irá:
1. Sincronizar com os sinais de temporização da célula (NPSS/NSSS)
2. Decodificar o Master Information Block via NPBCH (janela de transmissão de 640 ms)
3. Decodificar o SIB1-NB do NPDSCH (agendamento de 2560 ms)
4. Usar as informações de agendamento no SIB1-NB para localizar blocos de informações de sistema adicionais
No passo 3, o modem processa uma mensagem de uma entidade que não autenticou, antes de qualquer conexão ou interação do usuário. Um transmissor malicioso que satisfaça as condições normais de seleção de célula será processado.```
+------------------+ +---------------------+
| 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 é definido na 3GPP TS 36.331. Seu campo schedulingInfoList carrega quantas
mensagens de Informação de Sistema a célula transmite, restringido pela especificação a um máximo de 8
entradas (1..maxSI-Message-NB-r13 = 8). Esta é uma restrição da camada de protocolo. A
restrição de segurança de memória — que o comprimento da lista não deve exceder a capacidade dos
arrays de destino — deve ser imposta separadamente pelo firmware.
Não foi.
O firmware foi obtido de um pacote CP da Samsung e extraído usando o conjunto de ferramentas mtk_bp
do NCC Group:```
md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image)
→ 017_md1_dbginfo (XZ-compressed CATI debug symbols)
A seção de depuração CATI foi descomprimida e analisada com `mtk_dbg_extract.py symbols`, depois
importada para o Ghidra via `ImportSymbolsScript.py`. O resultado foram nomes de funções internas
completos em toda a pilha do modem — camada ERRC, gerenciamento de canais L1, subsistema IPC e a
cadeia de manipuladores NB-IoT BCCH — permitindo a reconstrução da cadeia guiada por semântica.
Todos os nomes de funções neste post vêm dos próprios símbolos de depuração incorporados da MediaTek extraídos
da imagem de firmware.
---
## 5. Vulnerabilidade
### 5.1 O loop vulnerável
`el1_ch_nbcch_resume_req` (`0x90213940`) trata o evento de retomada do canal de broadcast NB-IoT.
Seu prólogo de função MIPS16e2:```asm
90213940: save 0xE8, ra, s0-s1
A instrução SAVE decrementa sp em 0xE8 e armazena os registradores salvos pelo chamador de cima para baixo:```
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
Do decompilado do Ghidra do binário real do firmware:```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] — um byte persistente na struct BSS do contexto do canal.
O limite do loop é usado diretamente, sem comparação prévia com as capacidades do array.
O stream A (escritas de halfword sh) começa em new_sp+0x98 e avança 2 bytes por iteração.
Ele alcança o RA salvo em new_sp+0xE4 na iteração 38:```
new_sp + 0x98 + i×2 = new_sp + 0xE4
i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38
Stream B (gravações de byte `sb`) começa em `new_sp+0x78` e exigiria a iteração 108 para alcançar
o slot RA:```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108
Com si_count = 40 (o valor do demonstrator, escolhido para exceder o limiar de overflow de 38)
o loop executa 40 iterações. O Stream B nunca alcança o slot RA. A corrupção do RA vem
inteiramente do Stream A.
Após 40 iterações, a instrução RESTORE do MIPS16e2 recarrega o valor corrompido da
pilha para $ra, e jrc ra transfere o controle.
ch_ctx[+0x40A] é escrito por el1_ch_nbcch_start em 0x90213444. Duas instruções MIPS
consecutivas sem nada entre elas:```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 O construtor ERRC — Camada A
O buffer CPHY_CFG_REQ é construído na camada ERRC a partir do SIB1-NB decodificado. A função
`errc_chm_l1_set_bcch_si_reception` escreve `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
}
}
O limite do loop é a contagem de entradas descodificadas do SIB1-NB. O contador incrementa uma vez por entrada descodificada, para tantas entradas quantas foram descodificadas, sem limite máximo.
Assim que o buffer CPHY_CFG_REQ é preenchido, o ERRC despacha-o para o L1 com sap_id = 0x501F
como chave de encaminhamento:```
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 Ausência de clamping em três camadas
| Camada | Função | Endereço | Clamp presente? |
|---|---|---|---|
| A — construtor ERRC | `errc_chm_l1_set_bcch_si_reception` | intervalo ERRC | **Nenhum** |
| B — cópia L1 | `el1_ch_nbcch_start` | `0x90213444` | **Nenhum** |
| C — loop L1 | `el1_ch_nbcch_resume_req` | `0x90213940` | **Nenhum** |
Qualquer verificação única em qualquer uma das camadas teria quebrado a cadeia.
### 5.7 Causa raiz
Uma invariante violada:
> O número de entradas de agendamento de SI nunca deve exceder a capacidade do array de destino.
O 3GPP fornece o limite de protocolo pretendido (8 entradas). O firmware precisava impor o
limite de segurança de memória em cada camada onde a contagem se torna um índice ou limite
de loop. Na build vulnerável, a contagem viajou do campo de broadcast SIB1-NB através do
decodificador ERRC, para a mensagem CPHY_CFG_REQ, através de uma fronteira IPC para a
tarefa L1, para o BSS de contexto de canal, e para um loop de escrita na stack — sem que
nenhuma camada a limitasse.
---
## 6. A Cadeia de Chamadas — Como Foi Encontrada
### 6.1 A confusão dos dois caminhos
Dois caminhos estruturalmente semelhantes mas distintos podem entregar um buffer de
configuração de 0x760 bytes a `el1_ch_nbcch_main`:
| Caminho | Origem | Valor de `[+0x99]` | Relevância |
|---|---|---|---|
| Caminho A (ERRC → L1 IPC) | ERRC constrói CPHY_CFG_REQ a partir do SIB1-NB decodificado | `schedulingInfoList.count` do OTA | **O caminho vulnerável** |
| Caminho B (L1 interno) | `el1_ch_scs_ind_send` constrói corpo IPC interno | `1` hardcoded | Não vulnerável |
O Caminho B confirmou o formato da mensagem — o byte `+0x99` é a contagem de SI consumida
por `el1_ch_nbcch_start`. Como a sua contagem é sempre hardcoded para 1, não pode
transbordar. O caminho influenciado externamente é o Caminho A.
### 6.2 A busca pelo escritor
A busca por padrões no firmware por qualquer instrução que escrevesse no offset `+0x99`
produziu ruído: T1 (`sb` direto, ~100 resultados), T2 (base dividida, 5 resultados), T3
(offset computado, 0), T4 (`sh`/`sw` sobrepostos, ~465). As funções de gestão de canal ERRC
estavam ausentes da lista de referências cruzadas de `msg_send6` porque o ERRC usa
`errc_com_send_msg`. Uma sonda de emulação confirmou que a escrita era do lado ERRC:
executar o harness Unicorn a partir do dispatcher L1 e observar escritas no offset `+0x99`
do buffer não capturou nada do lado 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.
Seguindo sap_id = 0x501F em errc_com_send_msg, identificou-se o roteamento para
el1_chmgm_errc_cfg_req_in_idle, que armazena o ponteiro CPHY_CFG_REQ em
L1_ctx[+0x323C] e inicia o despacho downstream.
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. Validação
Este modelo específico SM-A145R não parece exercitar
o caminho de código NB-IoT vulnerável em operação normal de construção de navios, razão pela qual
emulação híbrida e análise estática foram usadas em vez de reprodução direta em hardware.
**Provado estaticamente.** O binário de firmware contém o par de instruções vulnerável. A cadeia
de chamadas é reconstruída a partir de símbolos, referências cruzadas e corpos de funções descompilados.
**Executado nativamente em emulação.** O loop dentro de `el1_ch_nbcch_resume_req` foi executado sobre bytes
reais do firmware MediaTek no Unicorn Engine (MIPS32). A própria instrução `sh` do firmware em
`0x90213B02` escreveu no slot do endereço de retorno salvo. A instrução `RESTORE` carregou o
valor corrompido em `$ra`, e `jrc ra` transferiu o controle.
**Modelado explicitamente.** A cópia `lbu`/`sb` em `el1_ch_nbcch_start` não pôde ser executada totalmente
de forma nativa porque o caminho de despacho da tabela de callbacks do RTOS dentro de `el1_ch_nbcch_cphy_cfg_req_
process` esperava objetos de heap Nucleus vivos que o emulador plano não fornecia. O manipulador
de retomada (`el1_ch_nbcch_resume_req`) na Fase 2 lê apenas do contexto de canal residente na BSS
e não atinge esse mesmo caminho de despacho, razão pela qual a Fase 2 foi executada nativamente sem
exigir a mesma estrutura de suporte. O efeito colateral da Fase 1 — um byte de `IPC_msg[+0x99]`
escrito em `ch_ctx[+0x40A]` — foi modelado diretamente e rotulado `[PHASE1-MODEL]`.
**Não alegado.** Uma reprodução completa de hardware ponta a ponta via rádio.
### 7.1 Anti-adulteração
O harness impôs uma regra: nenhum hook tinha permissão para escrever o marcador de prova no slot
do endereço de retorno salvo. Toda escrita em memória não pertencente ao firmware foi rastreada.```
[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 é a instrução sh dentro do corpo do loop. O firmware colocou esses bytes no
deslocamento de pilha previsto. No armazenamento little-endian, as meias-palavras 0xBEEF e 0xDEAD
em new_sp+0xE4 e new_sp+0xE6 combinam-se para [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 Entrega ZMQ
Para confirmar que o payload de teste sobrevive à codificação PHY do NB-IoT e à entrega do bloco de transporte, foi utilizado o srsRAN 4G com um loopback ZMQ (sem emissão RF). O payload era um vetor deliberadamente não conforme — a restrição ASN.1 SIZE em `schedulingInfoList` foi relaxada para permitir 40 entradas, com a decodificação round-trip do pycrate confirmando o campo de contagem no byte 14.```
SIB1 received
SIB2 activated
exit 0
Isso confirma a entrega na camada de transporte. O comportamento ASN.1 do lado do firmware é estabelecido pela análise estática da Camada A.
A tarefa el1_ch possui uma única pilha. A Fase 1 e a Fase 2 são dois eventos IPC separados processados sequencialmente pela mesma tarefa, com a pilha sendo completamente desenrolada entre eles. A contagem persiste no BSS de contexto do canal, não na pilha:```
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]` reside no BSS e retém o valor do atacante até que o modem seja reiniciado ou uma
configuração de canal subsequente o sobrescreva.
### 8.2 Stack frame```
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]
Tamanho do frame confirmado por medição de emulação. Posições do array confirmadas pelo resultado da emulação — RA escrito na iteração 38, consistente com si_sched_arr começando em new_sp+0x98.
| Build | Firmware do modem | Data do build |
|---|---|---|
| Vulnerável | A145RXXU1AWD1, MOLY LR12A...V1.P5 | 2023-04-18 |
| Corrigido | A145RXXUDDZC2, MOLY LR12A...V3.P8 |
Datas de build confirmadas pela extração dos metadados md1_dbginfo de ambas as imagens. ID do patch:
MOLY00720348 · ID da issue: MSV-2392.
el1_ch_nbcch_start (0x90213444 no binário vulnerável): O par de instruções lbu/sb
está ausente. A cópia direta de IPC_msg[+0x99] para ch_ctx[+0x40A] foi removida.
el1_ch_nbcch_resume_req (0x90213940 no binário vulnerável): O loop de escrita na pilha
sobre ch_ctx[0x40A] está ausente. A arquitetura em que um byte não confiável se torna um limite de loop
sobre arrays de pilha de tamanho fixo não existe mais. O corpo da função é substituído por uma estrutura
de despacho diferente.
errc_chm_l1_set_bcch_si_reception: O loop de contador sem limite é substituído por
chamadas de helpers orientadas à validação.
Duas funções presentes no binário corrigido estão ausentes do binário vulnerável:``` el1_ch_nbcch_param_check el1_ch_scell_param_check
Uma verificação de limites de linha única apareceria como algumas instruções adicionadas dentro de uma função existente no mesmo endereço. O que o binário corrigido mostra é uma revisão arquitetural: o caminho de agendamento NBCCH foi redesenhado para que o padrão `si_count`-como-limite-de-loop não exista mais em nenhum lugar do caminho.
### 10.4 Atribuição de CVE
A vulnerabilidade aqui descrita corresponde à CVE-2024-20154, conforme publicada pela MediaTek em 6 de janeiro de 2025. Base da confirmação:
- A família de firmware afetada (LR12A) corresponde ao boletim da MediaTek.
- A classe da vulnerabilidade — estouro de pilha, verificação de limites ausente, RCE a partir de estação base maliciosa, sem interação do usuário — corresponde à descrição da CVE e ao registro do NVD.
- O firmware corrigido remove exatamente as estruturas de código identificadas como vulneráveis.
- ID do patch MOLY00720348 confirmado a partir do boletim da MediaTek e do Android Security Bulletin (A-376809176).
- A análise assistida por IA correspondeu independentemente o padrão reconstruído à CVE-2024-20154 antes da confirmação manual.
---
## 11. Ética e Divulgação Responsável
### 11.1 O que este post não contém
Nenhum exploit armado. Nenhum conteúdo de binário de firmware. Nenhum byte de payload malformado. Nenhum procedimento passo a passo para acionar a vulnerabilidade contra um dispositivo ativo. As informações necessárias para reproduzir um ataque funcional — construção completa de payload para o decodificador de modem específico, estruturação de objetos de heap do RTOS para emulação completa da Fase 1, configuração de rádio over-the-air — estão deliberadamente ausentes.
### 11.2 Por que loopback ZMQ e emulação são a abordagem ética
Loopback ZMQ significa que nenhum sinal foi jamais transmitido pelo ar. Nenhum dispositivo real foi alvo. Nenhuma rede de operadora foi envolvida. A prova é executada inteiramente em um ambiente de software contido, em hardware de propriedade do analista. Esta é a abordagem correta para validar uma vulnerabilidade de rádio de pré-associação — transmitir um broadcast malformado afetaria qualquer dispositivo ao alcance.
A emulação Unicorn demonstra que o comportamento vulnerável está no próprio binário do firmware, de forma reproduzível, independentemente de qualquer estado específico do dispositivo ou ambiente de rádio. Esta é uma afirmação tecnicamente mais forte do que uma única falha de hardware, e evita implantar qualquer coisa pelo ar.
### 11.3 Propriedade intelectual da MediaTek
Toda a análise foi realizada em firmware obtido legitimamente de um dispositivo de consumo e dos pacotes de firmware publicamente divulgados pela Samsung. Nenhuma documentação proprietária foi utilizada. Definições internas de structs da MediaTek e formatos de mensagens IPC são descritos apenas na medida necessária para explicar a falha de segurança de memória. Eles não são publicados como especificações.
---
| Iteração | sh escreve em | Efeito |
|---|
| 0–33 | si_sched_arr[0..33] | Dentro dos limites |
| 34–35 | new_sp+0xDC — s0 salvo | s0 corrompido |
| 36–37 | new_sp+0xE0 — s1 salvo | s1 corrompido |
| 38 | new_sp+0xE4 — ra salvo [15:0] | Metade inferior do RA |
| 39 | new_sp+0xE6 — ra salvo [31:16] | Metade superior do RA |
| Gate | Condição | Onde é verificado |
|---|
| Caminho ativo NB-IoT | cfg_type == 1 | el1_ch_nbcch_cphy_cfg_req_process |
| Canal não completo | done_flag == 0 | ch_ctx[0x438] |
Máquina de estados 0x0B | NBCCH em estado de resume | despacho de el1_ch_nbcch_main |
| si_count diferente de zero | ch_ctx[0x40A] > 0 | Condição do loop |
| Classe de banda ≤ 2 | Modo NB-IoT válido | Entrada de el1_ch_nbcch_resume_req |
el1_chmgm_cell_info_get diferente de zero | Célula na tabela de serviço | Chamado em el1_ch_nbcch_start |
| Função | Endereço | Papel | Limita? |
|---|
errc_chm_l1_set_bcch_si_reception | Faixa ERRC | Escreve CPHY_CFG_REQ[+0x99] | Nenhum |
el1_ch_nbcch_cphy_cfg_req_process | 0x90213F80 | Encaminha configuração CPHY para L1 | N/A — não lê si_count |
el1_chmgm_cell_info_get | 0x9020E0D0 | Valida EARFCN/PCI | N/A |
el1_ch_nbcch_start | 0x90213444 | Copia contagem para BSS | Nenhum |
el1_ch_nbcch_resume_req | 0x90213940 | Usa contagem como limite do loop | Nenhum |
| 2025-04-23 |