Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
ExecASLR-ekoparty — استغلال لإثبات المفهوم يتحايل على آلية ASLR في معالجات Intel عبر إساءة استخدام مخزن أهداف الفروع (Branch Target Buffer) والتنفيذ التخميني لتسريب العناوين العشوائية عبر قناة جانبية. | Kitploit
أدوات/GitHubGitHub/es0j/execaslr-ekoparty
تحليل الثغرات الأمنيةالاستغلالأمن الأجهزةالتعلم والتعليمالفريق الأحمرالهجوم العدائياستغلال الملفات الثنائية
GitHubes0j/execaslr-ekoparty

ExecASLR-ekoparty

استغلال لإثبات المفهوم يتحايل على آلية ASLR في معالجات Intel عبر إساءة استخدام مخزن أهداف الفروع (Branch Target Buffer) والتنفيذ التخميني لتسريب العناوين العشوائية عبر قناة جانبية.

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

الأكثر شعبية

عرض الكل →

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

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

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

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

ExecASLR - إساءة استخدام متنبئات الفروع في معالجات إنتل لتجاوز ASLR

ما هو ASLR

توزيع عشوائي لمساحة العنوان (ASLR) هو إجراء تخفيفي يُستخدم لزيادة صعوبة استغلال هجمات تلف الذاكرة. في سيناريو وجود ثغرة تجاوز سعة المخزن المؤقت، على سبيل المثال، يحتاج المهاجم الذي يحاول بناء استغلال باستخدام البرمجة الموجهة بالإرجاع (Return Oriented Programming) إلى معرفة عناوين القطع (gadgets) في السلسلة. إذا كان جزء الكود من البرنامج المستهدف يتم توزيعه عشوائيًا، يصبح من الأصعب بكثير على المهاجم اختيار العنوان الصحيح للاستغلال، مما يجعل الاستغلال غير ممكن.

يوضح المثال التالي كيف يتم توزيع عنوان عشوائيًا:

root@kitploit:~
#include <stdio.h>
void DoNothing();
void (*codePtr)() = DoNothing;

void DoNothing(){}

int main(int argc,char **argv){

    printf("Destination %p\n",codePtr);
    DoNothing();
}


في كل تنفيذ يتم توزيع القيمة عشوائيًا:

root@kitploit:~
Destination 0x563714256149
Destination 0x556d8e2f1149
Destination 0x5618c8bdd149
Destination 0x55ee623b0149

البتات الاثنتا عشرة الأخيرة 149 تكون نفسها دائمًا، لكن موقع الدالة يمكن أن يكون تقريبًا في أي مكان بين 0x550000000000 و0x570000000000، مما يعني أن 29 بتًا يتم توزيعها عشوائيًا، لتشغل مساحة عنوان محتملة تبلغ 0x200 0000 0000 أو 2.2 تيرابايت تقريبًا.

خط أنابيب المعالج (CPU pipeline)

إن معالجة كل تعليمة هي مهمة صعبة. بعض مراحل معالجة تعليمة واحدة هي:

  • جلب التعليمة؛
  • فك ترميز التعليمة؛
  • تنفيذ العمليات في وحدة الحساب والمنطق

من أجل زيادة إنتاجية التعليمات في المعالج، يتم تنفيذ كل مهمة من مهام التعليمة بواسطة وحدة محددة من معالج. مع عمل جميع الوحدات بالتوازي، يسمح ذلك للمعالج بالعمل بسرعات ساعة أعلى بكثير، وهذه هي فكرة خط الأنابيب.

العملية \ دورة الساعة12345
الجلبABC
فك الترميزABC
التنفيذABC

تنفيذ التعليمات A وB وC عبر الدورات 1-5. في الدورة 3، على سبيل المثال، تكون وحدات القراءة وفك الترميز والتنفيذ نشطة في الوقت نفسه

ومع ذلك، فإن التعليمات ليست مستقلة تمامًا عن بعضها البعض. على سبيل المثال، التسلسل التالي:

