nginx文件解析漏洞
2013年夏天,析漏一个叫“nginx解析漏洞”的析漏东西在圈子里炸了。那会儿我还在做渗透测试,析漏客户丢过来一个IP,析漏说“你看看这个站有没有问题”。析漏打开一看,析漏nginx 1.4.0,析漏PHP-FPM跑着。析漏我随手传了个图片马,析漏文件名改成 漏洞的析漏根子不在nginx本身,而在nginx和PHP-FPM之间的析漏通信方式。nginx配置里常见这么一段: 问题出在 这个逻辑听起来很合理对吧?但攻击者只要能在服务器上传任意文件——哪怕是一张图片——就能构造出可执行的PHP代码。上传的时候在图片末尾附加 我见过最夸张的案例是一个电商站。上传头像功能只检查了Content-Type和文件头,后缀名随便改。攻击者传了个 修复方案其实不复杂。最直接的是在nginx配置里加一行: 这样nginx会把 还有个坑:很多人以为升级nginx到最新版就没事了。错。这个漏洞跟nginx版本关系不大,1.4、1.6、1.8甚至现在的1.20,只要配置不对,照样中招。核心是 顺带说一句,Apache的 如果你现在手里有nginx+PHP-FPM的环境,别光看配置文件里有没有shell.jpg/x.php,析漏访问一下——直接执行了。析漏当时后背一凉,析漏这玩意儿比Apache那个多后缀解析漏洞还离谱。析漏location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; include fastcgi_params; }fastcgi_params里的SCRIPT_FILENAME。nginx把请求的URI原样传给PHP-FPM,但PHP-FPM有个特性:它会对SCRIPT_FILENAME做fix_pathinfo处理。默认cgi.fix_pathinfo=1时,PHP-FPM会从右往左扫描路径,找到第一个存在的文件就执行。比如请求/uploads/shell.jpg/x.php,nginx一看.php$匹配上了,转给PHP-FPM。PHP-FPM发现x.php不存在,就往前找,找到shell.jpg存在,直接把它当PHP执行了。<?php eval($_POST['cmd']); ?>,然后访问/upload/evil.jpg/test.php,shell就到手了。更狠的是,有些站点允许上传.txt、.jpg甚至.zip,全都能被这样利用。avatar.png,里面藏着webshell,访问/avatar/avatar.png/1.php直接拿到服务器权限。后来查日志发现,从上传到提权,前后不到三分钟。fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;shell.jpg/x.php里的x.php识别为PATH_INFO,而不是让PHP-FPM去猜。另一个办法是把cgi.fix_pathinfo设成0,但这样会影响一些依赖PATH_INFO的框架,比如ThinkPHP的老版本。我一般推荐两个都做,双保险。fastcgi_split_path_info和cgi.fix_pathinfo的配合问题。我去年还碰到一个站,nginx 1.18.0,配置里没写fastcgi_split_path_info,PHP 7.4,cgi.fix_pathinfo默认值变成了1(PHP 5.3.9之后默认是1),照样能复现。mod_php也有类似问题,但表现形式不同。Apache是从左往右解析,shell.php.jpg会执行shell.php。nginx这个是从右往左,shell.jpg/x.php执行shell.jpg。方向相反,本质一样——都是路径解析的歧义被攻击者利用了。fastcgi_split_path_info。实际传个图片马试试,访问一下/图片路径/任意文件名.php。能执行,就赶紧改。这玩意儿不像SQL注入那样需要构造复杂payload,一个请求就搞定,门槛低得吓人。
-
上一篇
-
下一篇