漏洞介绍
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 | <?php |
gitlist\src\Git\Repository.php#L319-L331
其中,$query是搜索的关键字,$branch是搜索的分支。
如果用户输入的$query的值是--open-files-in-pager=id;,将可以执行id命令:
escapeshellarg
PHP内置的命令执行函数(如shell_exec、system),都只接受一个“字符串”作为参数。而在内核中,这个字符串将被直接作为一条shell命令来调用,这种情况下就极为容易出现命令注入漏洞。
由于这个特点,PHP特别准备了两个过滤函数:
- escapeshellcmd
- escapeshellarg
二者分工不同,前者为了防止用户利用shell的一些技巧(如分号、反引号等),执行其他命令;后者是为了防止用户的输入逃逸出“参数值”的位置,变成一个“参数选项”。
escapeshellarg为什么没有奏效?
导致这个漏洞的原因,有几点:
- 开发者对于
escapeshellarg函数的误解,造成参数注入 git grep的参数--open-files-in-pager的值,将被直接执行
理论上,在经过$query = escapeshellarg($query);处理后,$query将变成一个由单引号包裹的字符串。但不出漏洞的前提是,这个字符串应该出现在“参数值”的位置,而不是出现在参数选项(option)中。
我们可以试一下如下命令:
1 | git grep -i --line-number -e '--open-files-in-pager=id;' master |
如上图,我将$query放在了-e参数的值的位置,此时它就仅仅是一个字符串而已,并不会被当成参数--open-files-in-pager。
这应该作为本漏洞的最佳修复方法,也是git官方对pattern可能是用户输入的情况的一种解决方案(以下说明来自man-page):
漏洞复现
发送如下数据包:
1 | POST /example/tree/a/search HTTP/1.1 |

其中,我们访问的是/example/tree/a/search,example是项目名称,需要是目标gitlist上一个已存在的项目;a在正常情况下应该是分支的名称,也就是"grep -i --line-number {$query} $branch"中的$branch,但因为我们的$query被当成了一个参数,所以$branch就应该被当做搜索的关键字。
如果没有搜索结果的话,我们的命令是不会被执行的,所以我用了“a”这个关键字,只是为了保证能搜出结果,你也可以换成其他的试试。
数据包发送后,用docker compose exec web bash进入容器中,可见/tmp/success已成功创建:

poc使用
https://www.exploit-db.com/download/44548
由于该漏洞无回显,采用dnslog验证

1 | python2 44548.py |

dnslog出现回显

参考
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