root@kitploit:~
A. add ax,[bx]
B. jz $+1
C. mov dl,[rsi]  
D. nop

في هذه الحالة، ستنتهي التعليمة A في أفضل الأحوال فقط في الدورة 3 عند مرحلة التنفيذ. ومع ذلك، تحتاج وحدة الجلب إلى تحديد ما هي التعليمة التالية التي يجب جلبها من الذاكرة، وما إذا كان يجب تخطي التعليمة C (mov dl,[rsi]). في هذا السيناريو، أمام المعالج خيار الانتظار حتى تنتهي التعليمة A، وهو ما لن يحدث إلا في الدورة الثالثة، ليقوم بعدها بجلب التعليمة الصحيحة من الذاكرة، إذا كانت عملية الجمع تُرجع 0، على سبيل المثال:

العملية \ دورة الساعة123456
الجلبABD
فك الترميزABD
التنفيذABD

وهذا يعني حدوث تأخير في خط الأنابيب لأن المعالج يجب أن ينتظر تنفيذ التعليمة. في هذا المثال، التأخير هو دورة ساعة واحدة فقط، لكن التعليمة add ax,[bx] تتطلب عملية ذاكرة، والتي كما رأينا سابقًا يمكن أن تستغرق مئات الدورات حتى تكتمل، مما يفرض تكلفة أداء كبيرة على المعالج.

سيكون الخيار الأسرع هو محاولة «تخمين» مسار التنفيذ الصحيح. يمكن للمعالج أن يخمن (speculate) ما إذا كان الفرع سيُتخذ أم لا. بعد تلك النقطة، يستمر التنفيذ من المسار المُخمَّن، ولا يتم اعتماد القيم إلا إذا ثبت صحة المسار بعد انتهاء التعليمة A. إذا ثبت أن المسار خاطئ، يتم تجاهل النتائج وإعادة الحالة إلى ما قبل نقطة التخمين.

العملية \ دورة الساعة123456
الجلبAB(S) C
فك الترميزAB(S) C
التنفيذAB(S) C

المشكلة الوحيدة في التراجع عن المسار المُتخذ هي أن الحالة المعمارية الدقيقة للمعالج لا يمكن التراجع عنها. لذا إذا خمّن المعالج تنفيذ التعليمة C (mov dl,[rsi])، فسيتم نقل البيانات المشار إليها بواسطة rsi إلى الكاش. ويمكن قياس هذا التأثير لاحقًا باستخدام هجوم قناة جانبية.

متنبئ شرطي ثنائي البت. https://en.wikipedia.org/wiki/Branch_predictor

Spectre V2 (حقن هدف الفرع)

لا يجب التنبؤ بالتعليمات الشرطية فقط، بل أيضًا بالفروع غير المباشرة. يجب أن يمتلك المعالج آلية لتخمين وجهات تعليمة مثل call [rdi].

تظهر ثغرة Spectre v2 أنه من الممكن استغلال المتنبئ غير المباشر لتحقيق تنفيذ عابر (transient execution) في عمليات أخرى: مأخوذ من https://spectreattack.com/spectre.pdf

عند وضع تعليمة استدعاء في السياق A على نفس العنوان الافتراضي لتعليمة استدعاء أخرى في السياق B، يمكن للمهاجم تدريب المعالج على تنفيذ كود عند موضع يختاره المهاجم في السياق B، في هجوم إعادة استخدام الكود، على غرار البرمجة الموجهة بالإرجاع (ROP).

يجب أن يمتلك الضحية المستهدفة قطعة كود تُعرف باسم «spectre gadget» قادرة على تسريب سر باستخدام هجوم قناة جانبية. لنجاح هجوم Spectre، يجب على المهاجم أيضًا معرفة موقع الـ spectre gadget. لذلك، في هجمات المستخدم ضد المستخدم، كان حماية الضحية باستخدام ASLR تُستخدم كإجراء تخفيفي لهذا النوع من الهجمات. ومع ذلك، توجد أيضًا تقنيات لاستخراج ASLR باستخدام هجمات معمارية دقيقة مثل القفز فوق ASLR (Jump Over ASLR). لكن لهذه التقنية بعض القيود فيما يتعلق بكمية البتات المسربة، لأنها تعتمد على التصادم في المتنبئ المباشر لتجاوز ASLR.

