三个案例看Nginx配置安全

之前在Sec-News中推荐了一个开源程序 https://github.com/yandex/gixy ,作用是来检测Nginx配置文件中存在的问题。正好Pwnhub上周的比赛也出现了一道题,包含由Nginx配置错误导致的漏洞。

所以我挑选我觉得比较有趣,而且很有可能犯错误的三个典型案例,来说说Nginx配置文件的安全。

另外,本文所涉及的三个案例,均已上线到Vulhub( https://github.com/phith0n/vulhub/tree/master/nginx/insecure-configuration ),阅读本文的同时可以自己动手测试。

$uri导致的CRLF注入漏洞

下面两种情景十分常见:

  1. 用户访问http://example.com/aabbcc,自动跳转到https://example.com/aabbcc
  2. 用户访问http://example.com/aabbcc,自动跳转到http://www.example.com/aabbcc

比如我的博客,访问http://www.leavesongs.com/other/tinger.html,将会301跳转到https://www.leavesongs.com/other/tinger.html。随着现在https的普及,很多站点都强制使用https访问,这样的跳转非常常见。

第二个场景主要是为了统一用户访问的域名,更加有益于SEO优化。

在跳转的过程中,我们需要保证用户访问的页面不变,所以需要从Nginx获取用户请求的文件路径。查看Nginx文档,可以发现有三个表示uri的变量:

  1. $uri
  2. $document_uri
  3. $request_uri

解释一下,1和2表示的是解码以后的请求路径,不带参数;3表示的是完整的URI(没有解码)。那么,如果运维配置了下列的代码:

location / {
    return 302 https://$host$uri;
}

因为$uri是解码以后的请求路径,所以可能就会包含换行符,也就造成了一个CRLF注入漏洞。(关于CRLF注入漏洞,可以参考我的老文章 https://www.leavesongs.com/PENETRATION/Sina-CRLF-Injection.html

这个CRLF注入漏洞可以导致会话固定漏洞、设置Cookie引发的CSRF漏洞或者XSS漏洞。其中,我们通过注入两个\r\n即可控制HTTP体进行XSS,但因为浏览器认为这是一个300跳转,所以并不会显示我们注入的内容。

这个情况下,我们可以利用一些技巧:比如使用CSP头来iframe的地址,这样浏览器就不会跳转,进而执行我们插入的HTML:

14967564064912.jpg

关于上述利用方法,可以参考我的另一篇文章《Bottle HTTP 头注入漏洞探究》。

如何修复这个CRLF漏洞?正确的做法应该是如下:

location / {
    return 302 https://$host$request_uri;
}

另外,由$uri导致的CRLF注入漏洞不仅可能出现在上述两个场景中,理论上,只要是可以设置HTTP头的场景都会出现这个问题。

目录穿越漏洞

这个常见于Nginx做反向代理的情况,动态的部分被proxy_pass传递给后端端口,而静态文件需要Nginx来处理。

假设静态文件存储在/home/目录下,而该目录在url中名字为files,那么就需要用alias设置目录的别名:

location /files {
    alias /home/;
}

此时,访问http://example.com/files/readme.txt,就可以获取/home/readme.txt文件。

但我们注意到,url上/files没有加后缀/,而alias设置的/home/是有后缀/的,这个/就导致我们可以从/home/目录穿越到他的上层目录:

14967571806301.jpg

进而我们获得了一个任意文件下载漏洞。

这个有趣的漏洞出现在了Pwnhub上一期比赛《寻找 SNH48》中,@Ricter师傅的题目。

如何解决这个漏洞?只需要保证location和alias的值都有后缀/或都没有这个后缀。

Http Header被覆盖的问题

众所周知,Nginx的配置文件分为Server、Location、If等一些配置块,并且存在包含关系,和编程语言比较类似。如果在外层配置的一些选项,是可以被继承到内层的。

但这里的继承也有一些特性,比如add_header,子块中配置后将会覆盖父块中的add_header添加的所有HTTP头,造成一些安全隐患。

如下列代码,Server块添加了CSP头:

server {
    ...
    add_header Content-Security-Policy "default-src 'self'";
    add_header X-Frame-Options DENY;

    location = /test1 {
        rewrite ^(.*)$ /xss.html break;
    }

    location = /test2 {
        add_header X-Content-Type-Options nosniff;
        rewrite ^(.*)$ /xss.html break;
    }
}

但/test2的location中又添加了X-Content-Type-Options头,导致父块中的add_header全部失效:

14967575824298.jpg

此时,test2的csp就完全失效了,我们成功触发XSS:

14967576277243.jpg

总结

Nginx配置文件造成的漏洞绝不止这三种,比如之前特别火的解析漏洞( https://github.com/phith0n/vulhub/tree/master/nginx_parsing_vulnerability ),也和Nginx的配置有一定关系。

解决这类漏洞,最根本的方法是仔细阅读官方文档,文档里说明了很多配置文件错误和正确的用法。最忌去百度网上的一些解决方法,很多错误就是一传十十传百,最后流传开来的。

另外,本文开头提到的工具gixy,我们也可以利用起来,网站上线前进行一下扫描,也许就能发现一些可能存在的问题。

参考文章:

赞赏

喜欢这篇文章?打赏1元

评论

ABCDEF 回复

哈!p师傅好,我发现了一个问题,当我测试第二个任意文件读取漏洞想要读取/usr/share/nginx/html这个web目录的时候,发现301跳转到index.html,所以web目录下的文件没办法读取,但是删除这个index.html就可以读取web目录了。
我又试了下,如果随便访问一个目录,并且这个目录恰好存在index.html的话都会强制跳转index.html
还有php文件,不管有没有index.html都不可以访问,其他的类型的文件可以访问。
请问是nginx配置的问题吗?具体在哪里呢

ABCDEF 回复

@ABCDEF
师傅的docker环境是可以访问php的,我自己搭建的不可以,尴尬

李瑞 回复

我看了下crlf相关的问题。经验证jetty6.1.6rc1后不存在crlf漏洞。
rfc本身考虑到这些问题https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2,要求receives a CRLF first, it should ignore the CRLF
php是5.1.2解决 http://php.net/manual/en/function.header.php This function now prevents more than one header to be sent at once as a protection against header injection attacks.

tomcat参考http://grokbase.com/t/tomcat/users/1194m46hms/crlf-stripped-in-tomcat-response-header,其对crlf限制不严格,lr即可换行(8.5.23 is generating CRLF in response (showing up as ^M in vim), while previous versions of tomcat are just producing LF.),报道https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3544显示Tomcat 6.x before 6.0.37 and 7.x before 7.0.30存在问题但存疑,我认为tomcat5即不存在问题,将%da%0a替换为%20。

weblogic支持crlf漏洞

漏洞触发也与浏览器有关系https://bugzilla.mozilla.org/show_bug.cgi?id=655389

一个解决办法是配置Apache ngnix rule类似

RewriteCond %{THE_REQUEST} ^.*(\\r|\\n|%0A|%0D).*
RewriteRule .* /xxxxxxx/xxxxxxx/inicio? [R,L]

在实际中,nodejs+tengine出现过不少案例。
回到ngnix,举个例子,配置文件中设置http-https为rewrite .* https://$host$uri redirect;
那么对于想通过location跳转的情况,chrome Chrome 16.0.912.63后的版本浏览器会显示ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION。而想设置绕过xss策略执行xss脚本,这里因为localtion已经跳转到https,所以xss不会触发。只有设置cookie的办法,因为同源策略所以会生效。有更好的利用方法欢迎多交流

ClarkKent 回复

学习一下 小白完全不明白

JoyChou 回复

alias的问题,
location /files {
alias /home/viarus/;
}
这样配置就不会有安全问题233,只能往上走一层。

JoyChou 回复

@JoyChou 能往上一层也算是有问题吧,只是不能随意任意文件读取了,比如/etc/passwd。如果开了目录浏览,还是能泄露一些信息。

56音乐网 回复

不错的博客,可以和我的网站换链接吗?

hello 回复

好文章,顶一个

123456789 回复

后排请教一下:我目前擅长渗透测试和PHP代码审计,自学1年多了,但是现在总感觉干事情没动力,一提起代码审计前前后后也就是SQL注入,xss,文件上传...那几个漏洞来回玩而已,完全提不起兴趣。渗透测试也是一样,简单的网站没什么水平,用脑子就能想出攻击过程。复杂的网站也没啥漏洞,测了也白测。总之,我现在不知道该干啥,很彷徨。。。不知道博主有没有类似的情况出现过?现在我该怎么办?

phithon 回复

@123456789 两条路,1是仔细研究每个漏洞的原理,视野扩充到整个web安全领域,接触各种语言各种框架,每个web有关的cve都可以进行研究;2是往死里挖众测和src,刷排名刷钱。

404notfound 回复

@phithon 我很自觉的选择了第一条路-.-

迷茫的大一学弟 回复

哇,博客从头看到了尾,感觉博主成长速度好快啊,有些文章也略带文艺。很想拥有博主一样的大学四年。

her0ma 回复

前排膜拜师傅!

ttt 回复

nginx的解析漏洞是nginx的配置问题吗?

“” 回复

@ttt 当然是

chybeta 回复

前排膜师傅!

captcha