漏洞介绍

Nginx 在配置 alias 的时候,如果 location 最后不是以斜杠结尾,而 alias 以斜杠结尾,那么将出现目录穿越漏洞。

通过实验了解漏洞

实验靶场用的是《从 0 到 1:CTFer 成长之路》第一章第三节任意文件读取漏洞的第 2 个实验靶场。

靶场的配置文件 docker-compose.yml 内容如下

version: '3.2'

services:
  web:
    image: registry.cn-hangzhou.aliyuncs.com/n1book/web-file-read-2:latest
    ports:
      - 80:80

使用 docker-compose up -d 命令启动即可。

nginx 的配置文件在/etc/nginx/sites-available 目录下,内容为:

server {
    listen 80;

    root /var/www/html/;

    index index.html;

    server_name _;

    autoindex on;

    location /img {
        alias /tmp/;
    }
}

可以看到为路径/img 配置了别名/tmp/。关键点就在这,location 最后没有斜杠,alias 最后有斜杠,所以存在 nginx 目录穿越漏洞(漏洞原理下面会讲)。

访问 http://localhost/img/img.gif 实际返回的是/tmp/img.gif

因为启用了 autoindex,可以比较方便看到路径下有哪些文件。

利用漏洞,访问 http://localhost/img../,穿越到了/tmp 的上级目录,也就是根目录。

看到根目录下有 flag 文件,成功拿到 flag,靶场完成!

疑问

运维配置少输入一个斜杠就可能导致漏洞,为什么 Nginx 官方不修复这个漏洞?网上查阅这个漏洞的修复方式,均为修改为正确配置,并没有升级至最新版本这类方法。

这个疑问我也在知乎上提了问题,但并没有得到明确的回答。

后来通过对漏洞原理的深入理解,自己解开了这个疑惑。

漏洞原理

理解目录穿越漏洞首先要知道两个前置知识,一个是 Nginx 配置中 alias 、 proxy_pass 、 root 的机制,另一个是 location 的匹配机制。这里就先不讲 proxy_pass 和 root 了。

找了几篇参考的文章:

  1. Nginx 代理:路径代理配置 root 、 alias 、 proxy_pass 的区别 – 我命倾尘 – 博客园 (cnblogs.com)
  2. 一文读懂 nginx 的 location 匹配规则 – wangqingyong – 博客园 (cnblogs.com)
  3. Nginx location 匹配规则 – Ryan.Miao – 博客园 (cnblogs.com)
  4. Nginx 中 location 与 root,alias,proxy_pass 的使用 | 王硕’s Blog (ws.lu)

alias 机制和 location 匹配

简单来说,alias 机制就是用 alias 替换 location 匹配到的内容。 location 匹配就是从 url 最左边开始找,

举个例子,假设配置文件如下

location /xxx/ {
	  alias /path/to/file/;
}

那么访问 http://localhost/xxx/index.html/xxx/替换成/path/to/file/,那么实际返回的资源是/path/to/file/index.html 文件。

location /xxx {
    alias /path/to/file;
}

同理,访问 http://localhost/xxx/index.html/xxx 替换成/path/to/file,那么实际返回的资源还是/path/to/file/index.html 文件。

当配置不当时

location /xxx {
    alias /path/to/file/;
}

访问 http://localhost/xxx/index.html/xxx 替换成/path/to/file/,替换结果就是/path/to/file//index.html,注意这里有两个斜杠,程序会自动修正,多个连续斜杠视为一个斜杠,结果是/path/to/file/index.html,也就和上面一样。

插个题外话,多个连续斜杠的机制应该是通用的,可以在浏览器里试试 http://localhost////index.html 访问的就是首页,或者在 Linux 里用 ls 命令,查看文件目录/home/dir//home///dir/结果是一样的。

# ls /var/www/html
index.html
# ls /var///www//html////
index.html

然后就回到漏洞的 payload,当访问/xxx../index.html 时,前面的/xxx 命中匹配,替换成/path/to/file/,结果为/path/to/file/../index.html,造成了目录穿越。

直接访问上级目录为什么不行?

比如我直接在浏览器地址栏输入 http://localhost/img/../,按回车,浏览器自动转成了 http://localhost/

那我通过 BurpSuite 抓包,强制修改 URL 呢。

返回的依旧是首页的内容。意思是 URL 发送到后端还会自动计算一次上级目录,修正 URL 后再拿去匹配路由规则。再试试多层上级目录:

好的确认了就是这样,后端会自动修正 URL 中的上级目录,所以直接访问 http://localhost/img/../没用。

换个玩法,进一步验证匹配和替换机制

假如 location 和 alias 都没有斜杠,是不是可以访问另一个目录名相似的目录呢?

将配置文件修改成:

location /img {
    alias /tmp;
}

在根目录创建一个叫 tmpaaa 的文件夹,里面创建一个 hello 文件。

# mkdir /tmpaaa
# touch /tmpaaa/hello
# ls /tmpaaa
hello

访问 http://localhost/imgaaa/,果不其然,看到了 hello 文件。

解答疑问

所以并不是 Nginx 官方不修复这个漏洞,而是漏洞 「合理」 利用了机制实现了目录穿越,这本身就是 nginx 规则的一部分。

订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论