Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/c3r34lk1ll3r/cve-2017-5123
تصعيد الامتيازاتالاستغلالالتعلم والتعليماستغلال الملفات الثنائيةمختبرات وتدريب عملي
GitHubc3r34lk1ll3r/cve-2017-5123

CVE-2017-5123

إثبات المفهوم CVE-2017-5123 - تصعيد الامتيازات المحلية - تجاوز SMEP/SMAP. بدون KASLR

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

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2017-5123

PoC CVE-2017-5123 - LPE - تجاوز SMAP/SMEP. بدون KASLR

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

مقدمة

في هذا الشرح الصغير، سأقوم بتحليل ثغرة في النواة تسمح لنا بالحصول على امتياز الجذر.

ينقسم هذا الملف إلى أربعة أجزاء:

  1. إعداد الجهاز الظاهري;
  2. تحليل الثغرة;
  3. الاستغلال;
  4. إثبات المفهوم.

أود أن أشير إلى أن هناك العديد من الطرق الأفضل لاستغلال هذا CVE (في الواقع، هذا مجرد PoC لتعلم النواة، ولا يمكن استخدامه في الواقع) لكنني أعتقد أن هذه المنهجية يمكن أن تكون مفيدة كمقدمة لاستغلال النواة.

إعداد الجهاز الظاهري

بناء النواة

تم تقديم هذه الثغرة في 4c48abe91be0 لذا نحتاج إلى بناء هذا الإصدار من النواة.

قد يكون هذا صعبًا بعض الشيء لأنه إصدار قديم ويجب تصحيح الكود. لقد قمت بإنشاء مستودع يحتوي على كود نواة مصحح بالفعل وملف .config حتى تتمكن من الاستنساخ والبناء.

git clone https://github.com/c3r34lk1ll3r/kernel_mirror.git
cd kernel_mirror
git checkout origin/modified_v4.14
wget https://gist.githubusercontent.com/c3r34lk1ll3r/c9c34ae86140cc7a24d0d90141686ee8/raw/52431b577a71e3fe8f89d6ce355ce9c1c54c53b6/.config
make -j 8 --output-sync=recurse

لاحظ أن هذه النواة سيتم بناؤها مع برامج تشغيل virtio حتى تتمكن من استخدام قرص virtio لمشاركة الملفات من/إلى الجهاز الظاهري.

إعداد نظام الجذر

الآن، سنقوم بإنشاء rootfs الأولي:

qemu-img create -f raw hda.raw 10G
# تنسيق القرص إلى ext4
mkfs.ext4 ./hda.raw 
# إنشاء نقطة تحميل للصورة
mkdir /tmp/mount1
# تحميل القرص
sudo mount -o loop ./hda.raw /tmp/mount1

بعد ذلك، يجب علينا تثبيت توزيعة لينكس أساسية، على سبيل المثال باستخدام pacstrap أو debootstrap.

sudo pacstrap /tmp/mount1 base base-devel vim

أخيرًا، يمكننا تعديل النظام:

# إضافة مستخدم 'test'
echo 'test:x:1000:1000::/home/test:/bin/bash' | sudo tee -a /tmp/mount1/etc/passwd
# بدون كلمة مرور
echo 'test::14871::::::' | sudo tee -a /tmp/mount1/etc/shadow 
# يمكننا تحميل قرص virtio لمشاركة الملفات بين المضيف والضيف
echo '/transient /home/test/shared 9p trans=virtio,version=9p2000.L,rw,user,exec 0 0' | sudo tee -a /tmp/mount1/etc/fstab
sudo mkdir -p /tmp/mount1/home/test/shared 
# من المفيد الحصول على صلاحية sudo
echo '%wheel ALL=(ALL) NOPASSWD: ALL' | sudo tee -a /tmp/mount1/etc/sudoers
echo 'wheel:x:998:test' | sudo tee -a /tmp/mount1/etc/group

sudo chown -R 1000:1000 /tmp/mount1/home/test
sudo umount /tmp/mount1

إذا كان كل شيء على ما يرام، يمكننا الآن تجربة نظام الاختبار الخاص بنا باستخدام qemu:

qemu-system-x86_64 \
    -kernel ./kernel_mirror/arch/x86_64/boot/bzImage \
    -hda ./hda.raw \
    -m 4G \
    -cpu "Skylake-Client-IBRS,ss=on,vmx=on,hypervisor=on,tsc-adjust=on,clflushopt=on,umip=on,md-clear=on,stibp=on,arch-capabilities=on,ssbd=on,xsaves=on,pdpe1gb=on,ibpb=on,amd-ssbd=on,skip-l1dfl-vmentry=on,hle=off,rtm=off" \
    -smp 4 \
    -vga virtio \
    -enable-kvm \
    -nographic \
    -machine type=q35,accel=kvm \
    -virtfs "fsdriver=local,id=fs.1,path=./trans_fs,security_model=mapped,writeout=immediate,mount_tag=/transient" \
    -append "root=/dev/sda rw noquiet nokaslr console=ttyS0 loglevel=5" \
    -chardev "vc,id=vc.0,cols=1920,rows=1080" \
    -net "user,hostfwd=tcp::10022-:22" \
    -net "nic" \
    -s

