Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2024-20154 — CVE-2024-20154 기술 분석 | Kitploit
도구/GitHubGitHub/sneakid/cve-2024-20154
Embedded Systems SecurityIoT SecurityVulnerability AnalysisExploitationReverse EngineeringMobile SecurityPapers & ResearchLearning & EducationFirmware AnalysisBinary Exploitation
GitHubsneakid/cve-2024-20154
212개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2024-20154

CVE-2024-20154 기술 분석

저장소 보기

CVE-2024-20154: MediaTek MT6769 베이스밴드의 NB-IoT SIB1-NB 스택 오버플로

분류: CWE-121 — 스택 기반 버퍼 오버플로
심각도: Critical (MediaTek 게시판) · 8.8 높음(High), 공격 벡터: 인접(Adjacent) (CISA-ADP)
유형: 원격 코드 실행 — 사용자 상호작용 불필요, 사전 연관 불필요
공개: MediaTek 보안 게시판, 2025년 1월 6일 https://corp.mediatek.com/product-security-bulletin/January-2025 분석 대상: 삼성 갤럭시 A14 SM-A145R — MT6769 제품군(Helio G80), MediaTek의 영향 칩셋 목록에 포함 - 펌웨어는 안전한 조건에서 에뮬레이션되었습니다. 상태: 패치됨.


배경 및 동기

이것은 내가 처음으로 공개한 베이스밴드 연구였다. 나는 통신 인프라, 합법적 감청 중재 계층, 스팅레이(Stingray) 및 IMSI-캐처 분석, 임베디드 기기 보안과는 거리가 먼 배경에서 왔으며, 이전에 셀룰러 모뎀 펌웨어에 대한 깊이 있는 리버스 엔지니어링을 해본 적이 없었다. 나는 구조화된 분석 방법론이 대상에 관계없이 적용되며, 특정 플랫폼에 대한 친숙함은 엄격한 체인 추적으로 대체될 수 있음을 스스로에게 증명하고 싶었다. NB-IoT는 진정으로 위험한 교차점에 위치하기 때문에 눈에 띄었다. 이 프로토콜은 제약이 많은 IoT 기기를 위해 설계되었고, 공격 표면은 사전 연관 단계에 있으며, 모뎀 스택은 핸드셋 사용자가 무엇을 하고 있든 관계없이 이를 처리한다.

패치된 펌웨어를 분석하고 취약한 패턴이 없는 것을 확인했을 때, 특정 기능을 대상으로 삼기 전에 펌웨어의 대량 분석에 사용된 AI 시스템은 재구성된 버그 클래스, 조건, 영향받는 펌웨어 제품군을 CVE-2024-20154의 설명과 독립적으로 일치시켰습니다.

기술적 결론은 분석자의 몫입니다.


1. 서론

당신 주머니 속의 전화기에는 최소한 두 대의 분리된 컴퓨터가 들어 있습니다. 당신이 상호작용하는 것은 Android를 실행합니다. 다른 하나 — 베이스밴드 — 는 완전히 독립적으로 실행되며 모든 무선 통신을 처리하고, 그 위의 운영체제에서는 거의 완전히 보이지 않습니다. Android는 완전히 패치되어 있을 수 있습니다. 브라우저는 샌드박스 처리되어 있을 수 있습니다. 사용자는 악성 링크를 한 번도 탭하지 않을 수 있습니다. 취약한 코드가 애플리케이션 프로세서가 개입하기 전에 무선 신호를 처리하는 모뎀 펌웨어에 있다면 그 어느 것도 중요하지 않습니다.

CVE-2024-20154는 바로 그런 종류의 취약점입니다.

잘못된 형태의 NB-IoT 시스템 정보 브로드캐스트로 인해 MediaTek 모뎀 펌웨어는 공격자가 제어하는 스케줄링 횟수를 수용하고, 그 횟수를 결코 클램핑하지 않은 채 RRC-to-L1 구성 경로를 통과시킨 다음, 결국 NB-IoT 브로드캐스트 채널 핸들러 내부의 스택 쓰기 루프의 루프 경계로 사용하게 됩니다. 횟수가 대상 배열의 용량을 초과하면 루프는 배열을 지나쳐 쓰게 되고, 스택의 저장된 레지스터에 도달한 다음 저장된 반환 주소를 덮어씁니다. 그러면 함수는 손상된 값을 반환 주소 레지스터로 복원하고 그 주소로 점프합니다.

