
Análisis técnico de CVE-2024-20154, un desbordamiento de búfer basado en pila en el firmware del módem baseband MediaTek MT6769 NB-IoT, que abarca ingeniería inversa y cadena de explotación.
Clasificación: CWE-121 — Desbordamiento de búfer basado en pila
Gravedad: Crítica (boletín de MediaTek) · 8.8 Alta, Vector de ataque: Adyacente (CISA-ADP)
Tipo: Ejecución remota de código — sin interacción del usuario, sin asociación previa
Divulgación: Boletín de seguridad de MediaTek, 6 de enero de 2025 https://corp.mediatek.com/product-security-bulletin/January-2025
Objetivo analizado: Samsung Galaxy A14 SM-A145R — familia MT6769 (Helio G80), dentro de la lista de chipsets afectados de MediaTek - El firmware fue emulado en condiciones seguras.
Estado: Parcheado.
Esta fue mi primera investigación publicada sobre banda base. Vengo de un entorno muy alejado de la infraestructura de telecomunicaciones, las capas de mediación de interceptación legal, el análisis de stingray y capturadores de IMSI, y la seguridad de dispositivos embebidos — no había realizado previamente ingeniería inversa profunda de firmware en un módem celular. Quería demostrarme a mí mismo que una metodología analítica estructurada se adapta a distintos objetivos, y que la familiaridad con una plataforma específica puede reemplazarse por un rastreo riguroso de la cadena. NB-IoT destacaba porque se sitúa en una intersección genuinamente peligrosa: el protocolo está diseñado para dispositivos IoT con recursos limitados, la superficie de ataque es previa a la asociación, y la pila del módem lo procesa independientemente de lo que esté haciendo el usuario del teléfono.
Cuando se analizó el firmware parcheado y se confirmó la ausencia del patrón vulnerable, el sistema de IA utilizado para el análisis masivo del firmware antes de apuntar a funciones específicas
coincidió de forma independiente con la clase de bug reconstruida, las condiciones y la familia de firmware afectada con la descripción de CVE-2024-20154.
Las conclusiones técnicas son del propio analista.
El teléfono que llevas en el bolsillo contiene al menos dos computadoras separadas. Con la que interactúas ejecuta Android. La otra — la banda base — se ejecuta de forma completamente independiente, gestiona toda la comunicación por radio, y es casi totalmente invisible para el sistema operativo que está por encima. Android puede estar completamente parcheado. El navegador puede estar en sandbox. El usuario puede no tocar nunca un enlace malicioso. Nada de eso importa si el código vulnerable está en el firmware del módem que procesa las señales de radio antes de que el procesador de aplicaciones intervenga.
CVE-2024-20154 es exactamente ese tipo de vulnerabilidad.
Una difusión de información de sistema NB-IoT malformada hace que el firmware del módem MediaTek acepte un conteo de planificación controlado por el atacante, arrastre ese conteo a través de la ruta de configuración RRC-a-L1 sin acotarlo nunca, y finalmente lo use como límite de bucle para un bucle de escritura en pila dentro del manejador del canal de difusión NB-IoT. Cuando el conteo excede la capacidad de los arrays de destino, el bucle escribe más allá de ellos, alcanza los registros guardados en la pila y sobrescribe la dirección de retorno guardada. La función entonces restaura el valor corrupto en el registro de dirección de retorno y salta a él.
Lo que hace que la gravedad sea la que es:
La vulnerabilidad se publicó en el Boletín de Seguridad de MediaTek del 6 de enero de 2025 con una calificación de gravedad Crítica, afectando a la familia de módems LR12A entre otras. Samsung incorporó la corrección en su Versión de Mantenimiento de Seguridad de febrero de 2025.
Esta publicación no publica un exploit weaponizado y no es reproducible a partir de lo que se publica aquí. El objetivo es mostrar dónde se rompe la cadena, por qué cada capa falló en detenerlo, y qué se necesita para validar un bug de banda base de forma responsable cuando no puedes conectar un depurador al módem en vivo.
Objetivo principal: Samsung Galaxy A14 (SM-A145R). El subsistema de radio está controlado por un procesador de banda base MediaTek de la familia de chipsets MT6769 (Helio G80). La familia MT6769 está explícitamente incluida en la lista de chipsets afectados de MediaTek para CVE-2024-20154.``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18
El firmware de banda base no es código Android. Es un sistema embebido separado en el
subsistema de radio del SoC con su propia CPU, su propio RTOS y su propio espacio de memoria,
fuera del sandbox de procesos de Android.
### 2.2 Arquitectura del módem
El análisis del binario extraído muestra que el procesador del módem ejecuta MIPS32 con
instrucciones comprimidas MIPS16e2 en modo little-endian. MIPS16e2 es una extensión de
codificación de 16 bits para la reducción del tamaño de código embebido — consistente con el
enfoque de MediaTek para las bandas base de la generación Helio, confirmado por investigación
independiente publicada sobre bandas base de esta familia de SoC.
El sistema operativo es Nucleus RTOS, que proporciona planificación de tareas, colas de
mensajes IPC y un asignador de memoria basado en pools. No hay separación de privilegios
kernel/usuario, no hay aplicación de unidad de protección de memoria entre tareas y no hay
mecanismo de protección de pila por hardware.
Todas las direcciones en este post son direcciones virtuales, tal como se cargan en Ghidra con
base `0x90000000`.
### 2.3 Mitigaciones (observadas en la compilación analizada)
| Mitigación | Estado | Efecto |
|---|---|---|
| ASLR | Ausente | Las direcciones del firmware son estáticas y predecibles a partir de la imagen |
| Stack canary | Ausente | `SAVE`/`RESTORE` almacena registros callee-saved sin valor de guarda |
| NX / W^X | Ausente | La memoria de pila es ejecutable |
| CFI | Ausente | Las direcciones de retorno no se validan contra ninguna política |
### 2.4 Enfoque de análisis
Tres vías paralelas:
**Análisis estático.** Paquete de firmware de Samsung → extracción de la partición CP → `md1img.img` →
Ghidra (MIPS LE 32-bit, base `0x90000000`) con símbolos de ingeniería de MediaTek recuperados de
la sección de depuración del firmware usando el conjunto de herramientas `mtk_bp` de NCC Group.
**Validación dinámica.** Se utilizó Unicorn Engine (emulación MIPS32) para ejecutar rutinas
específicas del firmware de forma aislada en dos fases. La Fase 1 intentó demostrar la copia sin
restricciones de `si_count` en el contexto del canal a través del par de instrucciones nativo. La
Fase 2 ejecutó el bucle vulnerable sobre bytes reales del firmware y confirmó que las propias
instrucciones del firmware corrompen la dirección de retorno guardada. Donde la Fase 1 no pudo
ejecutarse completamente de forma nativa — porque el entorno de objetos de servicio del RTOS
requerido por la ruta de despacho CPHY no fue reconstruido — el efecto secundario se modeló
directamente y se etiquetó como tal en toda la salida.
**Validación del lado de radio.** srsRAN 4G con un loopback ZMQ — solo software, sin emisión de RF —
confirmó que el payload de prueba sobrevive a la codificación PHY de NB-IoT y a la entrega del
bloque de transporte.
---
## 3. Superficie de ataque: NB-IoT y SIB1-NB
### 3.1 Superficie de ataque previa a la asociación
NB-IoT (Narrowband Internet of Things) es 3GPP Release 13, diseñado para conectar dispositivos
IoT de recursos limitados usando espectro LTE licenciado existente. Está implementado en una
amplia gama de SoCs celulares modernos, incluidos los de smartphones de consumo.
Mientras está en RRC_IDLE, antes de que se establezca cualquier conexión RRC, un dispositivo que
busca servicio:
1. Se sincroniza con las señales de temporización de la celda (NPSS/NSSS)
2. Decodifica el Master Information Block sobre NPBCH (ventana de transmisión de 640 ms)
3. Decodifica SIB1-NB desde NPDSCH (programación de 2560 ms)
4. Usa la información de programación en SIB1-NB para localizar bloques de información de sistema adicionales
En el paso 3, el módem procesa un mensaje de una entidad que no ha autenticado, antes de
cualquier conexión o interacción del usuario. Un transmisor malicioso que cumpla las condiciones
normales de selección de celda será procesado.```
+------------------+ +---------------------+
| 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 se define en 3GPP TS 36.331. Su campo schedulingInfoList indica cuántos
mensajes de Información de Sistema difunde la celda, restringido por la especificación a un máximo de 8
entradas (1..maxSI-Message-NB-r13 = 8). Esta es una restricción de la capa de protocolo. La
restricción de seguridad de memoria —que la longitud de la lista no debe exceder la capacidad de los
arrays de destino— debe ser aplicada por separado por el firmware.
No lo fue.
El firmware se obtuvo de un paquete CP de Samsung y se extrajo utilizando el conjunto de herramientas mtk_bp
de NCC Group:```
md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image)
→ 017_md1_dbginfo (XZ-compressed CATI debug symbols)
La sección de depuración CATI se descomprimió y se analizó con `mtk_dbg_extract.py symbols`, y luego
se importó en Ghidra mediante `ImportSymbolsScript.py`. El resultado fueron nombres de funciones
internas completos en toda la pila del módem — la capa ERRC, la gestión de canales L1, el subsistema IPC y la
cadena de gestores BCCH de NB-IoT — lo que permitió la reconstrucción de la cadena guiada por semántica.
Todos los nombres de funciones en esta publicación provienen de los propios símbolos de depuración
integrados de MediaTek extraídos de la imagen del firmware.
---
## 5. Vulnerabilidad
### 5.1 El bucle vulnerable
`el1_ch_nbcch_resume_req` (`0x90213940`) gestiona el evento de reanudación del canal de difusión NB-IoT.
Su prólogo de función MIPS16e2:```asm
90213940: save 0xE8, ra, s0-s1
La instrucción SAVE decrementa sp en 0xE8 y almacena los registros guardados por el destinatario hacia abajo:```
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
Desde la descompilación de Ghidra del binario de firmware real:```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] es ch_ctx[+0x40A] — un byte persistente en la estructura BSS del contexto del canal.
El límite del bucle se utiliza directamente, sin comparación previa con las capacidades del array.
El flujo A (escrituras de media palabra sh) comienza en new_sp+0x98 y avanza 2 bytes por iteración.
Alcanza la RA guardada en new_sp+0xE4 en la iteración 38:```
new_sp + 0x98 + i×2 = new_sp + 0xE4
i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38
Stream B (escrituras de byte `sb`) comienza en `new_sp+0x78` y requeriría la iteración 108 para alcanzar
la ranura RA:```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108
Con si_count = 40 (el valor del demostrador, elegido para superar el umbral de desbordamiento de 38)
el bucle se ejecuta 40 iteraciones. El Stream B nunca alcanza el slot de RA. La corrupción de RA proviene
enteramente del Stream A.
Tras 40 iteraciones, la instrucción RESTORE de MIPS16e2 recarga el valor corrompido desde la
pila en $ra, y jrc ra transfiere el control.
ch_ctx[+0x40A] es escrito por el1_ch_nbcch_start en 0x90213444. Dos instrucciones MIPS
consecutivas sin nada entre ellas:```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 El constructor de ERRC — Capa A
El búfer CPHY_CFG_REQ se construye en la capa ERRC a partir del SIB1-NB decodificado. La función
`errc_chm_l1_set_bcch_si_reception` escribe `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
}
}
El límite del bucle es el recuento de entradas decodificadas de SIB1-NB. El contador se incrementa una vez por entrada decodificada, para tantas entradas como se hayan decodificado, sin ninguna protección de máximo.
Una vez que el búfer CPHY_CFG_REQ está poblado, ERRC lo despacha a L1 con sap_id = 0x501F
como clave de enrutamiento:```
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 Ausencia de limitación en tres capas
| Capa | Función | Dirección | ¿Limitación presente? |
|---|---|---|---|
| A — constructor ERRC | `errc_chm_l1_set_bcch_si_reception` | Rango ERRC | **Ninguna** |
| B — copia L1 | `el1_ch_nbcch_start` | `0x90213444` | **Ninguna** |
| C — bucle L1 | `el1_ch_nbcch_resume_req` | `0x90213940` | **Ninguna** |
Cualquier verificación única en cualquiera de las capas habría roto la cadena.
### 5.7 Causa raíz
Un invariante violado:
> El número de entradas de planificación de SI nunca debe exceder la capacidad del array de destino.
3GPP proporciona el límite de protocolo previsto (8 entradas). El firmware necesitaba aplicar el
límite de seguridad de memoria en cada capa donde el conteo se convierte en un índice o límite de bucle. En la
compilación vulnerable, el conteo viajó desde el campo de difusión SIB1-NB a través del decodificador
ERRC, hacia el mensaje CPHY_CFG_REQ, cruzando una frontera IPC hacia la tarea L1, hacia
el contexto de canal BSS, y hacia un bucle de escritura en pila — sin que ninguna capa lo limitara.
---
## 6. La cadena de llamadas — Cómo se encontró
### 6.1 La confusión de dos rutas
Dos rutas estructuralmente similares pero distintas pueden entregar un búfer de configuración de 0x760 bytes a
`el1_ch_nbcch_main`:
| Ruta | Origen | Valor de `[+0x99]` | Relevancia |
|---|---|---|---|
| Ruta A (ERRC → L1 IPC) | ERRC construye CPHY_CFG_REQ a partir de SIB1-NB decodificado | `schedulingInfoList.count` desde OTA | **La ruta vulnerable** |
| Ruta B (L1 interna) | `el1_ch_scs_ind_send` construye el cuerpo IPC interno | `1` codificado | No vulnerable |
La Ruta B confirmó el formato del mensaje — el byte `+0x99` es el conteo de SI consumido por
`el1_ch_nbcch_start`. Debido a que su conteo siempre está codificado a 1, no puede desbordarse. La
ruta influenciada externamente es la Ruta A.
### 6.2 La búsqueda del escritor
La búsqueda por patrones en el firmware de cualquier instrucción que escriba en el desplazamiento `+0x99` produjo ruido:
T1 (`sb` directo, ~100 coincidencias), T2 (base dividida, 5 coincidencias), T3 (desplazamiento calculado, 0), T4
(`sh`/`sw` superpuestos, ~465). Las funciones de gestión de canales ERRC estaban ausentes de la
lista de referencias cruzadas de `msg_send6` porque ERRC utiliza `errc_com_send_msg`. Una sonda de emulación
confirmó que la escritura era del lado ERRC: ejecutar el arnés Unicorn desde el despachador L1 y
observar escrituras en el desplazamiento `+0x99` del búfer no capturó nada desde el 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.
El seguimiento de sap_id = 0x501F en errc_com_send_msg identificó el enrutamiento hacia
el1_chmgm_errc_cfg_req_in_idle, que almacena el puntero CPHY_CFG_REQ en
L1_ctx[+0x323C] y comienza el despacho descendente.
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. Validación
Este modelo específico SM-A145R no parece ejecutar
la ruta de código NB-IoT vulnerable en la operación normal de compilación de envío, por lo que se utilizaron
emulación híbrida y análisis estático en lugar de reproducción directa en hardware.
**Probado estáticamente.** El binario del firmware contiene el par de instrucciones vulnerable. La cadena
de llamadas se reconstruye a partir de símbolos, referencias cruzadas y cuerpos de funciones descompilados.
**Ejecutado de forma nativa en emulación.** El bucle dentro de `el1_ch_nbcch_resume_req` se ejecutó sobre bytes
reales del firmware MediaTek en Unicorn Engine (MIPS32). La instrucción `sh` del propio firmware en
`0x90213B02` escribió en la ranura de dirección de retorno guardada. La instrucción `RESTORE` cargó el
valor corrupto en `$ra`, y `jrc ra` transfirió el control.
**Modelado explícitamente.** La copia `lbu`/`sb` en `el1_ch_nbcch_start` no pudo ejecutarse completamente
de forma nativa porque la ruta de despacho de la tabla de callbacks del RTOS dentro de `el1_ch_nbcch_cphy_cfg_req_
process` esperaba objetos de heap de Nucleus activos que el emulador plano no proporcionaba. El manejador
de reanudación (`el1_ch_nbcch_resume_req`) en la Fase 2 lee únicamente del contexto de canal residente en BSS
y no alcanza esa misma ruta de despacho, por lo que la Fase 2 se ejecutó de forma nativa sin
requerir el mismo andamiaje. El efecto secundario de la Fase 1 — un byte de `IPC_msg[+0x99]`
escrito en `ch_ctx[+0x40A]` — se modeló directamente y se etiquetó como `[PHASE1-MODEL]`.
**No afirmado.** Una reproducción completa de extremo a extremo por aire en hardware.
### 7.1 Anti-manipulación
El arnés impuso una regla: no se permitió que ningún hook escribiera el marcador de prueba en la ranura
de dirección de retorno guardada. Se rastreó cada escritura en memoria que no fuera del firmware.```
[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 es la instrucción sh dentro del cuerpo del bucle. El firmware colocó estos bytes en
el desplazamiento de pila previsto. En almacenamiento little-endian, las medias palabras 0xBEEF y 0xDEAD
en new_sp+0xE4 y new_sp+0xE6 se combinan para formar [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 el payload de prueba sobrevive a la codificación PHY de NB-IoT y a la entrega del bloque de transporte, se utilizó srsRAN 4G con un loopback ZMQ (sin emisión de RF). El payload era un vector deliberadamente no conforme — la restricción de SIZE de ASN.1 sobre `schedulingInfoList` se relajó para permitir 40 entradas, con una decodificación round-trip de pycrate que confirma el campo de conteo en el byte 14.```
SIB1 received
SIB2 activated
exit 0
Esto confirma la entrega en la capa de transporte. El comportamiento ASN.1 del lado del firmware queda establecido por el análisis estático de la Capa A.
La tarea el1_ch tiene una sola pila. La Fase 1 y la Fase 2 son dos eventos IPC separados procesados secuencialmente por la misma tarea, con la pila desenrollándose por completo entre ellos. El contador persiste en el BSS del contexto del canal, no en la pila:```
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 en BSS y conserva el valor del atacante hasta que el módem se reinicie o una configuración de canal posterior lo sobrescriba.
### 8.2 Marco de pila```
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]
El tamaño del frame confirmado por medición de emulación. Las posiciones del array confirmadas por el resultado de la emulación — RA escrito en la iteración 38, consistente con si_sched_arr comenzando en new_sp+0x98.
| Compilación | Firmware del módem | Fecha de compilación |
|---|---|---|
| Vulnerable | A145RXXU1AWD1, MOLY LR12A...V1.P5 | 2023-04-18 |
| Parcheada | A145RXXUDDZC2, MOLY |
Fechas de compilación confirmadas extrayendo los metadatos md1_dbginfo de ambas imágenes. ID del parche:
MOLY00720348 · ID del problema: MSV-2392.
el1_ch_nbcch_start (0x90213444 en el binario vulnerable): El par de instrucciones lbu/sb está ausente. La copia directa de IPC_msg[+0x99] en ch_ctx[+0x40A] ha desaparecido.
el1_ch_nbcch_resume_req (0x90213940 en el binario vulnerable): El bucle de escritura en pila sobre ch_ctx[0x40A] está ausente. La arquitectura donde un byte no confiable se convierte en un límite de bucle sobre arrays de pila de tamaño fijo ya no existe. El cuerpo de la función se reemplaza con una estructura de despacho diferente.
errc_chm_l1_set_bcch_si_reception: El bucle de contador sin límites se reemplaza con llamadas a funciones auxiliares orientadas a la validación.
Dos funciones presentes en el binario parcheado están ausentes del binario vulnerable:``` el1_ch_nbcch_param_check el1_ch_scell_param_check
Una comprobación de límites de una sola línea aparecería como unas pocas instrucciones añadidas dentro de una función existente en la misma dirección. Lo que muestra el binario parcheado es una revisión arquitectónica: la ruta de planificación de NBCCH fue rediseñada para que el patrón de `si_count`-como-límite-de-bucle ya no exista en ningún punto de la ruta.
### 10.4 Atribución de CVE
La vulnerabilidad descrita aquí coincide con CVE-2024-20154 tal como fue publicada por MediaTek el 6 de enero de 2025. Base de la confirmación:
- La familia de firmware afectada (LR12A) coincide con el boletín de MediaTek.
- La clase de vulnerabilidad — desbordamiento de pila, comprobación de límites ausente, RCE desde una estación base maliciosa, sin interacción del usuario — coincide con la descripción del CVE y el registro de NVD.
- El firmware parcheado elimina exactamente las estructuras de código identificadas como vulnerables.
- ID de parche MOLY00720348 confirmado a partir del boletín de MediaTek y el Boletín de Seguridad de Android (A-376809176).
- El análisis asistido por IA coincidió de forma independiente con el patrón reconstruido con CVE-2024-20154 antes de la confirmación manual.
---
## 11. Ética y divulgación responsable
### 11.1 Lo que esta publicación no contiene
Ningún exploit weaponizado. Ningún contenido de binario de firmware. Ningún byte de payload malformado. Ningún procedimiento paso a paso para desencadenar la vulnerabilidad contra un dispositivo en vivo. La información necesaria para reproducir un ataque funcional — la construcción completa del payload para el decodificador de módem específico, el andamiaje de objetos del heap del RTOS para la emulación completa de la Fase 1, la configuración de radio por aire — está deliberadamente ausente.
### 11.2 Por qué el loopback ZMQ y la emulación son el enfoque ético
El loopback ZMQ significa que nunca se transmitió ninguna señal por el aire. No se atacó ningún dispositivo real. No se involucró ninguna red de operador. La prueba se ejecuta enteramente en un entorno de software contenido sobre hardware propiedad del analista. Este es el enfoque correcto para validar una vulnerabilidad de radio previa a la asociación — transmitir un broadcast malformado afectaría a cualquier dispositivo dentro del alcance.
La emulación con Unicorn demuestra que el comportamiento vulnerable está en el propio binario del firmware, de forma reproducible, independientemente de cualquier estado específico del dispositivo o entorno de radio. Esta es una afirmación técnicamente más sólida que un único fallo de hardware, y evita desplegar cualquier cosa por el aire.
### 11.3 Propiedad intelectual de MediaTek
Todo el análisis se realizó sobre firmware obtenido legítimamente de un dispositivo de consumo y de los paquetes de firmware publicados públicamente por Samsung. No se utilizó documentación propietaria. Las definiciones internas de estructuras de MediaTek y los formatos de mensajes IPC se describen solo en la medida necesaria para explicar el fallo de seguridad de memoria. No se publican como especificaciones.
---
| Iteración | sh escribe en | Efecto |
|---|
| 0–33 | si_sched_arr[0..33] | Dentro de los límites |
| 34–35 | new_sp+0xDC — s0 guardado | s0 corrompido |
| 36–37 | new_sp+0xE0 — s1 guardado | s1 corrompido |
| 38 | new_sp+0xE4 — ra guardado [15:0] | Mitad baja de RA |
| 39 | new_sp+0xE6 — ra guardado [31:16] | Mitad alta de RA |
| Puerta | Condición | Dónde se verifica |
|---|
| Ruta activa NB-IoT | cfg_type == 1 | el1_ch_nbcch_cphy_cfg_req_process |
| Canal no completo | done_flag == 0 | ch_ctx[0x438] |
Máquina de estados 0x0B | NBCCH en estado de reanudación | despacho de el1_ch_nbcch_main |
| si_count distinto de cero | ch_ctx[0x40A] > 0 | Condición del bucle |
| Clase de banda ≤ 2 | Modo NB-IoT válido | Entrada de el1_ch_nbcch_resume_req |
el1_chmgm_cell_info_get distinto de cero | Celda en tabla de servicio | Invocado en el1_ch_nbcch_start |
| Función | Dirección | Rol | ¿Limita? |
|---|
errc_chm_l1_set_bcch_si_reception | Rango ERRC | Escribe CPHY_CFG_REQ[+0x99] | Ninguno |
el1_ch_nbcch_cphy_cfg_req_process | 0x90213F80 | Enruta la configuración CPHY hacia L1 | N/A — no lee si_count |
el1_chmgm_cell_info_get | 0x9020E0D0 | Valida EARFCN/PCI | N/A |
el1_ch_nbcch_start | 0x90213444 | Copia el conteo a BSS | Ninguno |
el1_ch_nbcch_resume_req | 0x90213940 | Usa el conteo como límite del bucle | Ninguno |
LR12A...V3.P8| 2025-04-23 |