الآليات الداخلية لهذا المتنبئ موضحة أدناه:

مأخوذ من https://spectreattack.com/spectre.pdf

بعض هذه المكونات هي:

  • مخزن أهداف الفروع (Branch Target Buffer - BTB)؛
    • BTB هو مكوّن يشبه الكاش يخزن الوجهات الخاصة بالتنبؤات. يخزن BTB عنوان الوجهة الكامل 64 بت، ويعتمد عدد الإدخالات المتاحة في BTB على البنية المعمارية.
  • مخزن تاريخ الفروع (Branch History Buffer - BHB)؛
    • يخزن BHB «تجزئة» لتدفق التنفيذ الأخير. كل تعليمة فرع تكتب إلى BHB. في معالجات Skylake وما قبلها، يمكن أن يخزن BHB سياق آخر 29 فرعًا. في Icelake يخزن BHB حتى ~100 فرع. لاحظ أن BHB يستخدم فقط 20 بتًا منخفضة من الفروع لإنشاء التجزئة، 12 منها غير موزعة عشوائيًا.
  • المتنبئ غير المباشر (Indirect predictor)؛
    • يستخدم فقط 12 بتًا منخفضة من تعليمة الفرع غير المباشر لتحديد الوجهة الكاملة 64 بت. يقوم Exec ASLR بتسريب مؤشر الـ 64 بت من BTB لاستعادة عناوين ASLR بالكامل.
  • المتنبئ المباشر للفروع (Direct branch predictor)
    • يستخدم 30 بتًا منخفضة من عنوان المصدر للتنبؤ بقيمة 32 بت. يتم إعادة استخدام النصف الآخر من العنوان من المصدر. هجوم Jump Over ASLR يستغل التصادمات في هذا المتنبئ للعثور على عنوان مصدر يتصادم مع سياق آخر، وبالتالي فهو محدود بتسريب 30 بتًا منخفضة فقط من سياق الضحية.

التخطيط الكلاسيكي لهجوم Spectre v2 يبدو هكذا:

  • يضع المهاجم فرعًا غير مباشر في نفس موضع فرع الضحية، لكن الوجهة تطابق قطعة spectre gadget في سياق الضحية
  • عندما ينفذ الضحية الفرع، يحدث تنبؤ خاطئ وتقوم الـ spectre gadget بتحميل سر وإجراء وصول شرطي إلى منطقة ذاكرة مشتركة مثل مكتبة. على سبيل المثال، يمكن لقطعة spectre gadget التي تنفذ getenv + secret[0]*4096 تسريب قيمة السر في الموضع 0 باستخدام libc كذاكرة مشتركة.
  • يسترد المهاجم بعد ذلك السر المسرب عبر اكتشاف أي أجزاء من الذاكرة المشتركة تم نقلها إلى الكاش باستخدام هجوم flush+reload

Exec ASLR

Exec ASLR (المعروف أيضًا باسم تسميم مخزن أهداف الفروع العكسي - Reverse Branch Target Buffer Poisoning) هو تقنية جديدة لتجاوز ASLR باستخدام ثغرة Spectre-BTI. تسيء هذه التقنية استخدام حقيقة أنه ليس فقط يمكن للمهاجم تلويث BTB في سيناريو Spectre-BTI الكلاسيكي، بل يمكن للضحايا أيضًا أن يتسببوا في تنبؤ خاطئ للفرع في عملية المهاجم، مما يقود المهاجم إلى قفزة تخمينية إلى عنوان محمي بواسطة ASLR. ثم باستخدام قناة جانبية تسرب العنوان الذي يتم تنفيذه، يمكن للمهاجم استرداد عنوان الوجهة الكامل، متجاوزًا ASLR للعملية المستهدفة.