심각도가 이렇게 높은 이유는 다음과 같습니다:

  • 취약한 코드 경로는 셀 캠핑 중에 실행됩니다 — 셀에 동기화한 후이지만 RRC 연결, 인증, 사용자 상호작용이 일어나기 전입니다.
  • 입력은 무선(over-the-air) 브로드캐스트입니다. 전화기는 출처를 인증할 수 없습니다.
  • 분석된 빌드의 베이스밴드 펌웨어는 ASLR 없이, 스택 카나리 없이, 비실행 스택 없이, 제어 흐름 무결성 없이 실행됩니다. 저장된 반환 주소 덮어쓰기는 프로그램 카운터 제어로 직접 이어집니다.

이 취약점은 MediaTek의 2025년 1월 6일 보안 게시판에 Critical 심각도 등급으로 게시되었으며, LR12A 모뎀 제품군을 비롯한 여러 제품군에 영향을 미칩니다. 삼성은 2025년 2월 보안 유지보수 릴리스에 이 수정을 포함했습니다.

이 게시물은 무기화된 익스플로잇을 공개하지 않으며, 여기에 공개된 내용만으로는 재현할 수 없습니다. 목표는 체인이 어디서 끊어지는지, 각 계층이 왜 이를 막지 못했는지, 그리고 실제 모뎀에 디버거를 연결할 수 없을 때 베이스밴드 버그를 책임 있게 검증하려면 무엇이 필요한지 보여주는 것입니다.


2. 대상 및 환경

2.1 기기 및 펌웨어

주요 대상: 삼성 갤럭시 A14 (SM-A145R). 무선 서브시스템은 MT6769 칩셋 제품군(Helio G80)의 MediaTek 베이스밴드 프로세서로 구동됩니다. MT6769 제품군은 CVE-2024-20154에 대한 MediaTek의 영향 칩셋 목록에 명시적으로 포함되어 있습니다.``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18

root@kitploit:~
The baseband firmware is not Android code. It is a separate embedded system on the radio
subsystem of the SoC with its own CPU, its own RTOS, and its own memory space, outside the
Android process sandbox.

베이스밴드 펌웨어는 Android 코드가 아닙니다. 이는 SoC의 무선(radio) 하위 시스템에 있는 별도의 임베디드 시스템으로, 자체 CPU, 자체 RTOS, 자체 메모리 공간을 가지며 Android 프로세스 샌드박스 밖에 있습니다.

### 2.2 Modem architecture

### 2.2 모뎀 아키텍처

Analysis of the extracted binary shows the modem processor runs MIPS32 with MIPS16e2
compressed instructions in little-endian mode. MIPS16e2 is a 16-bit encoding extension for
embedded code-size reduction — consistent with MediaTek's approach for Helio-generation
basebands, confirmed by independent published baseband research on this SoC family.

추출된 바이너리 분석 결과, 모뎀 프로세서는 little-endian 모드에서 MIPS16e2 압축 명령어가 포함된 MIPS32를 실행합니다. MIPS16e2는 임베디드 코드 크기 축소를 위한 16비트 인코딩 확장으로, Helio 세대 베이스밴드에 대한 MediaTek의 방식과 일치하며, 이 SoC 제품군에 대한 독립적으로 발표된 베이스밴드 연구로 확인되었습니다.

The operating system is Nucleus RTOS, providing task scheduling, IPC message queues, and a
pool-based memory allocator. There is no kernel/user privilege separation, no memory
protection unit enforcement between tasks, and no hardware stack-guard mechanism.

운영체제는 Nucleus RTOS로, 태스크 스케줄링, IPC 메시지 큐, 풀 기반 메모리 할당자를 제공합니다. 커널/사용자 권한 분리, 태스크 간 메모리 보호 유닛(MPU) 적용, 하드웨어 스택 가드 메커니즘은 없습니다.

