
Analyse technique de CVE-2024-20154
Classification: CWE-121 — Débordement de tampon basé sur la pile
Sévérité: Critique (bulletin MediaTek) · 8.8 Élevé, Vecteur d'attaque : Adjacent (CISA-ADP)
Type: Exécution de code à distance — aucune interaction utilisateur, aucune association préalable
Divulgation: Bulletin de sécurité MediaTek, 6 janvier 2025 https://corp.mediatek.com/product-security-bulletin/January-2025
Cible analysée: Samsung Galaxy A14 SM-A145R — famille MT6769 (Helio G80), dans la liste des chipsets affectés par MediaTek - Le firmware a été émulé dans des conditions de sécurité.
Statut: Corrigé.
Il s'agissait de ma première recherche publiée sur le modem de base. Je viens d'un milieu éloigné des infrastructures de télécommunications, des couches d'interception légale, de l'analyse des Stingray et des IMSI-catchers, et de la sécurité des dispositifs embarqués — je n'avais jamais fait de rétro-ingénierie approfondie du firmware sur un modem cellulaire. Je voulais me prouver qu'une méthodologie analytique structurée s'adapte à différentes cibles, et que la familiarité avec une plateforme spécifique peut être remplacée par un traçage rigoureux des chaînes de traitement. NB-IoT s'est démarqué car il se situe à une intersection véritablement dangereuse : le protocole est conçu pour des dispositifs IoT contraints, la surface d'attaque est pré-association, et la pile du modem le traite indépendamment de ce que l'utilisateur du téléphone est en train de faire.
Lorsque le firmware corrigé a été analysé et que le motif vulnérable a été confirmé absent, le système d'IA utilisé pour l'analyse de masse du firmware avant de cibler des fonctions spécifiques a indépendamment fait correspondre la classe de bogue reconstruite, les conditions et la famille de firmware affectée à la description de CVE-2024-20154. Les conclusions techniques sont propres à l'analyste.
Le téléphone dans votre poche contient au moins deux ordinateurs distincts. Celui avec lequel vous interagissez exécute Android. L'autre — le modem de base — fonctionne de manière totalement indépendante, gère toutes les communications radio et est presque entièrement invisible pour le système d'exploitation au-dessus. Android peut être entièrement corrigé. Le navigateur peut être isolé. L'utilisateur peut ne jamais cliquer sur un lien malveillant. Rien de tout cela n'a d'importance si le code vulnérable se trouve dans le firmware du modem qui traite les signaux radio avant que le processeur applicatif ne soit impliqué.
CVE-2024-20154 est exactement ce type de vulnérabilité.
Une diffusion d'informations système NB-IoT malformée amène le firmware du modem MediaTek à accepter un compte de planification contrôlé par l'attaquant, à transporter ce compte à travers le chemin de configuration RRC vers L1 sans jamais le limiter, et finalement à l'utiliser comme limite de boucle pour une boucle d'écriture sur la pile à l'intérieur du gestionnaire de canal de diffusion NB-IoT. Lorsque le compte dépasse la capacité des tableaux de destination, la boucle écrit au-delà, atteint les registres sauvegardés sur la pile et écrase l'adresse de retour sauvegardée. La fonction restaure alors la valeur corrompue dans le registre d'adresse de retour et saute dessus.
Ce qui rend la sévérité ce qu'elle est :
La vulnérabilité a été publiée dans le bulletin de sécurité du 6 janvier 2025 de MediaTek avec une évaluation de sévérité Critique, affectant la famille de modems LR12A entre autres. Samsung a incorporé le correctif dans sa version de maintenance de sécurité de février 2025.
Ce post ne publie pas d'exploit weaponisé et n'est pas reproductible à partir de ce qui est publié ici. L'objectif est de montrer où la chaîne se brise, pourquoi chaque couche a échoué à l'arrêter, et ce qu'il faut pour valider un bogue du modem de base de manière responsable quand on ne peut pas attacher un débogueur au modem en direct.
Cible principale : Samsung Galaxy A14 (SM-A145R). Le sous-système radio est piloté par un processeur de modem de base MediaTek de la famille de chipsets MT6769 (Helio G80). La famille MT6769 est explicitement listée dans la liste des chipsets affectés par MediaTek pour CVE-2024-20154.``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18
Le firmware de la bande de base n'est pas du code Android. Il s'agit d'un système embarqué séparé sur le sous-système radio du SoC avec son propre CPU, son propre RTOS et son propre espace mémoire, en dehors du sandbox des processus Android.
### 2.2 Architecture du modem
L'analyse du binaire extrait montre que le processeur du modem exécute du MIPS32 avec des instructions compressées MIPS16e2 en mode little-endian. MIPS16e2 est une extension de codage 16 bits pour la réduction de la taille du code embarqué — cohérente avec l'approche de MediaTek pour les bandes de base de la génération Helio, confirmée par des recherches indépendantes publiées sur cette famille de SoC.
Le système d'exploitation est Nucleus RTOS, fournissant l'ordonnancement des tâches, les files de messages IPC et un allocateur mémoire basé sur des pools. Il n'y a pas de séparation des privilèges noyau/utilisateur, aucune application d'unité de protection mémoire entre les tâches, et aucun mécanisme matériel de protection de pile.
Toutes les adresses dans cet article sont des adresses virtuelles, telles que chargées dans Ghidra à la base `0x90000000`.
### 2.3 Atténuations (observées dans la version analysée)
| Mitigation | Status | Effect |
|---|---|---|
| ASLR | Absent | Les adresses du firmware sont statiques et prévisibles à partir de l'image |
| Stack canary | Absent | `SAVE`/`RESTORE` stocke les registres sauvegardés par l'appelé sans valeur de garde |
| NX / W^X | Absent | La mémoire de la pile est exécutable |
| CFI | Absent | Les adresses de retour ne sont validées par aucune politique |
### 2.4 Approche d'analyse
Trois pistes parallèles :
**Analyse statique.** Paquet firmware Samsung → extraction de la partition CP → `md1img.img` → Ghidra (MIPS LE 32 bits, base `0x90000000`) avec les symboles d'ingénierie MediaTek récupérés de la section de débogage du firmware à l'aide de la boîte à outils `mtk_bp` du NCC Group.
**Validation dynamique.** Unicorn Engine (émulation MIPS32) a été utilisé pour exécuter des routines spécifiques du firmware de manière isolée en deux phases. La phase 1 a tenté de prouver la copie non limitée de `si_count` dans le contexte du canal via la paire d'instructions natives. La phase 2 a exécuté la boucle vulnérable sur des octets réels du firmware et a confirmé que les propres instructions du firmware corrompent l'adresse de retour sauvegardée. Là où la phase 1 n'a pas pu s'exécuter entièrement de manière native — parce que l'environnement des objets de service RTOS requis par le chemin de dispatch CPHY n'a pas été reconstruit — l'effet secondaire a été modélisé directement et étiqueté comme tel dans toutes les sorties.
**Validation côté radio.** srsRAN 4G avec une boucle de retour ZMQ — uniquement logiciel, sans émission RF — a confirmé que la charge utile de test survit au codage PHY NB-IoT et à la livraison des blocs de transport.
---
## 3. Surface d'attaque : NB-IoT et SIB1-NB
### 3.1 Surface d'attaque avant association
Le NB-IoT (Narrowband Internet of Things) est la version 13 de la 3GPP, conçue pour connecter des appareils IoT contraints en utilisant le spectre LTE sous licence existant. Il est implémenté dans une large gamme de SoC cellulaires modernes, y compris ceux des smartphones grand public.
En état RRC_IDLE, avant qu'aucune connexion RRC ne soit établie, un appareil recherchant un service va :
1. Se synchroniser avec les signaux de synchronisation de la cellule (NPSS/NSSS)
2. Décoder le bloc d'informations principales (MIB) sur NPBCH (fenêtre de transmission de 640 ms)
3. Décoder SIB1-NB depuis NPDSCH (planification de 2560 ms)
4. Utiliser les informations de planification dans SIB1-NB pour localiser des blocs d'informations système supplémentaires
À l'étape 3, le modem traite un message provenant d'une entité qu'il n'a pas authentifiée, avant toute connexion ou interaction utilisateur. Un émetteur malveillant satisfaisant les conditions normales de sélection de cellule sera traité.```
+------------------+ +---------------------+
| 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 est défini dans la 3GPP TS 36.331. Son champ schedulingInfoList transporte le nombre de messages d'informations système que la cellule diffuse, limité par la spécification à un maximum de 8 entrées (1..maxSI-Message-NB-r13 = 8). Il s'agit d'une contrainte de couche protocole. La contrainte de sécurité mémoire — à savoir que la longueur de la liste ne doit pas dépasser la capacité des tableaux de destination — doit être appliquée séparément par le firmware.
Ce n'était pas le cas.
Le firmware a été obtenu à partir d'un package CP Samsung et extrait à l'aide de l'ensemble d'outils mtk_bp de NCC Group :
bash
md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image)
→ 017_md1_dbginfo (XZ-compressed CATI debug symbols)
La section de débogage CATI a été décompressée et analysée avec `mtk_dbg_extract.py symbols`, puis importée dans Ghidra via `ImportSymbolsScript.py`. Le résultat a été les noms complets des fonctions internes dans toute la pile modem — couche ERRC, gestion de canal L1, sous-système IPC, et la chaîne de gestionnaire BCCH NB-IoT — permettant une reconstruction de chaîne guidée par la sémantique.
Tous les noms de fonctions dans cet article proviennent des symboles de débogage intégrés de MediaTek extraits de l'image du firmware.
---
## 5. Vulnérabilité
### 5.1 La boucle vulnérable
`el1_ch_nbcch_resume_req` (`0x90213940`) gère l'événement de reprise du canal de diffusion NB-IoT. Son prologue de fonction MIPS16e2 :
````asm
90213940: save 0xE8, ra, s0-s1
L'instruction SAVE décrémente sp de 0xE8 et stocke les registres sauvegardés par l'appelé vers le bas :```
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
À partir de la décompilation Ghidra du binaire du firmware réel :```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] est ch_ctx[+0x40A] — un octet persistant dans la structure BSS du contexte de canal.
La limite de boucle est utilisée directement, sans comparaison préalable avec les capacités du tableau.
Le flux A (écritures en demi-mot sh) commence à new_sp+0x98 et avance de 2 octets par itération.
Il atteint le RA sauvegardé à new_sp+0xE4 à l'itération 38 :```
new_sp + 0x98 + i×2 = new_sp + 0xE4
i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38
Flux B (byte `sb` writes) commence à `new_sp+0x78` et nécessiterait l'itération 108 pour atteindre l'emplacement RA :```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108
Avec si_count = 40 (la valeur de démonstration choisie pour dépasser le seuil de débordement de 38), la boucle exécute 40 itérations. Le flux B n'atteint jamais l'emplacement de RA. La corruption de RA provient entièrement du flux A.
Après 40 itérations, l'instruction MIPS16e2 RESTORE recharge la valeur corrompue de la pile dans $ra, et jrc ra transfère le contrôle.
ch_ctx[+0x40A] est écrit par el1_ch_nbcch_start à 0x90213444. Deux instructions MIPS consécutives sans rien entre elles :```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 Le constructeur ERRC — Couche A
Le tampon CPHY_CFG_REQ est construit dans la couche ERRC à partir du SIB1-NB décodé. La fonction `errc_chm_l1_set_bcch_si_reception` écrit `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
}
}
La limite de boucle est le nombre d'entrées décodées provenant de SIB1-NB. Le compteur s'incrémente une fois par entrée décodée, pour autant d'entrées que décodées, sans garde maximale.
Une fois le tampon CPHY_CFG_REQ rempli, ERRC le transmet à L1 avec sap_id = 0x501F comme clé de routage :```
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 Absence de limitation sur trois couches
| Couche | Fonction | Adresse | Limiteur présent ? |
|---|---|---|---|
| A — Constructeur ERRC | `errc_chm_l1_set_bcch_si_reception` | Plage ERRC | **Aucun** |
| B — Copie L1 | `el1_ch_nbcch_start` | `0x90213444` | **Aucun** |
| C — Boucle L1 | `el1_ch_nbcch_resume_req` | `0x90213940` | **Aucun** |
Un seul contrôle à n'importe quelle couche aurait brisé la chaîne.
### 5.7 Cause racine
Un invariant violé :
> Le nombre d'entrées de planification SI ne doit jamais dépasser la capacité du tableau de destination.
La 3GPP fournit la limite protocolaire prévue (8 entrées). Le firmware devait appliquer la
limite de sécurité mémoire à chaque couche où le nombre devient un indice ou une limite de boucle. Dans la
version vulnérable, le nombre a voyagé depuis le champ de diffusion SIB1-NB à travers le décodeur
ERRC, dans le message CPHY_CFG_REQ, à travers une frontière IPC dans la tâche L1, dans
le contexte de canal BSS, et dans une boucle d'écriture sur la pile — sans qu'aucune couche ne le limite.
---
## 6. La chaîne d'appels — Comment elle a été trouvée
### 6.1 La confusion des deux chemins
Deux chemins structurellement similaires mais distincts peuvent livrer un tampon de configuration de 0x760 octets à
`el1_ch_nbcch_main` :
| Chemin | Source | Valeur de `[+0x99]` | Pertinence |
|---|---|---|---|
| Chemin A (ERRC → IPC L1) | ERRC construit CPHY_CFG_REQ à partir du SIB1-NB décodé | `schedulingInfoList.count` depuis l'OTA | **Le chemin vulnérable** |
| Chemin B (interne L1) | `el1_ch_scs_ind_send` construit le corps IPC interne | 1 codé en dur | Non vulnérable |
Le chemin B a confirmé le format du message — l'octet `+0x99` est le nombre SI consommé par
`el1_ch_nbcch_start`. Comme son nombre est toujours codé en dur à 1, il ne peut pas déborder. Le
chemin influencé de l'extérieur est le Chemin A.
### 6.2 La recherche de l'écriture
La recherche par motif dans le firmware de toute instruction écrivant à l'offset `+0x99` a produit du bruit :
T1 (`sb` direct, ~100 hits), T2 (base scindée, 5 hits), T3 (offset calculé, 0), T4
(`sh`/`sw` chevauchants, ~465). Les fonctions de gestion de canal ERRC étaient absentes de la
liste de références croisées `msg_send6` car ERRC utilise `errc_com_send_msg`. Une sonde
d'émulation a confirmé que l'écriture était côté ERRC : l'exécution du harnais Unicorn depuis le dispatcher L1
et la surveillance des écritures sur l'offset `+0x99` du tampon n'ont rien capturé du côté 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.
En suivant sap_id = 0x501F dans errc_com_send_msg, on identifie le routage vers
el1_chmgm_errc_cfg_req_in_idle, qui stocke le pointeur CPHY_CFG_REQ à
L1_ctx[+0x323C] et commence la distribution en aval.
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. Validation
Ce modèle SM-A145R spécifique ne semble pas exercer le chemin de code NB-IoT vulnérable en fonctionnement normal du ship build, c'est pourquoi l'émulation hybride et l'analyse statique ont été utilisées plutôt qu'une reproduction matérielle directe.
**Prouvé statiquement.** Le binaire du firmware contient la paire d'instructions vulnérable. La chaîne d'appel est reconstruite à partir des symboles, des références croisées et des corps de fonctions décompilés.
**Exécuté nativement en émulation.** La boucle à l'intérieur de `el1_ch_nbcch_resume_req` a été exécutée sur des octets réels du firmware MediaTek dans Unicorn Engine (MIPS32). L'instruction `sh` du firmware à `0x90213B02` a écrit dans l'emplacement de l'adresse de retour sauvegardée. L'instruction `RESTORE` a chargé la valeur corrompue dans `$ra`, et `jrc ra` a transféré le contrôle.
**Modélisé explicitement.** La copie `lbu`/`sb` dans `el1_ch_nbcch_start` n'a pas pu être entièrement exécutée nativement parce que le chemin de dispatch de table de callback du RTOS à l'intérieur de `el1_ch_nbcch_cphy_cfg_req_process` attendait des objets heap Nucleus vivants que l'émulateur plat ne fournissait pas. Le gestionnaire de reprise (`el1_ch_nbcch_resume_req`) en phase 2 ne lit que depuis le contexte de canal résident BSS et n'emprunte pas ce même chemin de dispatch, c'est pourquoi la phase 2 a été exécutée nativement sans nécessiter le même échafaudage. L'effet de bord de la phase 1 — un octet de `IPC_msg[+0x99]` écrit dans `ch_ctx[+0x40A]` — a été modélisé directement et étiqueté `[PHASE1-MODEL]`.
**Non revendiqué.** Une reproduction matérielle complète de bout en bout par liaison radio.
### 7.1 Anti-altération
Le harness a imposé une règle : aucun hook n'était autorisé à écrire le marqueur de preuve dans l'emplacement de l'adresse de retour sauvegardée. Chaque écriture mémoire non firmware a été tracée.```
[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 est l'instruction sh à l'intérieur du corps de la boucle. Le firmware a placé ces octets au décalage de pile prédit. En stockage petit-boutiste, les demi-mots 0xBEEF et 0xDEAD à new_sp+0xE4 et new_sp+0xE6 se combinent en [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 Livraison ZMQ
Pour confirmer que la charge utile de test survit à l'encodage PHY NB-IoT et à la livraison de blocs de transport, srsRAN
4G avec une boucle de retour ZMQ (aucune émission RF) a été utilisé. La charge utile était un vecteur délibérément
non conforme — la contrainte SIZE de l'ASN.1 sur `schedulingInfoList` a été assouplie pour
autoriser 40 entrées, avec un décodage aller-retour pycrate confirmant que le champ de comptage se trouve à l'octet 14.```
SIB1 received
SIB2 activated
exit 0
Ceci confirme la livraison au niveau transport. Le comportement ASN.1 côté firmware est établi par l'analyse statique de la couche A.
La tâche el1_ch possède une seule pile. La phase 1 et la phase 2 sont deux événements IPC distincts traités séquentiellement par la même tâche, la pile se déroulant complètement entre eux. Le compteur persiste dans le contexte de canal BSS, pas sur la pile :```
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]` réside dans BSS et conserve la valeur de l'attaquant jusqu'à ce que le modem se réinitialise ou qu'une configuration de canal ultérieure l'écrase.
### 8.2 Trame de pile```
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]
Taille de trame confirmée par mesure d'émulation. Positions des tableaux confirmées par le résultat d'émulation — RA écrit à l'itération 38, cohérent avec si_sched_arr commençant à new_sp+0x98.
| Version | Firmware du modem | Date de build |
|---|---|---|
| Vulnérable | A145RXXU1AWD1, MOLY LR12A...V1.P5 | 2023-04-18 |
| Corrigé | A145RXXUDDZC2, MOLY LR12A...V3.P8 |
Dates de build confirmées par extraction des métadonnées md1_dbginfo des deux images. ID du correctif : MOLY00720348 · ID de l'incident : MSV-2392.
el1_ch_nbcch_start (0x90213444 dans le binaire vulnérable) : La paire d'instructions lbu/sb est absente. La copie directe de IPC_msg[+0x99] dans ch_ctx[+0x40A] a disparu.
el1_ch_nbcch_resume_req (0x90213940 dans le binaire vulnérable) : La boucle d'écriture dans la pile sur ch_ctx[0x40A] est absente. L'architecture où un octet non fiable devient une limite de boucle sur des tableaux de pile de taille fixe n'existe plus. Le corps de la fonction est remplacé par une structure de dispatch différente.
errc_chm_l1_set_bcch_si_reception : La boucle de compteur sans limite est remplacée par des appels d'assistants orientés validation.
Deux fonctions présentes dans le binaire corrigé sont absentes du binaire vulnérable :``` el1_ch_nbcch_param_check el1_ch_scell_param_check
Un contrôle de limites sur une seule ligne apparaîtrait comme quelques instructions ajoutées à l'intérieur d'une fonction existante à la même adresse. Ce que montre le binaire corrigé, c'est une révision architecturale : le chemin de planification NBCCH a été repensé de sorte que le motif `si_count` utilisé comme limite de boucle n'existe plus nulle part dans ce chemin.
### 10.4 Attribution CVE
La vulnérabilité décrite ici correspond à CVE-2024-20154 telle que publiée par MediaTek le 6 janvier 2025. Base de confirmation :
- La famille de firmware affectée (LR12A) correspond au bulletin de MediaTek.
- La classe de vulnérabilité — débordement de pile, absence de contrôle des limites, RCE à partir d'une station de base malveillante, aucune interaction utilisateur — correspond à la description CVE et à l'enregistrement NVD.
- Le firmware corrigé supprime exactement les structures de code identifiées comme vulnérables.
- L'ID de correctif MOLY00720348 est confirmé à partir du bulletin de MediaTek et du Bulletin de sécurité Android (A-376809176).
- L'analyse assistée par IA a indépendamment fait correspondre le motif reconstruit à CVE-2024-20154 avant confirmation manuelle.
---
## 11. Éthique et Divulgation Responsable
### 11.1 Ce que cet article ne contient pas
Aucun exploit militarisé. Aucun contenu binaire du firmware. Aucun octet de charge utile malformé. Aucune procédure pas à pas pour déclencher la vulnérabilité sur un appareil réel. Les informations nécessaires pour reproduire une attaque fonctionnelle — construction complète de la charge utile pour le décodeur de modem spécifique, échafaudage d'objets tas RTOS pour une émulation complète de la phase 1, configuration radio over-the-air — sont délibérément absentes.
### 11.2 Pourquoi la boucle de retour ZMQ et l'émulation sont l'approche éthique
La boucle de retour ZMQ signifie qu'aucun signal n'a jamais été transmis par voie hertzienne. Aucun appareil réel n'a été ciblé. Aucun réseau d'opérateur n'a été impliqué. La preuve s'exécute entièrement dans un environnement logiciel confiné sur du matériel appartenant à l'analyste. C'est l'approche correcte pour valider une vulnérabilité radio de pré-association — transmettre une diffusion malformée affecterait tout appareil à portée.
L'émulation Unicorn démontre que le comportement vulnérable se trouve dans le binaire du firmware lui-même, de manière reproductible, indépendamment de tout état d'appareil spécifique ou environnement radio. C'est une affirmation techniquement plus solide qu'un simple crash matériel, et cela évite de déployer quoi que ce soit par voie hertzienne.
### 11.3 Propriété intellectuelle de MediaTek
Toute l'analyse a été effectuée sur un firmware obtenu légitimement à partir d'un appareil grand public et des packages de firmware publiés publiquement par Samsung. Aucune documentation propriétaire n'a été utilisée. Les définitions de structures internes de MediaTek et les formats de messages IPC ne sont décrits que dans la mesure nécessaire pour expliquer la défaillance de sécurité mémoire. Ils ne sont pas publiés en tant que spécifications.
---
| Itération | sh écrit dans | Effet |
|---|
| 0–33 | si_sched_arr[0..33] | Dans les limites |
| 34–35 | new_sp+0xDC — s0 sauvegardé | s0 corrompu |
| 36–37 | new_sp+0xE0 — s1 sauvegardé | s1 corrompu |
| 38 | new_sp+0xE4 — ra sauvegardé [15:0] | Demi-mot faible de RA |
| 39 | new_sp+0xE6 — ra sauvegardé [31:16] | Demi-mot fort de RA |
| Barrière | Condition | Où vérifié |
|---|
| Chemin actif NB-IoT | cfg_type == 1 | el1_ch_nbcch_cphy_cfg_req_process |
| Canal non terminé | done_flag == 0 | ch_ctx[0x438] |
Machine d'état 0x0B | NBCCH en état de reprise | dispatch el1_ch_nbcch_main |
| si_count non nul | ch_ctx[0x40A] > 0 | Condition de boucle |
| Classe de bande ≤ 2 | Mode NB-IoT valide | Entrée de el1_ch_nbcch_resume_req |
el1_chmgm_cell_info_get non nul | Cellule dans table de service | Appelé dans el1_ch_nbcch_start |
| Fonction | Adresse | Rôle | Écrêtage ? |
|---|
errc_chm_l1_set_bcch_si_reception | Plage ERRC | Écrit CPHY_CFG_REQ[+0x99] | Aucun |
el1_ch_nbcch_cphy_cfg_req_process | 0x90213F80 | Achemine la config CPHY vers L1 | N/A — ne lit pas si_count |
el1_chmgm_cell_info_get | 0x9020E0D0 | Valide EARFCN/PCI | N/A |
el1_ch_nbcch_start | 0x90213444 | Copie le compteur vers BSS | Aucun |
el1_ch_nbcch_resume_req | 0x90213940 | Utilise le compteur comme limite de boucle | Aucun |
| 2025-04-23 |