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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
zipdefrag — تم تقديمه في Recon Montreal 2018 | Kitploit
أدوات/GitHubGitHub/nccgroup/zipdefrag
أمان الأنظمة المدمجةتحليل الذاكرة الجنائيالهندسة العكسيةاستعادة البياناتالتحاليل الرقمية الجنائيةتحليل البرامج الثابتة
GitHubnccgroup/zipdefrag

zipdefrag

تم تقديمه في Recon Montreal 2018

عرض المستودع
74منذ 8 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

هذا التفريغ لغز

أو تحليلٌ متقدّم بأسلوب Shotgun للحمقى والمتمرّدين

كان يا ما كان

في يوم من الأيام، أيها القارئ العزيز، في ليلة مظلمة وعاصفة، صادف مؤلّفكم المخلص موقفًا محيّرًا وغامضًا — نظامًا كان فيه الشيء الوحيد الذي يمنع تحليل ذاكرة chip-off والهندسة العكسية هو نظام ملفات خاص مجزّأ وغير معروف، إلى جانب الضغط الناتج عن استخدام جافا المضمّنة، مما يقلّل فعالية الأدوات الموجودة في استخراج الملفات (file carving).

ربما كان قد رُكّب حل مخصص (ad hoc) في ذلك الوقت عن طريق وصل الوحدات التي بدت متلائمة يدويًا، مع القليل من العمل البشع على سطر أوامر بايثون ونصوص bash مخصصة بشعة. كان الأمر «جيدًا بما يكفي»، لكنه مستهلك للوقت.

في حين أن استخراج البيانات العادية غير المضغوطة في تحليل chip-off هو عمل روتيني إلى حدّ ما في يوم مخترق الأجهزة (hardware hacker)، فإن الضغط يشكّل مشكلات كبيرة عندما تكون أجزاؤه مبعثرة في كل مكان بطريقة غير منطقية ومزعجة، حتى عندما لا تكون هناك أي حمايات حقيقية أخرى ضد الاستخراج.

لكن بالتأكيد لا بد من وجود طريقة أفضل؟

هناك بعض الأمور المثيرة للاهتمام في ملفات Zip تحديدًا (وهي الصيغة الأساسية المستخدمة لملفات JAR). وباعتباري طالبًا مجتهدًا في المجلة الدولية لـ PoC||GTFO منذ مدة ليست بالقصيرة، وتابعًا بشكل خاص لأعمال Ange Albertini في حيل تنسيقات الملفات، رأيت أنه قد يكون داخل ملف zip بيانات كافية عن الملف نفسه لتتيح لك القيام بعمل جيد في إعادة تجميعه معًا.

إذن، بعد أن تجاوزنا النقاط المرجعية، لندخل في التفاصيل التقنية.

قبل كل شيء، قد لا نعرف تفاصيل نظام الملفات (ومن منظور بحثي، وبشكل مستقل عن النظام الذي واجهت فيه المشكلة، قررت أنه من الأفضل ببساطة ألّا أهتم بها). لكننا نعرف شيئًا أو شيئين عن الطريقة التي تنفَّذ بها معظم أنظمة الملفات. على وجه الخصوص، نعرف أنها تميل إلى أن تُكتب على شكل وحدات (chunks). لهذه الوحدات حد أدنى من الحجم، يُعرف بالصفحات (pages)، ويمكننا تحديد حجم الصفحة هذا من خلال تصفّح التفريغ وتحديد أصغر حجم كتلة تتم كتابته.

بعض هذه الوحدات قد تكون متتالية، وبعضها ليس كذلك، دون نمط واضح لمعرفة متى تكون الكتل متتالية.

وخلاصة القول، إن المشكلة التي نواجهها هي كيفية إعادة ترتيب صفحات البيانات بحيث توفّر لنا صورًا صالحة (أو قريبة بما يكفي) للملفات التي نريد استخراجها.

ملفات Zip مكتوبة بطريقة تنفّذ نوعًا من التسلسل الهرمي العكسي. أولًا تأتي بيانات الملف المضغوطة (مغلّفة في ترويسات ملفات محلية (local file headers) تصفها). ثم الدليل المركزي (central directory) (الذي يسرد إزاحات ترويسات الملفات المحلية)، ثم سجل نهاية الدليل المركزي (end of central directory) (الذي يصف، من بين أمور أخرى، عدد الملفات المخزنة في zip، والإزاحة التي يبدأ عندها الدليل المركزي، وحجم الدليل المركزي).