All addresses in this post are virtual addresses, as loaded in Ghidra at base `0x90000000`.

이 글의 모든 주소는 Ghidra에서 베이스 `0x90000000`로 로드된 가상 주소입니다.

### 2.3 Mitigations (observed in analyzed build)

### 2.3 완화 조치 (분석된 빌드에서 관찰됨)

| Mitigation | Status | Effect |
|---|---|---|
| ASLR | Absent | Firmware addresses are static and predictable from the image |
| Stack canary | Absent | `SAVE`/`RESTORE` stores callee-saved registers with no guard value |
| NX / W^X | Absent | Stack memory is executable |
| CFI | Absent | Return addresses are not validated against any policy |

| 완화 조치 | 상태 | 효과 |
|---|---|---|
| ASLR | 부재 | 펌웨어 주소는 이미지로부터 정적이고 예측 가능함 |
| Stack canary | 부재 | `SAVE`/`RESTORE`는 가드 값 없이 호출자 저장 레지스터를 저장함 |
| NX / W^X | 부재 | 스택 메모리는 실행 가능함 |
| CFI | 부재 | 반환 주소는 어떤 정책으로도 검증되지 않음 |

### 2.4 Analysis approach

### 2.4 분석 접근법

Three parallel tracks:

세 개의 병렬 트랙:

**Static analysis.** Samsung firmware package → CP partition extraction → `md1img.img` →
Ghidra (MIPS LE 32-bit, base `0x90000000`) with MediaTek engineering symbols recovered from
the firmware debug section using the NCC Group `mtk_bp` toolset.

**정적 분석.** Samsung 펌웨어 패키지 → CP 파티션 추출 → `md1img.img` → Ghidra (MIPS LE 32-bit, base `0x90000000`) 및 NCC Group `mtk_bp` 도구 모음을 사용해 펌웨어 디버그 섹션에서 복구한 MediaTek 엔지니어링 심볼.

**Dynamic validation.** Unicorn Engine (MIPS32 emulation) was used to execute specific
firmware routines in isolation across two phases. Phase 1 attempted to prove the unclamped
copy of `si_count` into channel context through the native instruction pair. Phase 2 executed
the vulnerable loop on real firmware bytes and confirmed that the firmware's own instructions
corrupt the saved return address. Where Phase 1 could not run fully natively — because the
RTOS service-object environment required by the CPHY dispatch path was not reconstructed —
the side effect was modeled directly and labeled as such in all output.

**동적 검증.** Unicorn Engine(MIPS32 에뮬레이션)을 사용하여 두 단계에 걸쳐 특정 펌웨어 루틴을 격리된 상태로 실행했습니다. 1단계에서는 네이티브 명령어 쌍을 통해 `si_count`를 채널 컨텍스트로 복사할 때 클램프(clamp) 없이 복사하는 동작을 증명하려 했습니다. 2단계에서는 실제 펌웨어 바이트로 취약한 루프를 실행하여 펌웨어 자체의 명령어가 저장된 반환 주소를 손상시킨다는 것을 확인했습니다. 1단계가 완전히 네이티브로 실행되지 못한 경우(CPHY 디스패치 경로에 필요한 RTOS 서비스 객체 환경이 재구성되지 않았기 때문에) 부수 효과를 직접 모델링했고, 모든 출력에 그렇게 표시했습니다.

**Radio-side validation.** srsRAN 4G with a ZMQ loopback — software-only, no RF emission —
confirmed that the test payload survives NB-IoT PHY encoding and transport-block delivery.

**무선 측 검증.** ZMQ 루프백을 사용하는 srsRAN 4G — 소프트웨어 전용, RF 방사 없음 — 를 통해 테스트 페이로드가 NB-IoT PHY 인코딩과 전송 블록(transport block) 전달을 통과함을 확인했습니다.

---

## 3. Attack Surface: NB-IoT and SIB1-NB

## 3. 공격 표면: NB-IoT 및 SIB1-NB

### 3.1 Pre-association attack surface

### 3.1 연결 전(pre-association) 공격 표면