يبدو تخطيط هجوم Exec ASLR هكذا:

  • ينفذ الضحية فرعًا غير مباشر، يكتب مؤشر الوجهة العشوائي الخاص به (0x55aabbeef456) إلى BTB
  • يضع المهاجم فرعًا غير مباشر في عنوان محاذٍ لـ 12 بتًا منخفضة. نظرًا لأن الـ 12 بتًا منخفضة ليست موزعة عشوائيًا، فهذا الجزء بسيط.
  • يملأ المهاجم جميع المواضع الممكنة من الذاكرة بـ «قطعة تسريب» تخبر المهاجم «أنا أنفذ عند هذا العنوان!» باستخدام probeArray كقناة جانبية.
  • عندما ينفذ المهاجم الفرع غير المباشر، يحدث تنبؤ خاطئ إلى إحدى قطع التسريب العديدة في الذاكرة
  • يستخدم المهاجم هجوم flush+reload لاسترداد ما إذا تم الوصول إلى ProbeArray أم لا أثناء التخمين.

في هذا النوع من الهجمات، لا حاجة للعثور على spectre gadget ولا لامتلاك ذاكرة مشتركة للقناة الجانبية، الشرط الوحيد هو وجود فرع غير مباشر ليتم استغلاله، حيث يتم وضع جميع قطع Spectre v2 المطلوبة داخل عملية المهاجم. الشرط الجديد الوحيد لهذا الهجوم هو القدرة على تعيين عنوان وجهة الضحية في عمليتك الخاصة، لذلك لا يمكن لهذا الهجوم العمل ضد KASLR على سبيل المثال. هذا أيضًا ليس هجوم تخمين عنيف، فبمحاولة واحدة يمكن اختبار عناوين متعددة في نفس الوقت، ومع ذلك هناك حد لعدد «قطع التسريب» التي يمكن أن تحتويها الذاكرة في نفس الوقت. هذا يقلل بشكل كبير من الوقت اللازم لتنفيذ الهجوم مقارنة بـ Jump Over ASLR من ~100 عنوان في الثانية إلى بضع مئات مليارات العناوين في الثانية.

قطعة التسريب (Leak gadget)

تستخدم قطعة التسريب probeArray لإعلام المهاجم بالمكان الذي يتم فيه تنفيذ القطعة نفسها. تستقبل probeArray ومؤشر RIP كوسيطين وتقوم بنوع من البرمجة بدون فروع لتقرر ما إذا كان سيتم الوصول إلى probeArray[0] أو probeArray[4096].

root@kitploit:~
lea rax,[rip - 7]      ;load current address
shr rax,cl             ;selects the bit using cl arg
and rax,1
shl rax,12             ;loads probearray
mov dl,[rsi+rax]       ;or probearray+4096

التحكم في BHB وكود الضحية المستهدف

كما رأينا سابقًا، يتم استخدام BHB لتحديد إدخال في BTB. من أجل إيجاد تصادم في BTB واستغلال هذه الثغرة، يجب على المهاجم معرفة آخر N من الفروع (29 إذا كانت المعالجات < skylake) التي تم اتخاذها. في اختباراتنا، استخدمنا حلقة for لضبط حالة BHB إلى قيمة معروفة قبل الاستدعاء غير المباشر. إليك مثال ضعيف على كود الضحية:

root@kitploit:~
#include <stdio.h>

void DoNothing();
void (*codePtr)() = DoNothing;

void DoNothing(){
    return;
}

int main(){
    printf("Destination = %p\n",codePtr);
    while(1){
	for(int i=0;i<200;i++){}
    	codePtr();
    }
}

من أجل ضمان أن حالة BHB هي نفسها في كلا السياقين، ينسخ المهاجم البايتات المقابلة لحلقة for الخاصة بالضحية والاستدعاء في شكل شيل كود. يتم نسخ الشيل كود إلى جميع المواضع الـ 256 الممكنة التي يمكن أن تطابق محاذاة الـ 20 بتًا المنخفضة المطلوبة لتكون حالة BHB متماثلة.

