
شرح تقني لـ CVE-2024-20154
التصنيف: CWE-121 — تجاوز سعة المخزن المؤقت القائم على المكدس
الخطورة: حرجة (نشرة MediaTek) · 8.8 عالية، متجه الهجوم: مجاور (CISA-ADP)
النوع: تنفيذ تعليمات عن بُعد — لا حاجة لتفاعل المستخدم، ولا اتصال سابق
الإفصاح: نشرة أمان MediaTek، 6 يناير 2025 https://corp.mediatek.com/product-security-bulletin/January-2025
الهدف المُحلَّل: Samsung Galaxy A14 SM-A145R — عائلة MT6769 (Helio G80)، ضمن قائمة الرقاقات المتأثرة من MediaTek - تمت محاكاة البرنامج الثابت في ظل ظروف آمنة.
الحالة: تم التصحيح.
كان هذا أول بحث منشور لي في مجال القاعدة الأساسية. أنا قادم من خلفية بعيدة كل البعد عن البنى التحتية للاتصالات، وطبقات الوساطة في الاعتراض القانوني، وتحليل أجهزة stingray وكاشفات IMSI، وأمن الأجهزة المدمجة — لم أقم سابقًا بإجراء هندسة عكسية عميقة للبرامج الثابتة لمودم خلوي. أردت أن أثبت لنفسي أن منهجية تحليلية مهيكلة تتكيف عبر الأهداف المختلفة، وأن الإلمام بمنصة معينة يمكن استبداله بتتبع تسلسلي صارم. برز NB-IoT لأنه يقع عند تقاطع خطير حقًا: البروتوكول مصمم لأجهزة إنترنت الأشياء المقيدة، وسطح الهجوم يسبق الارتباط، وتعامل مكدس المودم معه بغض النظر عن ما يفعله مستخدم الجهاز.
عند تحليل البرنامج الثابت المُصحَّح وتأكيد غياب النمط القابل للاستغلال، قام نظام الذكاء الاصطناعي المُستخدم للتحليل الشامل للبرنامج الثابت قبل استهداف وظائف محددة بمطابقة فئة الخلل المُعاد بناؤه وظروفه وعائلة البرنامج الثابت المتأثرة بشكل مستقل مع وصف CVE-2024-20154.
الاستنتاجات الفنية هي استنتاجات المحلل نفسه.
يحتوي الهاتف الموجود في جيبك على حاسوبين منفصلين على الأقل. الحاسوب الذي تتفاعل معه يشغل Android. أما الآخر — القاعدة الأساسية — فهو يعمل بشكل مستقل تمامًا، ويتعامل مع جميع الاتصالات اللاسلكية، ويكاد يكون غير مرئي تمامًا لنظام التشغيل الذي يعلوه. قد يكون Android مُصحَّحًا بالكامل. قد يكون المتصفح مُعزولاً. قد لا ينقر المستخدم أبدًا على رابط ضار. لا شيء من هذا يهم إذا كان الكود القابل للاستغلال موجودًا في البرنامج الثابت للمودم الذي يعالج الإشارات اللاسلكية قبل أن يتدخل معالج التطبيقات.
إن CVE-2024-20154 هي بالضبط هذا النوع من الثغرات.
يتسبب بث معلومات نظام NB-IoT المشوه في قبول البرنامج الثابت لمودم MediaTek لعدد جدولة يتحكم فيه المهاجم، ثم تمرير هذا العدد عبر مسار تهيئة RRC-to-L1 دون تقييده أبدًا، واستخدامه في النهاية كحد للحلقة داخل معالج قناة البث الخاصة بـ NB-IoT. عندما يتجاوز العدد سعة المصفوفات الوجهة، تكتب الحلقة بما يتجاوزها، وتصل إلى السجلات المحفوظة على المكدس، وتستبدل عنوان العودة المحفوظ. ثم تستعيد الدالة القيمة المُفسدة في سجل عنوان العودة وتقفز إليه.
ما يجعل الخطورة بهذا المستوى:
تم نشر الثغرة في نشرة أمان MediaTek بتاريخ 6 يناير 2025 بتصنيف خطورة حرج، مما يؤثر على عائلة مودم LR12A من بين آخرين. قامت Samsung بتضمين الإصلاح في إصدار الصيانة الأمنية لشهر فبراير 2025.
هذا المنشور لا ينشر استغلالاً قابلاً للاستخدام ولا يمكن إعادة إنتاجه مما هو منشور هنا. الهدف هو إظهار أين ينكسر التسلسل، ولماذا فشلت كل طبقة في إيقافه، وما هو مطلوب للتحقق من خطأ في القاعدة الأساسية بمسؤولية عندما لا يمكنك توصيل مصحح أخطاء بالمودم المباشر.
الهدف الرئيسي: Samsung Galaxy A14 (SM-A145R). النظام الفرعي الراديوي مُدار بواسطة معالج قاعدة أساسية من MediaTech ضمن عائلة الرقاقات MT6769 (Helio G80). عائلة MT6769 مُدرجة صراحةً في قائمة الرقاقات المتأثرة من MediaTek لـ CVE-2024-20154.``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18
البرامج الثابتة للنطاق الأساسي ليست كود أندرويد. إنها نظام مضمن منفصل على النظام الفرعي الراديوي في SoC مع وحدة معالجة مركزية خاصة بها، ونظام تشغيل في الوقت الحقيقي خاص بها، ومساحة ذاكرة خاصة بها، خارج بيئة أندرويد المعزولة.
### 2.2 بنية المودم
يظهر تحليل الثنائي المستخرج أن معالج المودم يعمل بنظام MIPS32 مع تعليمات مضغوطة MIPS16e2 في وضع endian الصغير. MIPS16e2 هو امتداد ترميز 16 بت لتقليل حجم الكود المضمن — بما يتوافق مع نهج MediaTek للنطاقات الأساسية من جيل Helio، وقد أكدته الأبحاث المنشورة المستقلة حول النطاق الأساسي لهذه العائلة من SoC.
نظام التشغيل هو Nucleus RTOS، الذي يوفر جدولة المهام، وقوائم انتظار الرسائل IPC، وموزع ذاكرة قائم على التجمع. لا يوجد فصل امتيازات بين النواة والمستخدم، ولا تطبيق لوحدة حماية الذاكرة بين المهام، ولا آلية حماية مكدس الأجهزة.
جميع العناوين في هذا المنشور هي عناوين افتراضية، كما تم تحميلها في Ghidra عند القاعدة `0x90000000`.
### 2.3 الإجراءات التخفيفية (الملاحظة في البنية التي تم تحليلها)
| الإجراء التخفيفي | الحالة | التأثير |
|---|---|---|
| ASLR | غائب | عناوين البرامج الثابتة ثابتة ويمكن التنبؤ بها من الصورة |
| حارس المكدس | غائب | `SAVE`/`RESTORE` يخزن السجلات المحفوظة للمستدعي بدون قيمة حارس |
| NX / W^X | غائب | ذاكرة المكدس قابلة للتنفيذ |
| CFI | غائب | عناوين العودة غير موثقة مقابل أي سياسة |
### 2.4 نهج التحليل
ثلاثة مسارات متوازية:
**التحليل الثابت.** حزمة البرامج الثابتة لـ Samsung → استخراج قسم CP → `md1img.img` → Ghidra (MIPS LE 32-bit، القاعدة `0x90000000`) مع رموز هندسة MediaTek المستعادة من قسم تصحيح البرامج الثابتة باستخدام مجموعة أدوات NCC Group `mtk_bp`.
**التحقق الديناميكي.** تم استخدام Unicorn Engine (محاكاة MIPS32) لتنفيذ إجراءات محددة للبرامج الثابتة بشكل منفصل عبر مرحلتين. حاولت المرحلة 1 إثبات النسخ غير المقيد لـ `si_count` إلى سياق القناة من خلال زوج التعليمات الأصلي. نفذت المرحلة 2 الحلقة الضعيفة على بايتات البرامج الثابتة الحقيقية وأكدت أن تعليمات البرامج الثابتة الخاصة بها تفسد عنوان العودة المحفوظ. حيث لم تتمكن المرحلة 1 من العمل بشكل أصلي بالكامل — لأن بيئة كائن الخدمة لنظام RTOS المطلوبة بواسطة مسار إرسال CPHY لم يتم إعادة بنائها — تم نمذجة التأثير الجانبي مباشرة وتم تصنيفه على هذا النحو في جميع المخرجات.
**التحقق من الجانب الراديوي.** قام srsRAN 4G مع حلقة ZMQ — برمجيات فقط، بدون انبعاث ترددات راديوية — بتأكيد أن حمولة الاختبار تنجو من تشفير NB-IoT PHY وتسليم كتلة النقل.
---
## 3. سطح الهجوم: NB-IoT وSIB1-NB
### 3.1 سطح الهجوم قبل الارتباط
NB-IoT (إنترنت الأشياء ضيق النطاق) هو إصدار 3GPP 13، مصمم لتوصيل أجهزة إنترنت الأشياء المحدودة باستخدام طيف LTE المرخص الحالي. يتم تنفيذه في مجموعة واسعة من أنظمة SoC الخلوية الحديثة بما في ذلك تلك الموجودة في الهواتف الذكية الاستهلاكية.
أثناء وجوده في RRC_IDLE، قبل إنشاء أي اتصال RRC، فإن الجهاز الذي يبحث عن خدمة سيقوم بما يلي:
1. المزامنة مع إشارات توقيت الخلية (NPSS/NSSS)
2. فك تشفير كتلة المعلومات الرئيسية عبر NPBCH (نافذة إرسال 640 مللي ثانية)
3. فك تشفير SIB1-NB من NPDSCH (جدول 2560 مللي ثانية)
4. استخدام معلومات الجدولة في SIB1-NB لتحديد موقع كتل معلومات النظام الإضافية
في الخطوة 3، يقوم المودم بمعالجة رسالة من كيان لم يصادق عليه، قبل أي اتصال أو تفاعل للمستخدم. سيتم معالجة جهاز إرسال مارق يحقق شروط اختيار الخلية العادية.```
+------------------+ +---------------------+
| Rogue Base Stn | | Target UE (Modem) |
+--------+---------+ +----------+----------+
| |
| NPSS/NSSS sync |
|--------------------------------------->|
| MIB-NB (640 ms cycle) |
|--------------------------------------->|
| SIB1-NB (malformed, si_count > 8) |
|--------------------------------------->| ← vulnerability triggered
| [no RRC connection established] |
SIB1-NB مُعرّف في 3GPP TS 36.331. حقل schedulingInfoList الخاص به يحمل عدد
رسائل معلومات النظام التي تبثها الخلية، مقيدة بالمواصفات بحد أقصى 8
إدخالات (1..maxSI-Message-NB-r13 = 8). هذا قيد على مستوى البروتوكول. الـ
قيد أمان الذاكرة — وهو أن طول القائمة يجب ألا يتجاوز سعة
المصفوفات الوجهة — يجب أن يُفرض بشكل منفصل بواسطة البرنامج الثابت.
لم يكن.
تم الحصول على البرنامج الثابت من حزمة CP من سامسونج واستخراجه باستخدام مجموعة NCC
mtk_bp:
مجموعة الأدوات:```
md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image)
→ 017_md1_dbginfo (XZ-compressed CATI debug symbols)
تم فك ضغط قسم التصحيح CATI وتحليله باستخدام `mtk_dbg_extract.py symbols`، ثم استيراده إلى Ghidra عبر `ImportSymbolsScript.py`. وكانت النتيجة هي أسماء الدوال الداخلية الكاملة عبر مجموعة مودم الراديو — طبقة ERRC، إدارة قناة L1، النظام الفرعي IPC، وسلسلة معالج BCCH الخاص بـ NB-IoT — مما سمح بإعادة بناء السلسلة بناءً على الدلالات.
جميع أسماء الدوال في هذه المقالة مستمدة من رموز التصحيح المضمنة لشركة MediaTek المستخرجة من صورة البرنامج الثابت.
---
## 5. الثغرة
### 5.1 الحلقة الضعيفة
`el1_ch_nbcch_resume_req` (`0x90213940`) تعالج حدث استئناف قناة البث الخاصة بـ NB-IoT. مقدمتها الوظيفية بلغة MIPS16e2:```asm
90213940: save 0xE8, ra, s0-s1
تعليمة SAVE تقوم بتقليل sp بمقدار 0xE8 وتخزين السجلات المحفوظة للمستدعى إليه باتجاه الأسفل:```
old_sp (= new_sp + 0xE8)
new_sp + 0xE4 saved ra ← overflow target
new_sp + 0xE0 saved s1
new_sp + 0xDC saved s0
new_sp + 0x98 si_sched_arr [34 halfwords = 68 bytes]
new_sp + 0x78 si_type_arr [32 bytes]
new_sp + 0x00 ← stack pointer after SAVE
من تفكيك Ghidra للبرنامج الثنائي الفعلي للبرنامج الثابت:```c
for (uVar6 = 0; uVar6 < (byte)param_2[0x40a]; uVar6 = uVar6 + 1) {
si_type_arr[uVar6] = /* SI type byte */; // 1 byte/iter, base new_sp+0x78
si_sched_arr[uVar6] = /* SI schedule halfword */; // 2 bytes/iter, base new_sp+0x98
}
param_2[0x40a] هي ch_ctx[+0x40A] — بايت دائم في بنية BSS لسياق القناة.
يتم استخدام حد الحلقة مباشرة، دون مقارنة مسبقة مع سعات المصفوفة.
يبدأ البث A (كتابات نصف كلمة sh) عند new_sp+0x98 ويتقدم بمقدار 2 بايت لكل تكرار.
يصل إلى RA المحفوظ عند new_sp+0xE4 في التكرار 38:```
new_sp + 0x98 + i×2 = new_sp + 0xE4
i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38
يبدأ Stream B (يكتب البايت `sb`) عند `new_sp+0x78` وسيحتاج إلى التكرار 108 للوصول إلى فتحة RA:```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108
باستخدام si_count = 40 (القيمة التوضيحية، المختارة لتتجاوز عتبة الفائض 38)
تقوم الحلقة بتشغيل 40 تكرارًا. لا يصل الدفق B أبدًا إلى فتحة RA. يأتي تلف RA
بالكامل من الدفق A.
بعد 40 تكرارًا، تقوم تعليمات MIPS16e2 RESTORE بإعادة تحميل القيمة التالفة من
المكدس إلى $ra، وينقل jrc ra التحكم.
يتم كتابة ch_ctx[+0x40A] بواسطة el1_ch_nbcch_start عند 0x90213444. تعليمتي MIPS متتاليتين دون شيء بينهما:```asm
; el1_ch_nbcch_start @ 0x90213444
lbu v0, 0x99(s0) ; read IPC_msg[+0x99] = si_count from CPHY_CFG_REQ
sb v0, 0x40A(s1) ; write to ch_ctx[+0x40A] — no clamp, no mask, no compare
### 5.4 باني ERRC — الطبقة A
يتم بناء مخزن CPHY_CFG_REQ المؤقت في طبقة ERRC من SIB1-NB المفكوك. الدالة
`errc_chm_l1_set_bcch_si_reception` تكتب `IPC_msg[+0x99]`:```c
// errc_chm_l1_set_bcch_si_reception — Layer A
// Loop bound: decoded schedulingInfoList entry count from SIB1-NB
while (bVar3 < *(byte *)(param_3 + 0x44) && (param_2 != 0)) {
bVar3++;
if (uVar2 != param_2) {
*param_5 = *param_5 + 1; // CPHY_CFG_REQ[+0x99]++ — no upper bound check
}
}
الحد المرتبط بالحلقة هو عدد الإدخالات المفكوكة من SIB1-NB. يزداد العداد بمقدار واحد لكل إدخال تم فك تشفيره، وذلك لعدد الإدخالات التي تم فك تشفيرها، دون حد أقصى للحماية.
بمجرد ملء المخزن المؤقت CPHY_CFG_REQ، يقوم ERRC بإرساله إلى L1 باستخدام sap_id = 0x501F كمفتاح التوجيه:```
el1_ch_rcv_ilm (sap 0x501F)
→ el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C]
→ el1_chmgm_nbcch_handler
→ el1_ch_nbcch_main
→ el1_ch_nbcch_cphy_cfg_req_process ← validates cell identity, no si_count check
→ el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp
### 5.6 غياب التثبيت ثلاثي الطبقات
| الطبقة | الوظيفة | العنوان | هل يوجد تثبيت؟ |
|---|---|---|---|
| A — منشئ ERRC | `errc_chm_l1_set_bcch_si_reception` | نطاق ERRC | **لا يوجد** |
| B — نسخة L1 | `el1_ch_nbcch_start` | `0x90213444` | **لا يوجد** |
| C — حلقة L1 | `el1_ch_nbcch_resume_req` | `0x90213940` | **لا يوجد** |
أي فحص واحد في أي طبقة كان سيكسر السلسلة.
### 5.7 السبب الجذري
ثابت واحد تم انتهاكه:
> يجب ألا يتجاوز عدد إدخالات جدولة SI أبدًا سعة المصفوفة الوجهة.
يوفر 3GPP حد البروتوكول المقصود (8 إدخالات). كان على البرنامج الثابت (firmware) فرض حد أمان الذاكرة في كل طبقة حيث يصبح العداد فهرسًا أو حد حلقة. في البناء الضعيف، انتقل العداد من حقل البث SIB1-NB عبر مفكك ERRC، إلى رسالة CPHY_CFG_REQ، عبر حدود IPC إلى مهمة L1، إلى سياق القناة BSS، وإلى حلقة كتابة المكدس — دون أي طبقة تثبته.
---
## 6. سلسلة الاستدعاء — كيف تم اكتشافها
### 6.1 الارتباك ذو المسارين
يمكن لمسارين متشابهين هيكليًا ولكن متميزين توصيل مخزن تكوين بحجم 0x760 بايت إلى `el1_ch_nbcch_main`:
| المسار | المصدر | قيمة `[+0x99]` | الصلة |
|---|---|---|---|
| المسار أ (ERRC ← L1 IPC) | يبني ERRC CPHY_CFG_REQ من SIB1-NB المفكوك | `schedulingInfoList.count` من OTA | **المسار الضعيف** |
| المسار ب (داخلي L1) | `el1_ch_scs_ind_send` يبني جسم IPC داخلي | قيمة ثابتة `1` | غير ضعيف |
أكد المسار ب تنسيق الرسالة — البايت `+0x99` هو عدد SI الذي تستهلكه `el1_ch_nbcch_start`. نظرًا لأن عدده دائمًا ثابت بقيمة 1، فلا يمكنه التجاوز. المسار المتأثر خارجيًا هو المسار أ.
### 6.2 البحث عن الكاتب
أنتج البحث عن الأنماط في البرنامج الثابت عن أي تعليمة تكتب إلى الإزاحة `+0x99` ضوضاء:
T1 (مباشر `sb`، ~100 نتيجة)، T2 (قاعدة مقسمة، 5 نتائج)، T3 (إزاحة محسوبة، 0)، T4
(متداخلة `sh`/`sw`، ~465). كانت وظائف إدارة قناة ERRC غائبة عن قائمة المراجع المتقاطعة
`msg_send6` لأن ERRC يستخدم `errc_com_send_msg`. أكد مسبار المحاكاة أن الكتابة كانت من جانب
ERRC: تشغيل أداة Unicorn من موزع L1 ومراقبة عمليات الكتابة إلى إزاحة `+0x99` من المخزن لم يلتقط
شيئًا من جانب L1.```
[RUN] dispatcher=0x90214418 watching IPC_msg+0x99
NO writes to IPC_msg+0x99 caught from dispatcher.
Write happened before el1_ch_nbcch_main — confirmed ERRC-side.
بعد sap_id = 0x501F في errc_com_send_msg تم تحديد التوجيه إلى
el1_chmgm_errc_cfg_req_in_idle، والذي يخزن مؤشر CPHY_CFG_REQ في
L1_ctx[+0x323C] ويبدأ التوزيع النهائي.
SIB1-NB schedulingInfoList.count (demonstrator: 40) │ ▼ [ERRC task] errc_chm_ch_ctrl_req_hdlr → errc_chm_call_ctrl → errc_chm_l1_main → errc_chm_l1_call_ctrl → errc_chm_l1_snd_cphy_cfg_req ← allocates 0x760-byte CPHY_CFG_REQ → errc_chm_l1_set_cphy_req_nbcch_cfg → errc_chm_l1_set_bcch_inf → errc_chm_l1_set_bcch_si_reception ← Layer A: CPHY_CFG_REQ[+0x99] = 40 → errc_com_send_msg(sap=0x501F) ← IPC to L1 │ ▼ [L1 task] el1_ch_rcv_ilm (sap 0x501F) → el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C] → el1_chmgm_nbcch_handler → el1_ch_nbcch_main → el1_ch_nbcch_cphy_cfg_req_process ← no si_count validation → el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp │ ▼ ch_ctx[0x40A] = 40 (persists in BSS) │ ▼ [state machine advances to 0x0B, event 0x2C] el1_ch_nbcch_resume_req @ 0x90213940 ← Layer C: loop bound from ch_ctx[0x40A] │ ▼ stack overflow → jrc ra → PC = attacker-controlled
## 7. التحقق
لا يبدو أن هذا الطراز SM-A145R المحدد يقوم بتشغيل مسار كود NB-IoT الضعيف في عملية البناء العادية للسفينة، ولهذا السبب تم استخدام المحاكاة الهجينة والتحليل الثابت بدلاً من النسخ المباشر على الأجهزة.
**تم إثباته بشكل ثابت.** يحتوي ثنائي البرنامج الثابت على زوج التعليمات الضعيف. يتم إعادة بناء سلسلة الاستدعاء من الرموز والمراجع المتقاطعة وهيئات الدوال المفككة.
**تم تنفيذه بشكل أصلي في المحاكاة.** تم تشغيل الحلقة داخل `el1_ch_nbcch_resume_req` على بايتات البرنامج الثابت الحقيقية لـ MediaTek في محرك Unicorn (MIPS32). قامت تعليمة `sh` الخاصة بالبرنامج الثابت عند `0x90213B02` بكتابة الفتحة المحفوظة لعنوان الإرجاع. قامت تعليمة `RESTORE` بتحميل القيمة التالفة إلى `$ra`، وقامت `jrc ra` بنقل التحكم.
**تم تصميمه بشكل صريح.** لم يكن من الممكن تشغيل نسخة `lbu`/`sb` في `el1_ch_nbcch_start` بشكل أصلي بالكامل لأن مسار توزيع جدول استدعاء RTOS داخل `el1_ch_nbcch_cphy_cfg_req_process` توقع كائنات كومة Nucleus الحية التي لم يوفرها المحاكي المسطح. يقرأ معالج الاستئناف (`el1_ch_nbcch_resume_req`) في المرحلة 2 فقط من سياق القناة المقيم في BSS ولا يصادف نفس مسار التوزيع، ولهذا السبب تم تشغيل المرحلة 2 بشكل أصلي دون الحاجة إلى نفس الدعم. تم تصميم التأثير الجانبي للمرحلة 1 — بايت واحد من `IPC_msg[+0x99]` مكتوب إلى `ch_ctx[+0x40A]` — مباشرة وتم تسميته `[PHASE1-MODEL]`.
**غير مُدَّعَم.** نسخ كامل من الأجهزة عبر الهواء من طرف إلى طرف.
### 7.1 مكافحة العبث
فرضت أداة التثبيت قاعدة واحدة: لم يُسمح لأي خطاف بكتابة علامة الإثبات في الفتحة المحفوظة لعنوان الإرجاع. تم تتبع كل كتابة في الذاكرة غير تابعة للبرنامج الثابت.```
[PROOF-W] saved_RA write: pc=0x90213b02 addr=new_sp+0xE4 value=0xbeef
[PROOF-W] saved_RA write: pc=0x90213b02 addr=new_sp+0xE6 value=0xdead
[ANTI-TAMPER] no hook wrote RA=0xDEADBEEF — firmware only
anti_tamper_fail = False
0x90213B02 هو تعليمة sh داخل جسم الحلقة. وضعت البرامج الثابتة هذه البايتات في إزاحة المكدس المتوقعة. في التخزين ذي النهاية الصغرى، تتحد النصف كلمات 0xBEEF و0xDEAD عند new_sp+0xE4 وnew_sp+0xE6 لتكوّن [ef be ad de] = 0xDEADBEEF.
[REGS] RA = 0xdeadbeef ← firmware wrote this; decisive proof PC = 0x00000000 ← Unicorn unmapped-fetch artifact, not a hardware exception vector
[STACK] new_sp+0xE4: [ef be ad de] ← little-endian 0xDEADBEEF
[PC-EXPLAIN] PC=0 is an unmapped-fetch artifact; decisive proof is RA=0xDEADBEEF + stack bytes [ef be ad de] + [PROOF-JRC] CONFIRMED: saved RA = 0xDEADBEEF
### 7.3 تسليم ZMQ
لتأكيد أن حمولة الاختبار تنجو من تشفير الطبقة المادية (PHY) لـ NB-IoT وتسليم كتلة النقل، تم استخدام srsRAN
4G مع حلقة ارتداد ZMQ (بدون انبعاث ترددات لاسلكية). كانت الحمولة متجهًا غير مطابق عمدًا — تم تخفيف قيد SIZE الخاص بـ ASN.1 على `schedulingInfoList` للسماح بـ 40 إدخالاً، مع فك الترميز الدائري لـ pycrate لتأكيد حقل العدد عند البايت 14.```
SIB1 received
SIB2 activated
exit 0
هذا يؤكد التسليم على طبقة النقل. يتم تحديد سلوك ASN.1 من جانب البرامج الثابتة بواسطة التحليل الثابت للطبقة A.
مهمة el1_ch تحتوي على مكدس واحد. المرحلة 1 والمرحلة 2 هما حدثان منفصلان لـ IPC يتم معالجتهما بشكل تسلسلي بواسطة نفس المهمة، مع تفكيك المكدس بالكامل بينهما. يستمر العدد في BSS سياق القناة، وليس على المكدس:```
EVENT: CPHY_CFG_REQ (Phase 1)
el1_ch_nbcch_start
lbu v0, 0x99(s0)
sb v0, 0x40A(s1) ← ch_ctx[0x40A] = attacker value, written to BSS
returns — stack fully unwound
EVENT: resume (state 0x0B, msg 0x2C) (Phase 2) el1_ch_nbcch_resume_req ← frame 0xE8, reads ch_ctx[0x40A] as loop bound loop × 40 → saved RA corrupted jrc ra → attacker-controlled PC
`ch_ctx[0x40A]` يعيش في BSS ويحتفظ بقيمة المهاجم حتى يتم إعادة تعيين المودم أو تكوين قناة لاحق يستبدلها.
### 8.2 إطار المكدس```
old_sp (= new_sp + 0xE8)
new_sp + 0xE4 saved ra
new_sp + 0xE0 saved s1
new_sp + 0xDC saved s0
new_sp + 0x98 si_sched_arr [34 halfwords = 68 bytes]
new_sp + 0x78 si_type_arr [32 bytes]
تم تأكيد حجم الإطار من خلال قياس المحاكاة. تم تأكيد مواضع المصفوفة من خلال نتيجة المحاكاة — تم كتابة RA عند التكرار 38، بما يتوافق مع بدء si_sched_arr عند new_sp+0x98.
| البناء | برنامج المودم الثابت | تاريخ البناء |
|---|---|---|
| ضعيف | A145RXXU1AWD1، MOLY LR12A...V1.P5 | 2023-04-18 |
| مصحح | A145RXXUDDZC2، MOLY LR12A...V3.P8 |
تم تأكيد تواريخ البناء عن طريق استخراج بيانات md1_dbginfo الوصفية من كلتا الصورتين. معرّف التصحيح: MOLY00720348 · معرّف المشكلة: MSV-2392.
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: تم استبدال حلقة العداد غير المحدودة باستدعاءات مساعدة موجهة للتحقق من الصحة.
دالتان موجودتان في الثنائي المصحح وغائبتان عن الثنائي الضعيف:``` el1_ch_nbcch_param_check el1_ch_scell_param_check
سوف يظهر فحص الحدود ذو السطر الواحد كبضعة تعليمات مضافة داخل دالة موجودة عند نفس العنوان. ما تظهره النسخة الثنائية المصححة هو مراجعة معمارية: تم إعادة تصميم مسار جدولة NBCCH بحيث لم يعد نمط `si_count`-كحد للحلقة موجودًا في أي مكان في المسار.
### 10.4 إسناد CVE
تتطابق الثغرة الموصوفة هنا مع CVE-2024-20154 كما نشرتها MediaTek في 6 يناير 2025. أساس التأكيد:
- عائلة البرامج الثابتة المتأثرة (LR12A) تتطابق مع نشرة MediaTek.
- فئة الثغرة — تجاوز سعة المكدس، عدم وجود فحص الحدود، تنفيذ التعليمات البرمجية عن بعد من محطة قاعدة خبيثة، بدون تفاعل المستخدم — تتطابق مع وصف CVE وسجل NVD.
- البرنامج الثابت المصحح يزيل بالضبط بنيات التعليمات البرمجية التي تم تحديدها على أنها ضعيفة.
- تم تأكيد معرف التصحيح MOLY00720348 من نشرة MediaTek ونشرة أمان Android (A-376809176).
- قام التحليل بمساعدة الذكاء الاصطناعي بشكل مستقل بمطابقة النمط المعاد بناؤه مع CVE-2024-20154 قبل التأكيد اليدوي.
---
## 11. الأخلاقيات والإفصاح المسؤول
### 11.1 ما لا يحتويه هذا المنشور
لا استغلال أسلحة. لا محتوى ثنائي للبرامج الثابتة. لا بايتات حمولة مشوهة. لا إجراء خطوة بخطوة لاستغلال الثغرة ضد جهاز حقيقي. المعلومات اللازمة لإعادة إنتاج هجوم فعال — بناء الحمولة الكاملة لوحدة فك تشفير المودم المحددة، بناء السقالات لكائنات كومة RTOS لمحاكاة المرحلة الأولى الكاملة، تكوين الراديو عبر الهواء — غير موجودة عمدًا.
### 11.2 لماذا الحلقة العكسية ZMQ والمحاكاة هما النهج الأخلاقي
يعني الحلقة العكسية ZMQ عدم إرسال أي إشارة عبر الهواء على الإطلاق. لم يتم استهداف أي جهاز حقيقي. لم تشارك أي شبكة ناقل. يعمل الإثبات بالكامل في بيئة برمجية محصورة على أجهزة يملكها المحلل. هذا هو النهج الصحيح للتحقق من ثغرة راديو قبل الارتباط — إرسال بث مشوه سيؤثر على أي جهاز ضمن النطاق.
تُظهر محاكاة Unicorn أن السلوك الضعيف موجود في البرنامج الثابت الثنائي نفسه، بشكل قابل للتكرار، بغض النظر عن أي حالة جهاز محددة أو بيئة راديو. هذا هو ادعاء أقوى تقنيًا من تعطل جهاز واحد، ويتجنب نشر أي شيء عبر الهواء.
### 11.3 الملكية الفكرية لـ MediaTek
تم إجراء جميع التحليلات على برامج ثابتة تم الحصول عليها بشكل قانوني من جهاز استهلاكي ومن حزم البرامج الثابتة التي أصدرتها Samsung علنًا. لم يتم استخدام أي وثائق مملوكة. يتم وصف تعريفات الهياكل الداخلية لـ MediaTek وتنسيقات رسائل IPC فقط بالقدر اللازم لشرح فشل سلامة الذاكرة. لم يتم نشرها كمواصفات.
---
| التكرار | ماذا يكتب sh | التأثير |
|---|
| 0–33 | si_sched_arr[0..33] | ضمن الحدود |
| 34–35 | new_sp+0xDC — s0 المحفوظة | s0 متلف |
| 36–37 | new_sp+0xE0 — s1 المحفوظة | s1 متلف |
| 38 | new_sp+0xE4 — ra المحفوظة [15:0] | نصف الكلمة السفلي لـ RA |
| 39 | new_sp+0xE6 — ra المحفوظة [31:16] | نصف الكلمة العلوي لـ RA |
| الحاجز | الشرط | مكان التحقق |
|---|
| مسار NB-IoT النشط | cfg_type == 1 | el1_ch_nbcch_cphy_cfg_req_process |
| القناة غير مكتملة | done_flag == 0 | ch_ctx[0x438] |
آلة الحالة 0x0B | NBCCH في حالة الاستئناف | إرسال el1_ch_nbcch_main |
| si_count غير صفري | ch_ctx[0x40A] > 0 | شرط الحلقة |
| فئة النطاق ≤ 2 | وضع NB-IoT صالح | مدخل el1_ch_nbcch_resume_req |
el1_chmgm_cell_info_get غير صفري | الخلية في جدول الخدمة | تم الاستدعاء في el1_ch_nbcch_start |
| الدالة | العنوان | الدور | تقيد؟ |
|---|
errc_chm_l1_set_bcch_si_reception | نطاق ERRC | يكتب CPHY_CFG_REQ[+0x99] | لا |
el1_ch_nbcch_cphy_cfg_req_process | 0x90213F80 | يوجه تكوين CPHY إلى L1 | N/A — لا يقرأ si_count |
el1_chmgm_cell_info_get | 0x9020E0D0 | يتحقق من صحة EARFCN/PCI | N/A |
el1_ch_nbcch_start | 0x90213444 | ينسخ العدد إلى BSS | لا |
el1_ch_nbcch_resume_req | 0x90213940 | يستخدم العدد كحد للحلقة | لا |
| 2025-04-23 |