NB-IoT (Narrowband Internet of Things) is 3GPP Release 13, designed to connect constrained
IoT devices using existing licensed LTE spectrum. It is implemented in a wide range of modern
cellular SoCs including those in consumer smartphones.

NB-IoT(Narrowband Internet of Things)는 3GPP Release 13으로, 기존의 면허 LTE 대역을 사용하여 제한된(constrained) IoT 기기를 연결하도록 설계되었습니다. 소비자용 스마트폰에 탑재된 SoC를 포함한 다양한 최신 셀룰러 SoC에 구현되어 있습니다.

While in RRC_IDLE, before any RRC connection is established, a device searching for service
will:

RRC_IDLE 상태에서 RRC 연결이 설정되기 전에, 서비스를 검색하는 기기는 다음을 수행합니다:

1. Synchronize with the cell's timing signals (NPSS/NSSS)
2. Decode the Master Information Block over NPBCH (640 ms transmission window)
3. Decode SIB1-NB from NPDSCH (2560 ms schedule)
4. Use the scheduling information in SIB1-NB to locate additional system information blocks

1. 셀의 타이밍 신호(NPSS/NSSS)와 동기화
2. NPBCH를 통해 마스터 정보 블록(Master Information Block)을 디코딩(640 ms 전송 창)
3. NPDSCH에서 SIB1-NB를 디코딩(2560 ms 스케줄)
4. SIB1-NB의 스케줄링 정보를 사용하여 추가 시스템 정보 블록을 찾음

At step 3, the modem processes a message from an entity it has not authenticated, before any
connection or user interaction. A rogue transmitter satisfying normal cell selection
conditions will be processed.

3단계에서 모뎀은 연결이나 사용자 상호작용이 발생하기 전에 인증되지 않은 엔티티로부터 온 메시지를 처리합니다. 정상적인 셀 선택 조건을 충족하는 악성(rogue) 송신기도 처리됩니다.```
+------------------+                   +---------------------+
|  Rogue Base Stn  |                   |  Target UE (Modem)  |
+--------+---------+                   +----------+----------+
         |                                        |
         |   NPSS/NSSS sync                      |
         |--------------------------------------->|
         |   MIB-NB (640 ms cycle)                |
         |--------------------------------------->|
         |   SIB1-NB (malformed, si_count > 8)    |
         |--------------------------------------->|   ← vulnerability triggered
         |   [no RRC connection established]      |

3.2 스케줄링 카운트 필드

SIB1-NB는 3GPP TS 36.331에 정의되어 있다. 해당 schedulingInfoList 필드는 셀이 브로드캐스트하는 System Information 메시지의 개수를 전달하며, 사양상 최대 8개의 항목(1..maxSI-Message-NB-r13 = 8)으로 제한된다. 이는 프로토콜 계층의 제약이다. 메모리 안전성 제약 — 즉 목록 길이가 대상 배열의 용량을 초과해서는 안 된다는 제약 — 은 펌웨어가 별도로 강제해야 한다.

그렇지 않았다.


4. 펌웨어 추출 및 심볼 복구

펌웨어는 Samsung CP 패키지에서 획득했으며 NCC Group mtk_bp 도구 세트를 사용하여 추출했다:``` md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image) → 017_md1_dbginfo (XZ-compressed CATI debug symbols)

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

이 게시물의 모든 함수 이름은 펌웨어 이미지에서 추출한 MediaTek 자체 임베디드 디버그 심볼에서 비롯된 것입니다.

---

## 5. 취약점

### 5.1 취약한 루프

`el1_ch_nbcch_resume_req` (`0x90213940`)는 NB-IoT 브로드캐스트 채널 재개 이벤트를 처리합니다.  
해당 MIPS16e2 함수 프롤로그:```asm
90213940:  save  0xE8, ra, s0-s1

SAVE 명령어는 sp를 0xE8만큼 감소시키고 callee-saved 레지스터를 아래쪽으로 저장합니다:``` old_sp (= new_sp + 0xE8) new_sp + 0xE4 saved ra ← overflow target new_sp + 0xE0 saved s1 new_sp + 0xDC saved s0 new_sp + 0x98 si_sched_arr [34 halfwords = 68 bytes] new_sp + 0x78 si_type_arr [32 bytes] new_sp + 0x00 ← stack pointer after SAVE

