/ 搞搞学术 / 34浏览

Nginx目录穿越漏洞

文章目录
  • 漏洞介绍
  • 通过实验了解漏洞
  • 疑问
  • 漏洞原理
  • 漏洞介绍

    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规则的一部分。

    Docker容器识别
    为什么AES在线加密每次结果不一样(CryptoJS库)
    HTTP的Referer请求头为什么少了个字母r?

    0

    1. This post has no comment yet

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注