root@kitploit:~
Victim Code

0x5594c566a152 <+28>:    mov    eax,0xc8
0x5594c566a157 <+33>:    dec    eax
0x5594c566a159 <+35>:    jne    0x1157 <main+33>
0x5594c566a15b <+37>:    nop
0x5594c566a15c <+38>:    nop
0x5594c566a15d <+39>:    nop
0x5594c566a15e <+40>:    lea    rdi,[rip+0x2ecb]
0x5594c566a165 <+47>:    call   QWORD PTR [rdi]

--> Executes to
0x5594c5669135:    ret

root@kitploit:~
Attacker Code

… //eax=200 rsi=probeArray, cl=0 
0x6a157    dec    eax
0x6a159    jne    0x455555500157
…
0x6a165    jmp    QWORD PTR [rdi]

--> Misspredicts to
0x5594c566a135:    lea rax,[rip - 7]
0x5594c566a13c:    shr rax,cl
0x5594c566a13f:    and rax,1
0x5594c566a133:    shl rax,12
0x5594c566a137:    mov dl,[rsi+rax]

التحديات

هناك مشكلة عند محاولة وضع قطعة في جميع المواضع الممكنة في نفس الوقت. في اختباراتنا، يضع ASLR الوجهة في مكان ما بين 0x550000000000 و0x570000000000. وهذا يعني وجود 2.2 تيرابايت من العناوين الافتراضية الممكنة لتعيينها أو 537 مليون قطعة تسريب. لكن النظام يحتوي فقط على 8 جيجابايت من ذاكرة الوصول العشوائي. إلى جانب إمكانية تعيين 2 تيرابايت من الذاكرة باستخدام COW، لم نحقق نجاحًا كبيرًا مع هذا النهج. أفترض أنه يخلق ضغطًا كبيرًا على مخزن الترجمة (Translation Lookaside Buffer - TLB)، مما يجعل التخمين إلى عنوان غير مترجم بطيئًا جدًا. في الاختبارات، أنشأنا صفحة بحجم 1 جيجابايت في الذاكرة وملأناها بقطع التسريب. ثم قمنا بتحويل الصفحة عبر نطاق الـ 2 تيرابايت باستخدام استدعاء remap. المشكلة الأخرى التي لوحظت هي أن العنوان المُخمَّن ربما لم يكن موجودًا في TLB، لأنه لم يتم تنفيذه فعليًا من قبل. لكن دليل إنتل ينص على:

  • «قد يقوم المعالج بتخزين الترجمات المطلوبة للجلب المسبق وللوصولات التي تنتج عن التنفيذ التخميني والتي قد لا تحدث فعليًا في مسار الكود المنفذ» - ISA

لذلك، من أجل زيادة فرص «التنقل الصفحي الناتج عن التخمين» حاولنا جعل من الصعب قدر الإمكان حل العنوان الصحيح. يتم ذلك باستخدام سلسلة مؤشرات لعنوان الوجهة. الفكرة هي أن الواجهة الأمامية للمعالج ستخمن وجهة الفرع وستقوم وحدة إعادة الترتيب بتنفيذ قطعة التسريب قبل إنهاء قراءة سلسلة المؤشرات.

root@kitploit:~
Improved Caller - Frontend fetched instructions
mov rcx,%1       ;mask arg for gadget
lea rsi,[%2]     ;probe array ptr arg
lea rdx,[%0]
mov rdx,[rdx]    ;pointer chain
mov rdx,[rdx]
mov rdx,[rdx]
...
mov rdx,[rdx]
mov rdx,[rdx]
check [rdx]      ;mispredicts to gadget

lea rax,[rip - 7];speculative execution
shr rax,cl
and rax,1
shl rax,12
mov dl,[rsi+rax]