الثغرة

يصف وصف الـ CVE وجود عملية كتابة غير مقيدة أثناء استدعاء النظام waitid.

لنفتح kernel/exit.c وننظر إلى الكود:

SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
		infop, int, options, struct rusage __user *, ru)
{
    struct rusage r;
    struct waitid_info info = {.status = 0};
    long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
    int signo = 0;

    if (err > 0) {
        signo = SIGCHLD;
        err = 0;
        if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
            return -EFAULT;
    }
    if (!infop)
        return err;
    user_access_begin();
    unsafe_put_user(signo, &infop->si_signo, Efault);
    unsafe_put_user(0, &infop->si_errno, Efault);
    unsafe_put_user(info.cause, &infop->si_code, Efault);
    unsafe_put_user(info.pid, &infop->si_pid, Efault);
    unsafe_put_user(info.uid, &infop->si_uid, Efault);
    unsafe_put_user(info.status, &infop->si_status, Efault);
    user_access_end();
    return err;
Efault:
    user_access_end();
    return -EFAULT;
}

هذه الدالة مباشرة إلى حد ما: بعد بضع عمليات فحص، هناك استدعاءات متعددة لـ unsafe_put_user(...) ثم تعود الدالة.

الجزء الرئيسي من هذه الدالة يتكون من دالة unsafe_put_user(...) لذا دعنا ننتقل إلى هناك (arch/x86/include/asm/uaccess.h):

/*
 * The "unsafe" user accesses aren't really "unsafe", but the naming
 * is a big fat warning: you have to not only do the access_ok()
 * checking before using them, but you have to surround them with the
 * user_access_begin/end() pair.
 */
#define user_access_begin()	__uaccess_begin()
#define user_access_end()	__uaccess_end()

#define unsafe_put_user(x, ptr, err_label)					\
do {										\
    int __pu_err;								\
    __typeof__(*(ptr)) __pu_val = (x);					\
    __put_user_size(__pu_val, (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);	\
    if (unlikely(__pu_err)) goto err_label;					\
} while (0)

#define unsafe_get_user(x, ptr, err_label)					\
do {										\
    int __gu_err;								\  
    __inttype(*(ptr)) __gu_val;						\
    __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);	\
    (x) = (__force __typeof__(*(ptr)))__gu_val;				\
    if (unlikely(__gu_err)) goto err_label;					\
} while (0)

هناك تحذير كبير جدًا في التعليق: إذا كنت تريد استخدام unsafe_put/get_user، يجب عليك أولاً استدعاء access_ok() وإحاطتها بـ user_access_begin/end().

إذا ألقينا نظرة على الكود السابق (waitid)، يمكننا أن نرى أن access_ok() لم يتم استدعاؤها أبدًا، لذا فإن استدعاء النظام ينتهك هذا التحذير.

ولكن ما هي هذه الماكرو?

SMAP/SMEP

SMAP و SMEP هما ميزتان أمنيتان تم تقديمهما في النواة من أجل جعل كتابة الاستغلالات أكثر صعوبة. وتجدر الإشارة إلى أن هذه الميزات يتم فرضها بواسطة وحدة المعالجة المركزية.

SMEP تمنع تنفيذ كود مساحة المستخدم بينما تكون وحدة المعالجة المركزية في وضع المشرف؛ SMAP، بدلاً من ذلك، تمنع الوصول للقراءة/الكتابة إلى ذاكرة المستخدم.

تحتاج النواة إلى كتابة/قراءة البيانات من/إلى ذاكرة المستخدم ويمكن تحقيق ذلك بطريقتين:

  1. هناك دوال (مثل copy_from_user) تسمح بنسخ الذاكرة في مساحة النواة؛
  2. تعطيل SMAP مؤقتاً

كما نرى في تعريف unsafe_put_user، ستقوم هذه الدالة فقط بنسخ قيمة x في الذاكرة المشار إليها بواسطة ptr (وتنتقل إلى err_label إذا حدث خطأ). لقد قلنا للتو أن النواة لا يمكنها الوصول إلى مساحة المستخدم بسبب SMAP ولهذا السبب يجب أن تكون هذه الدوال محاطة بين user_access_begin/end().

#define __uaccess_begin() stac()
#define __uaccess_end()   clac()

كما نرى، user_access_begin/end هما ببساطة تعليمة ASM stac و clac.

  • stac: "يضبط بت AC في سجل EFLAGS. قد يتيح ذلك فحص المحاذاة لوصول بيانات وضع المستخدم. يسمح هذا بوصول صريح لوضع المشرف إلى صفحات وضع المستخدم حتى إذا تم تعيين بت SMAP في سجل CR4."
  • clac: "يمسح بت AC في سجل EFLAGS. يعطل هذا أي فحص محاذاة لوصول بيانات وضع المستخدم. إذا تم تعيين بت SMAP في سجل CR4، فإن هذا يمنع الوصول الصريح لوضع المشرف إلى صفحات وضع المستخدم."

بشكل أساسي، تقوم هاتان الماكرو بتمكين/تعطيل SMAP.

تنزيل الأداة