root@kitploit:~
실제 펌웨어 바이너리의 Ghidra 디컴파일 결과:```c
for (uVar6 = 0; uVar6 < (byte)param_2[0x40a]; uVar6 = uVar6 + 1) {
    si_type_arr[uVar6]  = /* SI type byte */;          // 1 byte/iter, base new_sp+0x78
    si_sched_arr[uVar6] = /* SI schedule halfword */;  // 2 bytes/iter, base new_sp+0x98
}

param_2[0x40a]는 ch_ctx[+0x40A] — 채널 컨텍스트 BSS 구조체의 지속적인 바이트입니다. 루프 경계는 배열 용량과 사전 비교 없이 직접 사용됩니다.

5.2 오버플로 산술

스트림 A(하프워드 sh 쓰기)는 new_sp+0x98에서 시작하여 반복마다 2바이트씩 진행됩니다. 38번째 반복에서 new_sp+0xE4의 저장된 RA에 도달합니다:``` new_sp + 0x98 + i×2 = new_sp + 0xE4 i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38

root@kitploit:~
Stream B(바이트 `sb` 쓰기)는 `new_sp+0x78`에서 시작하며 RA 슬롯에 도달하려면 반복 108이 필요합니다:```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108

si_count = 40 (오버플로 임계값 38을 초과하도록 선택된 데모 값)일 때 루프는 40회 반복됩니다. Stream B는 결코 RA 슬롯에 도달하지 않습니다. RA 손상은 전적으로 Stream A에서 비롯됩니다.

40회 반복 후, MIPS16e2 RESTORE 명령어는 손상된 값을 스택에서 $ra로 다시 로드하고, jrc ra가 제어를 전송합니다.

5.3 클램프되지 않은 복사 — Layer B

ch_ctx[+0x40A]는 0x90213444에서 el1_ch_nbcch_start에 의해 쓰여집니다. 그 사이에 아무것도 없는 두 개의 연속된 MIPS 명령어:```asm ; el1_ch_nbcch_start @ 0x90213444 lbu v0, 0x99(s0) ; read IPC_msg[+0x99] = si_count from CPHY_CFG_REQ sb v0, 0x40A(s1) ; write to ch_ctx[+0x40A] — no clamp, no mask, no compare

root@kitploit:~
### 5.4 ERRC 빌더 — 레이어 A

CPHY_CFG_REQ 버퍼는 디코딩된 SIB1-NB로부터 ERRC 레이어에서 빌드됩니다. 함수
`errc_chm_l1_set_bcch_si_reception`은 `IPC_msg[+0x99]`를 기록합니다:```c
// errc_chm_l1_set_bcch_si_reception — Layer A
// Loop bound: decoded schedulingInfoList entry count from SIB1-NB

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

루프 상한은 SIB1-NB에서 디코딩된 엔트리 수입니다. 카운터는 디코딩된 엔트리마다 한 번씩 증가하며, 디코딩된 엔트리 수만큼 증가하고, 최대 상한이 없습니다.

5.5 IPC 경로

CPHY_CFG_REQ 버퍼가 채워지면, ERRC는 sap_id = 0x501F를 라우팅 키로 사용하여 L1로 디스패치합니다:``` el1_ch_rcv_ilm (sap 0x501F) → el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C] → el1_chmgm_nbcch_handler → el1_ch_nbcch_main → el1_ch_nbcch_cphy_cfg_req_process ← validates cell identity, no si_count check → el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp

root@kitploit:~
### 5.6 3계층 클램핑 부재

| 계층 | 함수 | 주소 | 클램프 존재? |
|---|---|---|---|
| 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가 디코딩된 SIB1-NB에서 CPHY_CFG_REQ 구성 | OTA의 `schedulingInfoList.count` | **취약 경로** |
| 경로 B (L1 내부) | `el1_ch_scs_ind_send`가 내부 IPC 본문 구성 | 하드코딩된 `1` | 취약하지 않음 |

