中间件解析漏洞
拜读了d09gy师傅的文章,记录一下笔记
概述
”服务器对脚本资源的理解差异,决定了服务器自身的安全性。“
解析漏洞是由于Web Server自身缺陷或者其相关配置存在缺陷导致服务器在解析网站资源文件时,出现的与所应当解析成的资源类型不一致的一类安全问题
这个所谓的不一致主要体现在错误地将”普通“文件当作脚本文件解析,导致服务器解析一些被精心构造的恶意文件,导致代码执行或被获取webshell
- 这里记录一下较为经典的解析漏洞
IIS解析漏洞
文件夹解析漏洞
-
影响版本
IIS 5.x 和6.0
-
漏洞内容
对于目录中名称为x.asp中的任何文件,包括其他类型的文件比如1.jpg,都会被当作ASP文件解析
在早期,很多网站的通用编辑器都是可以让用户自己去创建目录,利用编辑器创建example.asp文件夹,内置一个含有恶意asp代码的a.jpg文件,而ASP网站必然启用了ASP解析功能,那么这个a.jpg就会被当作ASP解析成功
-
思考
这里并不是利用了单一的漏洞点,文件夹解析漏洞和网站允许创建恶意文件夹这两个致命点缺一不可
分号截断漏洞
-
影响版本
IIS6.0
-
漏洞内容
IIS会将
1.asp;.jpg
这样的文件当作asp文件解析,在计算机对文件扩展名的理解上说,文件扩展名是以最后一个”.“后面的内容为依据,所以这个文件会被网站过滤程序理解成图片,但IIS会认为分号就是结尾,后面的内容被截断了,所以当作asp文件解析 -
思考
这种情况下,即使网站使用白名单判断上传的文件类型,只允许jpg文件,攻击者仍然可以实现攻击
防御
漏洞均为服务器本身缺陷所致,最佳方法即为升级IIS、打补丁
Nginx解析漏洞
文件类型错误解析漏洞
-
配置
Nginx会将用户请求的HTTP数据包解析成CGI环境变量,通过FastCGI协议发送给PHP-FPM的9000端口;PHP-FPM通过这些CGI环境变量,定义到用户需要执行的php文件并执行,将返回结果通过FastCGI协议的返回包返回给Nginx服务器
Nginx文件解析漏洞的产生原因是由于Nginx配置文件default.conf以及PHP配置文件php.ini的错误配置。
引发该漏洞的错误配置分别如下:
-
Nginx 在/etc/nginx/conf.d/default.conf文件下,有如下配置
location ~ \.php$ { fastcgi_index index.php; include fastcgi_params; fastcgi_params REDIRECT_STATUS 200; fastcgi_params SCRIPT_FILENAME $DOCUMENT_ROOT/$fastcgi_script_name; fastcgi_params DOCUMENT_ROOT /var/www/html; fastcgi_pass php:9000; }
其中引发Nginx文件解析漏洞的不正确配置,就包括
fastcgi_params SCRIPT_FILENAME $DOCUMENT_ROOT/$fastcgi_script_name
这一行配置意为:CGI环境变量SCRIPT_FILENAME的值是由$DOCUMENT_ROOT和$fastcgi_script_name二者拼接而来,$DOCUMENT_ROOT是web根路径,$fastcgi_script_name是HTTP请求的URI
举个例子,请求/index.php的时候,$DOCUMENT_ROOT的值就是/var/www/html,$fastcgi_script_name的值就是/index.php,所以SCRIPT_FILENAME的值为/var/www/html/index.php,当PHP-FPM获取到这个变量,就会去执行/var/www/html/index.php文件,并返回结果
而location ~ \.php$这一行会将path与.php进行正则匹配,匹配成功才会允许将数据发送给PHP-FPM
-
PATH_INFO是CGI端口CGI_RFC中定义的一个数据,是指PATH中去除SCRIPT_NAME后剩余的部分,比如请求”/index.php/yu/y0ung“,“/index.php”是SCRIPT_NAME,/yu/y0ung是PATH_INFO,正常情况下,Nginx应该使用fastcgi_split_path_info指令将PATH分割成$fastcgi_script_name和$fastcgi_path_info,但默认Nginx是不对此进行分割的,所以最后发送给PHP-FPM的是一个包含PATH_INFO的SCRIPT_FILENAME,就比如/var/www/html/index.php/yu/y0ung,这个路径在服务器上是不存在的,所以会报出相应错误
为了解决这种情况,PHP 在PHP的配置文件php.ini中,有cgi.fix_pathinfo变量,默认值为1,表示开启。该变量会对文件路径进行美化,当SCRIPT_FILENAME指向的文件不存在时,会去掉路径最后一个”/“及其后面的所有内容,举个例子,如果文件的上层路径为/index.php/yu/y0ung;当启用cgi.fix_pathinfo时,php检测到 “y0ung” 文件并不存在,则会向上寻找存在的文件,最终会找到index.php文件
可以利用这一特性,请求”/example.gif/.php“,此时PATH以.php结尾,通过了正则匹配,构造出了SCRIPT_FILENAME:/var/www/html/example.gif/.php,PHP-FPM收到请求后,发现文件不存在,就会向前寻找,发现/var/www/html/example.gif文件存在,则会将其当作php文件执行
-
当然,如若要实现上述将example.gif文件当作 .php的操作,还离不开 security.limit_extensions 属性的设置,该属性位于/etc/php-fpm.d/www.conf目录下,其作用是设置可以被当作php文件解析的文件后缀,如 security.limit_extensions .png .php 就代表着只有.png 和 . php结尾的文件才能被当作php文件执行。所以,实现Nginx文件解析漏洞的必要因素之一就是要把 security.limit_extensions 属性的属性值设为空,这才能让我们上述中的example.gif 文件被当成 .php文件执行
-
-
思考
该漏洞的本质是Nginx和PHP对PATH_INFO处理的差异,以及对网站配置上的一些失误导致的
空字节解析漏洞
-
影响版本
- 0.8.41~1.4.3
- 1.5.0~1.5.7
-
详情
如果Nginx配置文件的location中限制了解析文件类型:
location ~ \.php$
,如此,在正常情况下,只有php扩展名文件才能被发给FastCGI解析,但存在CVE-2013-4547漏洞的情况下,可以造成解析漏洞:请求
phpinfo.jpg[0x20][0x00].php
,这个URI可以通过location的正则匹配,但进入后,FastCGI在查找文件时被\0截断了,Nginx会错误地认为请求文件为phpinfo.jpg[0x20],并将其设置为SCRIPT_FILENAME的值发送给FastCGI,造成解析漏洞 -
利用
如果网站有文件上传点,但不允许php扩展名文件上传,可以尝试上传名为phpinfo.jpg[0x20]的文件([0x20] 表示空格),再利用解析漏洞解析该文件
值得一提的是,这里修改文件名的空字节需要使用burp抓包在hex模式下修改请求文件名的字符编码
检测
Nginx解析漏洞的表现形式就是任意文件都可以让php解释器执行,可以在目标站点中找一个静态文件,这里以robots.txt为例,利用bp查看请求包和响应包:
正常情况下,请求/robots.txt时,响应包的Content-Type是text/plain
如果请求/robots.txt/.php时,响应头字段变为php默认的text/html,并且增加了php的指纹X-Powered-By,则证明存在解析漏洞
此时,攻击者便可以上传webshell进行漏洞利用了
防御
-
文件类型错误解析
-
文件类型错误解析漏洞是PATH_INFO变量导致的,在不影响业务的情况下,可以在php.ini中关闭fix_pathinfo
-
PHP-FPM中新增了一个安全配置security.limit_extensions,通过设置其值,可以限制PHP-FPM执行的php文件的扩展名,将其值设置为”.php“,其他扩展名的文件就不会再作为php运行:
security.limit_extensions = .php
-
如果无法修改PHP的配置文件,也可以在Nginx的配置文件中增加如下选项:
fastcgi_split_path_info ^(.+\.php)(.*)$;
再此情况下,Nginx会按照正则表达式
^(.+\.php)(.*)$;
对PATH进行分割,匹配到的第一项作为”$fastcgi_script_name“,第二项作为”$fastcgi_path_info“
-
-
空字节解析
升级Nginx版本
Apache解析漏洞
通常指多扩展名导致执行任意代码的漏洞,主要由错误配置导致
多后缀解析漏洞
在apache的配置文件里,有一个配置选项为AddHandler:在用户请求某扩展名的文件时,使用某处理器处理
AddHandler是Apache与PHP能够正常运行的核心,只有设置了“AddHandler application/x-http-php.php”,Apache才会将“.php”为扩展名的文件交给处理器“application/x-http-php.php ”来处理
然而AddHandler指令有以下几个特点:
- 文件扩展名是大小写不敏感的
- 一个文件允许有多个扩展名,每个扩展名可以有一个处理器
假如有如下配置:
AddHandler application/x-http-php.php #.php 文件类型关联至 PHP 解释器
AddHandler cgi-script .cgi #所有以 .cgi 结尾的文件应当被视为 CGI 脚本并相应地执行
Apache会从左向右寻找所有可以被识别的扩展名,然后以最后一个可识别扩展名为准,解析这个文件,在带有上面配置的环境中:
- 如果上传了yuyoung.cgi.php,文件将交给application/x-http-php.php解析
- 如果上传了包含不认识扩展名的文件,比如yuyoung.php.xyz,将以最后一个可识别扩展名为准(即php)来解析该文件
如果开发者在文件上传的业务部分,使用黑名单校验文件内容,可以使用yuyoung.php.xyz这种黑名单不存在的扩展名绕过校验,并以php解析
Apache HTTPD 换行解析漏洞(CVE-2017-15715)
-
影响版本
2.4.0-2.4.29
为了应对上面提到的Apache多后缀解析漏洞,很多运维通过<FilesMatch>
配置,来限制匹配到的最后一个扩展名
如下:
<FilesMatch "[^.]+\.php$">
Sethandler application/x-http-php
</FilesMatch>
这里存在两个配置项:
- FilesMatch:设置一个用于URL路径匹配的正则表达式,在匹配上该正则表达式的情况下,再执行其中的命令
- SetHandler:设置当前配置块内默认的处理器,这里配置的是以php的方式处理
这样看,这个配置便意为:文件名以.php结尾的文件才会交给application/x-http-php处理器,这样似乎可以修复多后缀解析漏洞
但是:Apache使用的是Perl兼容的正则表达式库PCRE,这里的$有自己的语法标准,其能匹配以下三个内容:
- 一个字符串的结尾
- 一个以换行符作为结尾的字符串的结尾部分
- 在多行模式开启的情况下,匹配每一行的结尾
所以,如果文件名是以.php\n结尾(\n即换行),他依然能够匹配上正则表达式[^.]+\.php$
由此得到CVE-2017-15715的利用:如果开发者在文件上传的业务部分,使用黑名单校验文件内容,以此禁止.php扩展名的文件,可以上传扩展名为.php\n的文件,其不会被黑名单拦截,但能被<FilesMatch>
匹配并交给application/x-http-php处理器进行php解析
检测
Apache的解析漏洞都需要两个条件:
- 存在文件上传功能点
- 文件上传以黑名单检测
检测时尝试上传三种文件名,查看是否进行了php解析:
- yuyoung.php.xyz
- yuyoung.php.jpeg
- yuyoung.php\n
防御
- 使用白名单扩展名检测
- 由于Apache大多数解析漏洞均是由于畸形扩展名、畸形文件名导致,所以可以对用户上传的文件重命名,避免畸形字符和多扩展名的情况
总结
解析漏洞是一类与web server相关的漏洞,所以往往与其版本和配置紧密联系,版本更新和打补丁往往是常用防御手段,修改配置进行防御需要谨慎,避免引发关联的漏洞,另外,不必要的解析扩展名(php3、php4等)也是值得注意的