Git CVE-2018-11235 以及 ZipperDown
CVE-2018-11235
日前收到消息,安全部门让更新 Git 客户端,这是怎么回事呢?
近日Git客户端被发现存在一个潜在的远程代码执行漏洞(CVE-2018-11235),当用户使用’git clone –recurse-submodules’ 命令克隆恶意代码仓库时, 可易导致本地任意代码执行,被植入病毒、木马等,目前利用的POC代码已经公开。
通过给出的几个链接进行了一番观摩学习
- https://marc.info/?l=git&m=152761328506724&w=2
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-11235
- https://blogs.msdn.microsoft.com/devops/2018/05/29/announcing-the-may-2018-git-security-vulnerability/
大概了解到构造了目录穿越漏洞从而达到执行任意代码的目的,到底是怎么做到的没研究明白。于是找到一些白帽子的博客学习,阿里云社区上有篇文章详细分析了漏洞的原理、构造方法并从 Git 源码上解释了原因以及简要分析了修复代码
https://xz.aliyun.com/t/2371#toc-0
Git 的 hook 脚本
hook 脚本是放在 .git/hooks
目录下,并且这个目录不会被传送,也就是说当 clone 一个仓库时不会得到脚本文件。这些脚本都是客户端侧自己给自己加的,所以说这里有一层过滤防护——hook 脚本不会在网络中传送,因而一定程度断绝了远程代码执行的危险。
构造目录穿越,传送恶意脚本
通过利用 Git 子模块功能,绕过前述 hook 脚本过滤的保护,将脚本从远端推送(传递)到了 .git/hooks/
目录。
假设一个子模块叫做 vuln
,他的 .gitmodules 配置如下
[submodule “vuln”]
path = vuln
url = ./../repo_sub
本来正常的子模块 Git 目录为 .git/modules/vuln
,但最后被构造为 .git/modules/../../vuln
,指向了当前的目录 vuln
- 将目录
.git/modules/vuln
拷贝到当前目录modules
下。根目录中的 modules 目录是用来存放子模块代码的目录. - 往
modules/vuln
目录中的hooks
目录添加 hook 脚本。 - 构造子模块,使其
name
成为../../modules/vuln
,使子模块的Git
目录信息指向当前目录下module/vuln
- 构造 repo,使其在 git clone 时触发 hook 脚本
修复代码
https://github.com/git/git/commit/0383bbb9015898cbc79abd7b64316484d7713b44
主要是对从 .gitmodules
中获取的 name
进行了检查
问题就转为了如何检查名字中是否带有 ../
的字段?
int check_submodule_name(const char *name)
{
/* Disallow empty names */
if (!*name)
return -1;
/*
* Look for '..' as a path component. Check both '/' and '\\' as
* separators rather than is_dir_sep(), because we want the name rules
* to be consistent across platforms.
*/
goto in_component; /* always start inside component */
while (*name) {
char c = *name++;
if (c == '/' || c == '\\') {
in_component:
if (name[0] == '.' && name[1] == '.' &&
(!name[2] || name[2] == '/' || name[2] == '\\'))
return -1;
}
}
return 0;
}
这段代码里使用了 goto,goto 也不是不能用在生产生活中。五六个判断条件组合在一起也不是什么大逆不道的事情。需要检查 \ 来达到跨平台保护?什么平台是用 \ 来做目录分割?Windows?
ZipperDown
不久之前 iOS 上也有个类似的问题,不过复现方法简单多了。两个漏洞都具有相同的环境
- 可接收来自远端的脚本
- 客户端会在某个时刻调用特定目录下的脚本
所以,只需要将来自 1 的脚本想办法弄到 2 中的目录就行,在 iOS 上广泛存在热补文件,构造恶意的脚本替换正常的脚本就可以达到攻击的目的。
1.App直接接收不可信Zip文件,并使用SSZipArchive/ZipArchive(或其它存在路径穿越问题的代码)解压。例如聊天应用、文件管理应用中可能存在这类业务场景。
2.App通过HTTP下载Zip文件,使用SSZipArchive/ZipArchive(或其它存在路径穿越问题的代码)解压。在这种场景下,攻击者可以通过流量劫持等途径,将正常Zip文件替换为恶意Zip文件,在App中实现文件覆盖。
第二点广泛存在,我们的业务代码中就存在从非 HTTPS 协议中下载 zip 包的情况,即使 HTTPS 也不一定安全,也有可能中间人攻击。中间人攻击的典型案例就是 Charles 抓 HTTPS 的包,MrPeak 介绍的 mitmproxy 工具也是这个原理。