دعنا نقلب ذلك رأسًا على عقب، ونحفر قليلًا في مزيد من التفاصيل:

  • سجل نهاية الدليل المركزي (EOCD) يخبرنا بـ:

    • الموقع الدقيق، داخل ملف Zip، لسجل EOCD (إزاحة الدليل المركزي CD، بالإضافة إلى طول CD، الذي يسبق EOCD)
    • عدد الملفات (وبالتالي عدد سجلات CD) التي يجب البحث عنها.
    • الموقع المحدد في ملف Zip لأول سجل CD.
  • كل سجل في الدليل المركزي يخبرنا بـ:

    • CRC32 لبيانات الملف المضغوطة
    • الطابع الزمني
    • الكثير من البيانات الوصفية الأخرى (طريقة الضغط، الأعلام، إصدار نظام التشغيل المستخدم/المطلوب...)
    • فهرس داخل الملف لوحدة LF المقابلة
    • والأهم: بيانات كافية لبناء صورة لوحدة LF المقابلة.
  • كل سجل ملف محلي (Local File) يخبرنا بـ:

    • موقع بداية ملف داخل التفريغ لدينا
    • إذا كان الملف صغيرًا بما يكفي، نحصل على الملف كاملًا داخل الصفحة نفسها، أو بفضل ظهور ترويسة الملف التالية في وحدة الصفحة التالية من ملف zip!
    • إذا كانت ملفات صغيرة كافية معبأة في صفحات كافية، يمكننا استخدام مواقع الصفحات وقيم الدليل المعروفة لإنشاء ترتيب للصفحات (مع وجود فجوات معروفة!)

كل ما سبق يقودنا إلى إعادة بناء الغالبية العظمى من الملف.

منعطف الحبكة — يجب أن نتعامل واقعيًا مع أكثر من برنامج ثابت JAR واحد!

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

الحل المطلوب هنا هو خوارزمية kmeans (المعروفة أيضًا باسم «خوارزمية لويد»). يوجد فيديو رائع هنا يشرح طريقة عملها. كان لدى SciPy نسخة جيدة جاهزة، لكن كان عليّ أن أحدد/ أرقّع الكريت الوحيد في مجال التجميع العنقودي/التحليلات الذي ينفّذ الخوارزمية لكي يعمل ذلك مع تطبيق Rust. لحسن الحظ لم أضطر إلى كتابتها من الصفر.

بعد ذلك، تكون المهمة قد أُنجزت على أكمل وجه.

يمكننا استخدام عدد من السمات للقيام بذلك. حقول Flags وMethod وVersion تختلف جميعًا بناءً على حزمة Zip المستخدمة لضغط الملف. إضافة إلى ذلك، تحتوي الترويسات على طوابع زمنية، ومن غير المرجح عمومًا أن تكون جميع البرامج الثابتة قد جُمعت وضُغطت في الوقت نفسه تمامًا.

على سبيل الاستطراد، يجدر بالذكر أن ملفات Zip تستخدم طوابع زمنية بصيغة MS-DOS، وهي قيم قصيرة (shorts) معبأة بالبتات تمثل السنة-الشهر-اليوم والساعة-الدقيقة-ثانيتين. إذا لم تُحوَّل هذه القيم إلى قيمة عددية مطلقة قبل استخدامها كبيانات تصنيف، فقد تعطي وزنًا لفرق سنة بقدر وزنك لفرق ثانية، وهذا ليس جيدًا أبدًا!

نحوّل هذه القيم إلى متجه إقليدي (Euclidean Vector) (وهي كلمة فاخرة لمصفوفة من القيم ذات أبعاد n في ℝ، أو إحداثيات عشرية (float)، لكن الفيديو المرتبط أعلاه هو على الأرجح التفسير الأكثر وضوحًا) وتقوم خوارزمية التجميع العنقودي بمعظم الباقي، إذ تجمع كل الترويسات التي تم تحليلها في عدد الدلاء (buckets) الذي نتوقعه.

ملاحظة جانبية سريعة حول التحليل

رغم أنني كتبت هذا في سكربت بايثون مبدئي إلى حد ما لاختبار هذه الطريقة، وبعدما وصلت إلى معدل استعادة محتوى JAR يبلغ نحو 70-80% مع النموذج الإثباتي (PoC)، قررت التوقف عند هذا الحد والانتقال إلى تنفيذ نسخة سريعة بلغة Rust.