경로 B가 메시지 형식을 확인해 주었다 — 바이트 `+0x99`는 `el1_ch_nbcch_start`가 소비하는 SI 카운트다. 그 카운트는 항상 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 측임을 확인했다: L1 디스패처에서 Unicorn 하네스를 실행하고 버퍼의 `+0x99` 오프셋에 대한 쓰기를 감시했지만 L1 측에서는 아무것도 포착되지 않았다.```
[RUN] dispatcher=0x90214418  watching IPC_msg+0x99

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

6.3 IPC 라우팅 키를 통한 해석

errc_com_send_msg에서 sap_id = 0x501F를 추적하여 el1_chmgm_errc_cfg_req_in_idle로의 라우팅을 확인했으며, 이 함수는 CPHY_CFG_REQ 포인터를 L1_ctx[+0x323C]에 저장하고 하위 디스패치를 시작한다.

6.4 확인된 호출 체인```

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

root@kitploit:~
---
## 7. 검증

이 특정 SM-A145R 모델은 일반적인 출고 빌드 운영에서
취약한 NB-IoT 코드 경로를 실행하지 않는 것으로 보이므로, 하이브리드
에뮬레이션과 정적 분석이 직접적인 하드웨어 재현 대신 사용되었습니다.

**정적으로 입증됨.** 펌웨어 바이너리에는 취약한 명령어 쌍이 포함되어 있습니다. 호출
체인은 심볼, 상호 참조, 그리고 디컴파일된 함수 본문에서 재구성되었습니다.

**에뮬레이션에서 네이티브로 실행됨.** `el1_ch_nbcch_resume_req` 내부의 루프는 실제
MediaTek 펌웨어 바이트로 Unicorn Engine (MIPS32)에서 실행되었습니다.
`0x90213B02`에 있는 펌웨어 자체의 `sh` 명령어가 저장된 복귀 주소 슬롯에 기록했습니다. `RESTORE` 명령어는 손상된 값을
`$ra`에 로드했고, `jrc ra`가 제어권을 전달했습니다.

**명시적으로 모델링됨.** `el1_ch_nbcch_start`의 `lbu`/`sb` 복사는 완전히
네이티브로 실행될 수 없었습니다. RTOS 콜백 테이블 디스패치 경로가 `el1_ch_nbcch_cphy_cfg_req_
process` 내부에 있기 때문인데, 이 경로는 플랫 에뮬레이터가 제공하지 않는 라이브 Nucleus 힙 객체를
기대했습니다. Phase 2의 재개 핸들러(`el1_ch_nbcch_resume_req`)는 BSS 상주 채널 컨텍스트에서만
읽으며 동일한 디스패치 경로를 만나지 않으므로, Phase 2는 동일한 스캐폴딩 없이도
네이티브로 실행되었습니다. Phase 1 부작용 — `IPC_msg[+0x99]`의 1바이트가
`ch_ctx[+0x40A]`에 기록됨 — 은 직접 모델링되어 `[PHASE1-MODEL]`로 표시되었습니다.

**주장하지 않음.** 완전한 종단 간 OTA 하드웨어 재현.

### 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 명령어입니다. 펌웨어는 이 바이트들을 예측된 스택 오프셋에 배치했습니다. 리틀엔디언 저장 방식에서 new_sp+0xE4 및 new_sp+0xE6에 있는 하프워드 0xBEEF와 0xDEAD는 [ef be ad de] = 0xDEADBEEF로 결합됩니다.

7.2 에뮬레이션 결과```

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

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

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

root@kitploit:~
### 7.3 ZMQ 전달

테스트 페이로드가 NB-IoT PHY 인코딩 및 전송 블록 전달을 통과하는지 확인하기 위해 ZMQ 루프백(RF 방출 없음)이 포함된 srsRAN 4G를 사용했습니다. 페이로드는 의도적으로 비준수한 벡터였습니다. `schedulingInfoList`의 ASN.1 SIZE 제약 조건을 완화하여 40개 항목을 허용했으며, pycrate 라운드트립 디코딩을 통해 바이트 14의 카운트 필드를 확인했습니다.```
SIB1 received
SIB2 activated
exit 0

