Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

الخلاصاتاتصالالخصوصية© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
ReparcelBug2 — # مقالة واستغلال لتطبيق مثبت لتصعيد الامتيازات إلى مستوى النظام على أندرويد 12 بيتا عبر CVE-2021-0928، وهو عدم تطابق في تسلسل `writeToParcel`/`createFromParcel` في `OutputConfiguration` | Kitploit
أدوات/GitHubGitHub/michalbednarski/reparcelbug2
أمان أندرويدتصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالأمن الجوالتحليل الملفات الثنائية
GitHubmichalbednarski/reparcelbug2

ReparcelBug2

# مقالة واستغلال لتطبيق مثبت لتصعيد الامتيازات إلى مستوى النظام على أندرويد 12 بيتا عبر CVE-2021-0928، وهو عدم تطابق في تسلسل `writeToParcel`/`createFromParcel` في `OutputConfiguration`

عرض المستودع
1252468منذ 4 سنواتتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2021-0928، عدم تطابق في تسلسل writeToParcel/createFromParcel في android.hardware.camera2.params.OutputConfiguration

هذا استغلال يستخدم تلك الثغرة الأمنية لتصعيد الامتيازات من تطبيق Android مثبت إلى تطبيق إعدادات Android (أو أي تطبيق آخر مثبت يمكنه الإرسال إلى <receiver> المُعلن في AndroidManifest.xml، وكان تصعيد الامتيازات بالإرسال إلى <activity> ممكنًا أيضًا، وإن لم يُعرض هنا)

لقد وجدت المشكلة في الأصل على Android 12 Developer Preview 3

نسخة الاستغلال الموجودة في هذا المستودع تعمل على Android 12 Beta 2 و 3

تم إصلاح الثغرة الأمنية في أول إصدار رسمي من Android 12

الشرح أدناه كُتب في الأصل لشركة Google للنظر في هذا التقرير كسلسلة استغلال كاملة

في وقت كتابة هذا الشرح، لم يكن Android 12 متاحًا في AOSP (إصدارات Android Developer Preview/Beta ليست مفتوحة المصدر)

لقطة شاشة لإشعار Android من تطبيق الإعدادات: Hello from uid=1000(system) gid=1000(system) groups=1000(system),1007(log),1065(reserved_disk),1077(external_storage),3001(net_bt_admin),3002(net_bt),3003(inet),3007(net_bw_acct),9997(everybody) context=u:r:system_app:s0

مقدمة إلى Parcel

معظم الاتصالات بين العمليات (IPC) على Android تتم من خلال فئة تُسمى Parcel

الاستخدام الأساسي لـ Parcel هو كما يلي:```java Parcel p = Parcel.obtain(); p.writeInt(1); p.writeString("Hello");

ثم يتم إرسال `Parcel` إلى عملية أخرى [عبر `Binder`](https://developer.android.com/reference/android/os/IBinder#transact(int,%20android.os.Parcel,%20android.os.Parcel,%20int)). بدلاً من ذلك، ولأغراض الاختبار، يمكن استدعاء [`p.setDataPosition(0)`](https://developer.android.com/reference/android/os/Parcel#setDataPosition(int)) لإعادة توجيه الـ parcel إلى موضعه الأولي والبدء في القراءة:```java
int a = p.readInt(); // a = 1
String b = p.readString(); // b = "Hello"

يجب ملاحظة أن Parcel يحتفظ داخليًا بالموضع الذي تُنفَّذ منه عمليات القراءة. تقع على عاتق مستخدم فئة Parcel مسؤولية ضمان تطابق طرق read* مع طرق write* المستخدمة سابقًا، وإلا ستتم القراءات اللاحقة من مواضع خاطئة في المخزن المؤقت

كما يوفر Parcel إمكانية كتابة كائنات مخصصة، والطريقة المفضلة للقيام بذلك هي عبر تنفيذ واجهة Parcelable