لغة Rust لديها كريت (crate) يُدعى nom، وهو رائع للغاية لكتابة أدوات التحقق من المحلِّلات (parser-verifiers). كانت هذه واحدة من عوامل الجذب الرئيسية لإعادة كتابته بلغة Rust، على فكرة. القدرة على كتابة محلِّلات واضحة وصارمة للغاية تجعل هذا أسهل بكثير من محاولة معالجة كل هذا بلغة Python (التي تميل إلى أن تكون أكثر تساهلًا بكثير، لدرجة أنه يصعب أحيانًا أن تكون متأكدًا من أنك لا تتجاهل حالات الفشل الخاطئة وتفوتك حالة حافة).

إذا كانت المحلِّلات الرائعة والسريعة والمقروءة تثير اهتمامك، فاطلع على:

  • كتابة المحلِّلات كما لو كان العام 2017
  • معايير أداء Nom — حيث كتب شخص ما محللًا لبروتوكول http من الصفر بلغة Rust، أسرع قليلًا من تطبيق C سريع جدًا، وبدون تجاوزات في سعة المخزن المؤقت.

وعلاوة على ذلك، فإن تشغيل تحليل من هذا النوع في Python بطيء بطبيعته، ولم يكن مقصودًا أبدًا أن يكون أكثر من مجرد طريق إلى PoC لاستكشاف جدوى هذا النهج.

على أي حال، يكفي هذا...

مواصلة التقدم

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

يمكننا أيضًا تحقيق مكسب سريع عبر إيجاد حالات يكون فيها ترويس ملف محلي غير قابل للتحليل بسبب حدّ صفحة (يجب أن نتمكن من مطابقتها مع نظير مصطفّ بنفس الطريقة، على الأقل في الحالات التي تكون فيها الاصطفافات المشابهة فريدة ولا تتصادم مع آثار الفساد الأخرى).

كيف نتحقق من المرشّحين للصفحات المفقودة؟ حسنًا، لدينا مجاميع CRC32 للملفات موجودة هناك مباشرةً في الدليل المركزي! بدلًا من حساب CRC32 على الملف كاملًا، ربما تكون أفضل طريقة هي حساب CRC32 على الوحدات التي نعرفها بالفعل (بالاتجاه الأمامي من البيانات الموجودة في نهاية الصفحة قبل أن تبدأ فجوتنا، وبالاتجاه العكسي من البيانات — أو من وحدة DataDescriptor بعد تدفق deflate)، ونستنتج من هذه القيم قيمة CRC32 الوسيطة التي ينبغي أن نتوقعها لكل كتلة من الصفحات المفقودة.

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

أردت فقط بناء هذا الشيء اللعين، فما الأمر؟

إذا أردت العبث به، ثبّت Rust (يُوصى باستخدام rustup الليلي الرائع). ثم:

root@kitploit:~
$ git clone [repo]
...
$ cd zipdefrag
...
$ cargo build --release

يمكنك تجنّب وسم release لتمكين التصحيح.

ستكون نواتج البناء في /target/{debug,release}

وثّق البناء باستخدام cargo doc (هذا الكريت موثّق بكثافة. أنا أحب الكتابة).

حاليًا لا يوجد أي مخرجات طرفية افتراضية لنسخة Rust؛ إذا أردت تشغيل أداة سطر الأوامر التجريبية (CLI harness)، فأنت بحاجة إلى تعيين متغير البيئة RUST_LOG=zipdefrag، وهو ما يتيح تسجيلًا طرفيًا مفصّلًا يعرض التحليل حتى الآن.

المزيد قادم:

  • ملف تنفيذي أصلي سريع ومحمول (مع خطافات Python) لحل ألغاز تفريغات zip من أنظمة ملفات غير معروفة.

  • تفريغ توضيحي

مشكلات معروفة

  • الأداء معطوب حاليًا في تطبيق Rust بسبب سلوك مسرف في البحث عن وحدات LFH المقابلة. سأصلح هذا وأتعلّم الدرس.

  • لا تعمل هذه التقنية جيدًا عندما يكون العديد من الملفات في JAR أكبر بكثير من حجم الصفحة. وبما أنها تعتمد على استخدام مكثف للبنية المتأصلة في ملفات zip، فإن الملفات كثيفة البيانات لا تعمل بشكل جيد.

ومن المريح أن ملفات class تميل عمومًا إلى أن تكون صغيرة نسبيًا بالنسبة لتطبيقات J2ME المصغّرة (midlets)، لكن الملفات الثنائية الكبيرة المعبأة في الداخل ستكون على الأرجح غير قابلة للاسترجاع.

أيضًا، يحتوي PoC المكتوب بلغة Python على عدد من الأخطاء الحسابية.

تنزيل الأداة