-
-
[原创]Binwalk命令执行漏洞复现-CVE-2022-4510
-
发表于: 2023-2-8 19:56 13333
-
偶然间看见了binwalk的这个漏洞,这个工具知名度不必多说了,所以我去查看了我环境中的binwalk的版本
版本2.2.1刚好符合漏洞区间2.12b-2.3.3,所以决定自己去亲自复现一下这个漏洞
参考:https://onekey.com/blog/security-advisory-remote-command-execution-in-binwalk/
https://mp.weixin.qq.com/s/gZp87CAeuM1eC91kA8Cqeg
在漏洞介绍中,binwalk 的PFS文件的提取器存在着路径穿越漏洞,从而造成远程代码执行
所以我们去binwalk的路径下搜索一下pfs文件
看到出现了这个俩个相关文件路径,在后续的查看中这俩个是相同的文件,所以我选择了/src/binwalk/plugins/unpfs.py 进行查看
部分代码如下:
问题就出现在"os.path.join"这个函数之中
os.path.join函数从后往前去进行拼接 其中碰到第一个”/“这个字符后会将前面全部抛弃,而如果碰到了"/" 或者 "../"这样的字符则会将前面的路径全部保留,其中"/"比"./”或者"../"的优先级高,大体意思如下
所以"os.path.join"拼接后的路径并不能完全解析文件的后续路径,即使unpfs.py代码中有着路径穿越的检查,所以这里存在着漏洞
当确定存在路径穿越漏洞后,常规的利用思路是覆盖ssh文件或者其它的重要文件
但是作者想要不依赖环境去获得权限
这就不得不提到了binwalk的一种特性,它在运行的时候会加载所有的插件去保证文件的提取,同时binwalk运行用户自定义插件,且开放了插件的api,详情如下:
https://github.com/ReFirmLabs/binwalk/wiki/Creating-Custom-Plugins#plugin-activation
我们可以通过python编写自定义插件,然后将其放入到“$HOME/.config/binwalk/plugins/”路径中,这样在后续的运行中binwalk就会加载我们的程序,
因为是python编写,所有我们就可以去进行多种操作,手写socket啊,或者使用os.system查看敏感文件什么的
这里官方提供了poc:
https://github.com/ReFirmLabs/binwalk/pull/617
我们可以根据官方的文件头去进行自定义poc
编写好反弹shel的poc后我们用winhex将文件头复制到前面
文件头内容如下:
别忘了修改一下文件的大小也就是c100处
然后将其改名为poc.pfs并且压缩一下,
然后进入主目录下我们去使用binwalk去运行poc.zip这个压缩文件
可以看到在binwalk的插件目录下我们成功写入了自定义的脚本
同时成功的反弹了shell
截图如下:
def
extractor(
self
, fname):
fname
=
os.path.abspath(fname)
out_dir
=
binwalk.core.common.unique_file_name(os.path.join(os.path.dirname(fname),
"pfs-root"
))
try
:
with PFS(fname) as fs:
/
/
重复读取pfs文件内容
# The end of PFS meta data is the start of the actual data
data
=
binwalk.core.common.BlockFile(fname,
'rb'
)
data.seek(fs.get_end_of_meta_data())
for
entry
in
fs.entries():
outfile_path
=
os.path.join(out_dir, entry.fname)
/
/
将压缩包中的路径拼接到out_dir路径中 binwalk根据这个路径去进行响应路径文件填写
if
not
outfile_path.startswith(out_dir):
binwalk.core.common.warning(
"Unpfs extractor detected directory traversal attempt for file: '%s'. Refusing to extract."
%
outfile_path)
else
:
self
._create_dir_from_fname(outfile_path)
outfile
=
binwalk.core.common.BlockFile(outfile_path,
'wb'
)
outfile.write(data.read(entry.fsize))
outfile.close()
data.close()
def
extractor(
self
, fname):
fname
=
os.path.abspath(fname)
out_dir
=
binwalk.core.common.unique_file_name(os.path.join(os.path.dirname(fname),
"pfs-root"
))
try
:
with PFS(fname) as fs:
/
/
重复读取pfs文件内容
# The end of PFS meta data is the start of the actual data
data
=
binwalk.core.common.BlockFile(fname,
'rb'
)
data.seek(fs.get_end_of_meta_data())
for
entry
in
fs.entries():
outfile_path
=
os.path.join(out_dir, entry.fname)
/
/
将压缩包中的路径拼接到out_dir路径中 binwalk根据这个路径去进行响应路径文件填写
if
not
outfile_path.startswith(out_dir):
binwalk.core.common.warning(
"Unpfs extractor detected directory traversal attempt for file: '%s'. Refusing to extract."
%
outfile_path)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!