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了。
找了几篇参考的文章:
Nginx代理:路径代理配置root、alias、proxy_pass的区别 - 我命倾尘 - 博客园 (cnblogs.com)
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/htmlindex.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规则的一部分。
- 0
- 0
-
分享