이는 전송 계층 전달을 확인한다. 펌웨어 측 ASN.1 동작은 Layer A 정적 분석에 의해 확립된다.


8. 제어 흐름 메커니즘

8.1 두 단계, 하나의 태스크, 지속 상태

el1_ch 태스크는 스택이 하나다. Phase 1과 Phase 2는 동일한 태스크가 순차적으로 처리하는 두 개의 별도 IPC 이벤트이며, 그 사이에 스택이 완전히 해제된다. 카운트는 스택이 아닌 채널 컨텍스트 BSS에 유지된다:``` EVENT: CPHY_CFG_REQ (Phase 1) el1_ch_nbcch_start lbu v0, 0x99(s0) sb v0, 0x40A(s1) ← ch_ctx[0x40A] = attacker value, written to BSS returns — stack fully unwound

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

root@kitploit:~
`ch_ctx[0x40A]`는 BSS에 있으며, 모뎀이 재설정되거나 이후의 채널 구성이 이를 덮어쓸 때까지 공격자의 값을 유지한다.

### 8.2 스택 프레임```
old_sp  (= new_sp + 0xE8)
new_sp + 0xE4   saved ra
new_sp + 0xE0   saved s1
new_sp + 0xDC   saved s0
new_sp + 0x98   si_sched_arr  [34 halfwords = 68 bytes]
new_sp + 0x78   si_type_arr   [32 bytes]

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


9. 증거

9.1 취약 루프 이전의 게이트

9.2 si_count를 클램프하지 않는 것으로 확인된 함수


10. 패치 분석

10.1 버전

빌드모뎀 펌웨어빌드 날짜
취약A145RXXU1AWD1, MOLY LR12A...V1.P52023-04-18
패치A145RXXUDDZC2, MOLY LR12A...V3.P82025-04-23

두 이미지에서 md1_dbginfo 메타데이터를 추출하여 빌드 날짜를 확인했습니다. 패치 ID: MOLY00720348 · 이슈 ID: MSV-2392.

10.2 변경 사항

el1_ch_nbcch_start (취약 바이너리에서 0x90213444): lbu/sb 명령어 쌍이 존재하지 않습니다. IPC_msg[+0x99]를 ch_ctx[+0x40A]로 직접 복사하는 동작이 제거되었습니다.

el1_ch_nbcch_resume_req (취약 바이너리에서 0x90213940): ch_ctx[0x40A]에 대한 스택 쓰기 루프가 존재하지 않습니다. 신뢰할 수 없는 바이트가 고정 크기 스택 배열의 루프 상한이 되는 구조는 더 이상 존재하지 않습니다. 함수 본문은 다른 디스패치 구조로 대체되었습니다.

errc_chm_l1_set_bcch_si_reception: 무제한 카운터 루프가 검증 중심의 헬퍼 호출로 대체되었습니다.

10.3 새로운 검증 함수