فيما يلي مثال على تنفيذ واجهة Parcelable (تمت إزالة الكود غير ذي الصلة، ويُستخدم فئة WindowContainerTransaction في الاستغلال كجزء من سلسلة الأدوات، ومع ذلك لا يوجد بها أي خطأ)```java package android.window; public final class WindowContainerTransaction implements Parcelable { private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>(); private final ArrayList mHierarchyOps = new ArrayList<>();

private WindowContainerTransaction(Parcel in) {
    in.readMap(mChanges, null /* loader */);
    in.readList(mHierarchyOps, null /* loader */);
}

@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
    dest.writeMap(mChanges);
    dest.writeList(mHierarchyOps);
}

@NonNull
public static final Creator<WindowContainerTransaction> CREATOR =
        new Creator<WindowContainerTransaction>() {
            @Override
            public WindowContainerTransaction createFromParcel(Parcel in) {
                return new WindowContainerTransaction(in);
            }
        };

}

كما يتضح أعلاه، يتم استخدام طريقة `writeToParcel()` أثناء الكتابة. ثم أثناء القراءة يتم استدعاء طريقة المصنع `CREATOR.createFromParcel()`. تقع مسؤولية تنفيذ `Parcelable` في ضمان أن `createFromParcel` يقرأ نفس كمية البيانات التي كتبها `writeToParcel`، وإلا فإن جميع القراءات اللاحقة من ذلك `Parcel` ستقرأ البيانات من إزاحة خاطئة

يمكن كتابة/قراءة مثل هذه الفئة من/إلى `Parcel` من خلال:

* استدعاء `obj.writeToParcel(parcel, 0)` / `obj = WindowContainerTransaction.CREATOR.createFromParcel()` مباشرة، وهذا يُستخدم غالبًا عندما يكون نوع الفئة معروفًا، على سبيل المثال عندما يحتوي `Parcelable` على حقل بنوع `Parcelable` مختلف أو في الكود المُولّد بواسطة AIDL عندما تحتوي طريقة RPC المعرّفة على `Parcelable` كوسيط
* من خلال `Parcel.writeParcelable`/`readParcelable`. [`writeParcelable`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Parcel.java;l=1909;drc=58787794eb5c879f6e39ee58c0071b36e337f8e3) يكتب أولاً اسم الفئة ثم يستدعي طريقة `writeToParcel` من واجهة `Parcelable`. [`readParcelable`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Parcel.java;l=3282;drc=58787794eb5c879f6e39ee58c0071b36e337f8e3) يقرأ اسم الفئة المكتوب، ويجد الفئة بهذا الاسم في `ClassLoader` المقدم أو في `BOOTCLASSPATH` إذا تم توفير قيمة فارغة. بمجرد العثور على الفئة، يتم استخدام حقلها الثابت `CREATOR` للحصول على مثيل [`Parcelable.Creator`](https://developer.android.com/reference/android/os/Parcelable.Creator) وهو المصنع المستخدم لقراءة تلك الفئة. من المهم ملاحظة أنه عند استخدام طريقة `readParcelable` يمكنها قراءة أي `Parcelable` متاح في مسار الفئات حيث يتم قراءة اسم الكائن المراد إنشاؤه من نفس `Parcel`
* يتم استخدام `readParcelable` بواسطة العديد من طرق `Parcel` الأخرى، على سبيل المثال `readList` الذي شوهد في المثال أعلاه يقرأ العناصر من خلال `readValue`، وهي الطريقة الأكثر عمومية لنقل الكائنات في `Parcel` وإحدى الطرق التي تستخدمها هي من خلال `readParcelable`. أيضًا في المثال أعلاه، بسبب محو النوع في جافا (Type Erasure)، يمكن لحقل `ArrayList<HierarchyOp> mHierarchyOps` أن يحتوي فعليًا على أي كائنات يدعمها Parcel، وليس فقط تلك المتوافقة مع النوع المحدد في تعريف النوع العام

# عدم تطابق `writeToParcel`/`createFromParcel`

كما ذُكر أعلاه، تقع مسؤولية تنفيذ واجهة `Parcelable` في ضمان أن `createFromParcel` يقرأ نفس كمية البيانات من `Parcel` التي كتبها `writeToParcel` المطابق سابقًا. كلما وُجد في `BOOTCLASSPATH` عنصر `Parcelable` يمكنه انتهاك هذا العقد، فإنه يُنشئ ثغرة أمنية لأنه يسمح بالسيناريو التالي:

1. يرسل تطبيق خبيث إلى `system_server` حزمة `Bundle` أو عنصر `Parcelable` يحتوي على مثيل `Parcelable` معيب إلى جانب بيانات مُنشأة خصيصًا سيتم قراءتها فعليًا في الخطوة 3 ولكن يتم تمريرها حرفيًا خلال الخطوة 2
2. يتحقق `system_server` من أن `Bundle` آمن ثم يعيد توجيهه، أو يمرر `system_server` عنصر `Parcelable` المقدم إلى طريقة AIDL التي تحتوي أيضًا على بيانات حرجة مرسلة في المعامل التالي (إذا كان من الممكن تعديل البيانات المستلمة في ذلك المعامل فسيؤدي ذلك إلى مشكلة أمنية)
3. يستقبل تطبيق آخر البيانات من `system_server` ويثق بها، ومع ذلك بسبب التسلسل المعيب فإن البيانات التي يراها فعليًا تختلف عن البيانات التي قصد `system_server` إرسالها

استخدمت "أو" في الخطوات أعلاه لأن هذه الخطوات تصف كلاً من [نوع استغلال قديم يؤدي إلى تشغيل نشاط عشوائي والذي نشرته في 2017](https://github.com/michalbednarski/ReparcelBug) (على الجانب الأيسر من "أو") ونوع جديد سأصفه هنا في القسم التالي

# كيفية تنفيذ `BroadcastReceiver` في التطبيق

من وجهة نظر مطور التطبيق الذي يستخدم واجهات برمجة التطبيقات المتاحة في Android SDK، فإن طريقة عمل [`BroadcastReceiver`](https://developer.android.com/guide/components/broadcasts) هي أن أحد التطبيقات يستدعي [`sendBroadcast`](https://developer.android.com/reference/android/content/Context#sendBroadcast(android.content.Intent)) (على الرغم من أن التطبيقات غالبًا ما تريد استقبال البث من النظام، وليس من تطبيق آخر) ثم يتم مطابقة `Intent` المُبث مع `<receiver>` المعرّف في `AndroidManifest.xml`، وعند حدوث ذلك يبدأ النظام عملية التطبيق المستلم، ويُنشئ مثيلًا من فئة فرعية لـ `BroadcastReceiver` كما هو معرّف في سمة `<receiver android:name>` ثم يستدعي طريقة [`onReceive`](https://developer.android.com/reference/android/content/BroadcastReceiver#onReceive(android.content.Context,%20android.content.Intent))

دعنا نلقي نظرة على التواصل مع `system_server` الذي يحدث في عملية استقبال البث:
تنزيل الأداة