root@kitploit:~
Improved Caller - Reorder unit scheduled instructions
mov rcx,%1    ;mask arg for gadget
lea rsi,[%2]  ;probe array ptr arg
lea rdx,[%0]
mov rdx,[rdx] ;pointer chain
mov rdx,[rdx]
; <pagewalk occurs some where here>
... ;Out of order + speculation
lea rax,[rip - 7]
shr rax,cl
and rax,1
shl rax,12
mov dl,[rsi+rax]
...
mov rdx,[rdx]
mov rdx,[rdx]
check [rdx] ;the execution path reverted

أظهرت تقنية التنفيذ خارج الترتيب + التنفيذ التخميني تحسنًا في معدلات التنبؤ الخاطئ المطلوبة في الهجوم.

الجدولة وSTIBP

من أجل تنفيذ هجوم Spectre V2، يجب على المهاجم تنفيذ كود على نفس النواة التي يعمل عليها الضحية، بحيث يتشاركان نفس وحدة التنبؤ بالفروع (Branch Prediction Unit - BPU). في معالجات <= skylake لاحظنا أنه من الممكن تحقيق التواجد على نفس النواة باستخدام خيوط المعالجة المتزامنة (hyperthread). معالجات Icelake وCascade lake تنفذ إجراء تخفيفي يسمى «متنبئ الفروع غير المباشرة أحادي الخيط» (Single Thread Indirect Branch Predictor - STIBP)، الذي يفصل BPU عبر الخيوط. لذلك من الضروري تنفيذ الضحية والمهاجم على نفس الخيط واستخدام usleep للتناوب بين عملية الضحية وعملية المهاجم، مما قد يجعل المهاجم أبطأ على هذه المعالجات لولا حقيقة أن الكاشات (وربما TLB أيضًا) ممتازة جدًا في هذه الأجيال، مما يسمح بتخزين عدد أكبر بكثير من القطع في الكاش في نفس الوقت.

النتائج

تم اختبار هذه التقنية على جميع معالجات إنتل المتاحة على Google Cloud، في كل من جيلي N1 وN2:

  • Sandy Bridge
  • Ivy Bridge
  • Haswell
  • Broadwell
  • Skylake
  • Cascadelake
  • Icelake

بصرف النظر عن وجود بعض الاختلافات في الاستغلالات الخاصة بـ Cascade وIce lake، فإن جميع الاختبارات قادرة على استعادة العناوين بدقة >99% في أقل من 10 ثوانٍ.

الإجراءات التخفيفية

الإجراءات التخفيفية هي نفسها الخاصة بـ Spectre V2 للتخفيف من هجمات المستخدم ضد المستخدم. حاجز التنبؤ بالفروع غير المباشرة (Indirect Branch Prediction Barrier - IBPB) يسمح بمسح BPU ويمكن استخدامه عند تبديل السياقات. في لينكس يمكن استخدام IBPB عبر استدعاء النظام prctl مع الخيار PR_SET_SPECULATION_CTRL. ليس لدي أي فكرة عن الإجراء التخفيفي المكافئ لنظام ويندوز، من فضلك أخبرني.


الورقة البحثية:

https://cos.ufrj.br/uploadfile/publicacao/3061.pdf

محاضرة Ekoparty:

https://www.youtube.com/watch?v=Qj4z-KvnkxU

الشرائح:

https://docs.google.com/presentation/d/10t-oo-c26x9ydx1_FYgmhy204rxfmQ92eboPlCnA2y4/edit?usp=sharing

المراجع:

https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html https://eprint.iacr.org/2013/448.pdf https://spectreattack.com/spectre.pdf https://www.cs.ucr.edu/~nael/pubs/micro16.pdf http://download.vusec.net/papers/bhi-spectre-bhb_sec22.pdf https://www.kernel.org/doc/html/latest/userspace-api/spec_ctrl.html Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3. Santa Clara, USA: Intel Corporation, 2016, iSBN 325384-060US

تنزيل الأداة