패치된 바이너리에는 있지만 취약한 바이너리에는 없는 두 함수는 다음과 같습니다:``` el1_ch_nbcch_param_check el1_ch_scell_param_check

root@kitploit:~
단일 라인 경계 검사는 동일한 주소의 기존 함수 내부에 몇 개의 추가 명령어로 나타날 수 있습니다. 그러나 패치된 바이너리가 보여주는 것은 아키텍처 개정입니다: NBCCH 스케줄링 경로가 재설계되어 `si_count`를 루프 경계로 사용하는 패턴이 더 이상 해당 경로 어디에도 존재하지 않게 되었습니다.

### 10.4 CVE 귀속

여기에 설명된 취약점은 2025년 1월 6일 MediaTek이 공개한 CVE-2024-20154와 일치합니다. 확인 근거:

- 영향받는 펌웨어 제품군(LR12A)이 MediaTek의 게시판과 일치합니다.
- 취약점 유형 — 스택 오버플로, 경계 검사 누락, 악성 기지국으로부터의 RCE, 사용자 상호작용 불필요 — 이 CVE 설명 및 NVD 기록과 일치합니다.
- 패치된 펌웨어는 취약한 것으로 식별된 코드 구조를 정확히 제거합니다.
- 패치 ID MOLY00720348은 MediaTek 게시판 및 Android 보안 게시판(A-376809176)에서 확인되었습니다.
- AI 지원 분석은 수동 확인 전에 재구성된 패턴을 CVE-2024-20154에 독립적으로 매칭했습니다.

---

## 11. 윤리 및 책임 있는 공개

### 11.1 이 게시물에 포함되지 않은 것

무기화된 익스플로잇이 없습니다. 펌웨어 바이너리 콘텐츠가 없습니다. 변조된 페이로드 바이트가 없습니다. 실제 기기를 대상으로 취약점을 트리거하는 단계별 절차가 없습니다. 동작하는 공격을 재현하는 데 필요한 정보 — 특정 모뎀 디코더를 위한 완전한 페이로드 구성, 전체 Phase 1 에뮬레이션을 위한 RTOS 힙 객체 스캐폴딩, 무선(over-the-air) 라디오 구성 —는 의도적으로 누락되었습니다.

### 11.2 ZMQ 루프백과 에뮬레이션이 윤리적 접근 방식인 이유

ZMQ 루프백은 어떠한 신호도 무선으로 전송되지 않았음을 의미합니다. 실제 기기를 대상으로 하지 않았습니다. 통신사 네트워크도 관여하지 않았습니다. 이 증명은 분석가가 소유한 하드웨어의 완전히 격리된 소프트웨어 환경에서 실행됩니다. 이는 연결 전(pre-association) 라디오 취약점을 검증하는 올바른 접근 방식입니다 — 변조된 브로드캐스트를 전송하면 범위 내의 모든 기기에 영향을 미칠 것입니다.

Unicorn 에뮬레이션은 취약한 동작이 특정 기기 상태나 라디오 환경과 무관하게 펌웨어 바이너리 자체에 재현 가능하게 존재함을 입증합니다. 이는 단일 하드웨어 크래시보다 기술적으로 더 강력한 주장이며, 무선으로 무엇이든 배포하는 것을 피합니다.

### 11.3 MediaTek 지식재산권

모든 분석은 소비자 기기에서 합법적으로 획득한 펌웨어와 삼성이 공개 배포한 펌웨어 패키지를 대상으로 수행되었습니다. 독점 문서는 사용되지 않았습니다. MediaTek 내부 구조체 정의와 IPC 메시지 형식은 메모리 안전 실패를 설명하는 데 필요한 범위에서만 설명되었습니다. 이들은 사양으로 공개되지 않습니다.

---
도구 다운로드
반복sh가 쓰는 위치영향
0–33si_sched_arr[0..33]범위 내
34–35new_sp+0xDC — 저장된 s0s0 손상
36–37new_sp+0xE0 — 저장된 s1s1 손상
38new_sp+0xE4 — 저장된 ra [15:0]RA 하위 하프워드
39new_sp+0xE6 — 저장된 ra [31:16]RA 상위 하프워드
게이트조건확인 위치
NB-IoT 활성 경로cfg_type == 1el1_ch_nbcch_cphy_cfg_req_process
채널 불완전done_flag == 0ch_ctx[0x438]
상태 머신 0x0B재개 상태의 NBCCHel1_ch_nbcch_main 디스패치
si_count가 0이 아님ch_ctx[0x40A] > 0루프 조건
대역 클래스 ≤ 2유효한 NB-IoT 모드el1_ch_nbcch_resume_req 진입점
el1_chmgm_cell_info_get이 0이 아님서비스 테이블의 셀el1_ch_nbcch_start에서 호출됨
함수주소역할클램프?
errc_chm_l1_set_bcch_si_receptionERRC 범위CPHY_CFG_REQ[+0x99]에 기록없음
el1_ch_nbcch_cphy_cfg_req_process0x90213F80CPHY 구성을 L1으로 라우팅해당 없음 — si_count를 읽지 않음
el1_chmgm_cell_info_get0x9020E0D0EARFCN/PCI 검증해당 없음
el1_ch_nbcch_start0x90213444count를 BSS에 복사없음
el1_ch_nbcch_resume_req0x90213940count를 루프 상한으로 사용없음