网安基础学习之“文件上传漏洞原理与实现”
近期新闻头条上报出了“长沙市场监管局网站被上传了黄色页面”,经过长沙市公安局网技支队的排查,该门户网站后台编辑器存在**"文件上传漏洞"!**
![](https://i-blog.csdnimg.cn/blog_migrate/0e322835a0c3b8b3e6eb0500b12f5aae.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3660842e4cb2cb1ca3ebaa780a3911a1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1b98a7045ec04f7070618c0a1341eb78.png)
通过数据可以显示,文件上传漏洞,对网站的负面影响还是很大的,那么究竟"什么是文件上传漏洞?技术原理是什么?如何防范该漏洞?
今天小编我就以本篇文章内容给大家分享一下"文件上传漏洞的技术原理与实现,以及我们该如何防御该漏洞"。
一、 "文件上传漏洞"是什么
Web应用程序通常会有文件上传的功能, 例如在 BBS发布图片 , 在个人网站发布ZIP 压缩包, 在办公平台发布DOC文件等 , 只要 Web应用程序允许上传文件, 就有可能存在文件上传漏洞。
由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。这种攻击方式是最为直接和有效的,**"文件上传"本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。**如果服务器的处理逻辑做的不够安全,则会导致严重的后果。
二、 文件上传后导致的安全问题
上传的文件是web脚本语言,服务器的web容器解释并执行了文件上传的web脚本,导致了代码的执行。
上传文件是flash的策略文件,黑客可以通过控制flash在该域下的行为,来进行其他攻击。上传文件是病毒,木马文件,那攻击者可以诱使文件中其他的人员下载执行。
文件上传也有可能是钓鱼图片,或者包含了脚本文件的图片,在某些版本的浏览器中,这些脚本文件会被执行,可以用来做钓鱼攻击。
除此以外,还有一些不常见的利用方法,比如将一个文件作为一个入口,溢出服务器的后台处理程序,如图片解析模块,或者上传一个合法的文件,其内容包含了php的代码,再通过文件包含,来执行这个脚本。
三、造成文件上传漏洞的原因
(1)对于上传文件的后缀名(扩展名)没有做较为严格的限制
(2)对于上传文件的MIMETYPE 没有做检查
(3)权限上没有对于上传的文件的文件权限,(尤其是对于shebang类型的文件)
(4)对于web server对于上传文件或者指定目录的行为没有做限制
四、文件上传漏洞攻击方式
1.前端限制
function check(){
var filename=document.getElementById("file");
var str=filename.value.split(".");
var ext=str[str.length-1];
if(ext=='jpg'||ext=='png'||ext=='jpeg'||ext=='gif'){
return true;
}else{
alert("这不是图片!")
return false;
}
return false;
}
在表单中使用onsumbit=check()调用js函数来检查上传文件的扩展名。这种限制实际上没有任何用处,任何攻击者都可以轻而易举的破解。只能用于对于用户完全信任的情况下,很难称之为一种安全措施只能称之是一种防止用户误操作上传的措施。
原理:当用户在客户端选择文件点击上传的时候,客户端还没有向服务器发送任何消息,就对本地文件进行检测来判断是否是可以上传的类型,这种方式称为前台脚本检测扩展名。
绕过方法:
**1).**绕过前台脚本检测扩展名,就是将所要上传文件的扩展名更改为符合脚本检测规则的扩展名,通过BurpSuite工具,截取数据包,并将数据包中文件扩展名更改回原来的,达到绕过的目的。例如:文件名本来为【evil.jpg】,上传时,用BurpSuite截包后,将数据包中的名字改为【evil.php】(或其它脚本类型)即可。
**2).**如果是JS脚本检测,在本地浏览器客户端禁用JS即可。可使用火狐浏览器的NoScript插件、IE中禁用掉JS等方式实现。
2.检查扩展名
就是在文件被上传到服务端的时候,对于文件名的扩展名进行检查,如果不合法,则拒绝这次上传在检查扩展名是否合法的时候,有两种策略:
1).黑名单策略,文件扩展名在黑名单中的为不合法:
$postfix = end(explode('.','$_POST['filename']);
if($postfix=='php'||$postfix=='asp'||$postfix=='sh'){
echo "invalid file type";
return;
}
2).白名单策略,文件扩展名不在白名单中的均为不合法
$postfix = end(explode('.','$_POST['filename']);
if($postfix=='jpg'||$postfix=='png'||$postfix=='gif'){
//save the file and do something next
} else {
echo "invalid file type";
return;
}
白名单策略是更加安全的,通过限制上传类型为只有我们接受的类型,可以较好的保证安全,因为黑名单我们可以使用各种方法来进行注入和突破
原理:当浏览器将文件提交到服务器端的时候,服务器端会根据设定的黑白名单对浏览器提交上来的文件扩展名进行检测,如果上传的文件扩展名不符合黑白名单的限制,则不予上传,否则上传成功。
绕过方法:
在一些Web server中,存在解析漏洞
1).老版本的IIS6中的目录解析漏洞,如果网站目录中有一个 /.asp/目录,那么此目录下面的一切内容都会被当作asp脚本来解析
2).老板本的IIS6中的分号漏洞:IIS在解析文件名的时候可能将分号后面的内容丢弃,那么我们可以在上传的时候给后面加入分号内容来避免黑名单过滤,如 a.asp;jpg
3).旧版Windows Server中存在空格和dot漏洞类似于 a.php. 和 a.php[空格] 这样的文件名存储后会被windows去掉点和空格,从而使得加上这两个东西可以突破过滤,成功上传,并且被当作php代码来执行
4).nginx(0.5.x, 0.6.x, 0.7 <= 0.7.65, 0.8 <= 0.8.37)空字节漏洞 xxx.jpg%00.php 这样的文件名会被解析为php代码运行(fastcgi会把这个文件当php看,不受空字节影响,但是检查文件后缀的那个功能会把空字节后面的东西抛弃,所以识别为jpg)
5).apache1.x,2.x的解析漏洞,上传如a.php.rar a.php.gif 类型的文件名,可以避免对于php文件的过滤机制,但是由于apache在解析文件名的时候是从右向左读,如果遇到不能识别的扩展名则跳过,rar等扩展名是apache不能识别的,因此就会直接将类型识别为php,从而达到了注入php代码的目的。
3.检查HTTP Header中的Content-Type
原理:HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改,不过加上一层防护也是可以有一定效果的绕过方法使用各种各样的工具(如burpsuite)强行篡改Header就可以,将Content-Type: application/php改为其他web程序允许的类型Content-Type: image/jpgContent-Type: image/pngContent-Type: text/plain。
常用的MIMETYPE表
text/plain(纯文本)
text/html(HTML文档)
text/javascript(js代码)
application/xhtml+xml(XHTML文档)
image/gif(GIF图像)
image/jpeg(JPEG图像)
image/png(PNG图像)
video/mpeg(MPEG动画)
application/octet-stream(二进制数据)
application/pdf(PDF文档)
application/(编程语言) 该种语言的代码
application/msword(Microsoft Word文件)
message/rfc822(RFC 822形式)
multipart/alternative(HTML邮件的HTML形式和纯文本形式,相同内容使用不同形式表示)
application/x-www-form-urlencoded(POST方法提交的表单)
multipart/form-data(POST提交时伴随文件上传的表单)
4.分析文件头内容来检查文件类型
与方法2不同,还有一种检查类型的方式是使用对于文件内容的验证机制,这种方法利用的是每一个特定类型的文件都会有不太一样的开头或者标志位。
![](https://i-blog.csdnimg.cn/blog_migrate/53e5600794b48b5dc90eb5f103e66e0c.png)
在正常情况下,通过判断前10个字节,基本上就能判断出一个文件的真实类型。可以通过比如php的exif_imagetype()函数,一个通过这种方法来过滤的示例代码如下:
if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {
echo "File is not an image";
return;
}
也可以自己编写函数来进行识别,图片文件通常有称作幻数的头字节,我们来看一下几种图片文件的幻数:(注意!下面是二进制而不是文本格式的数据)
JPGFF D8 FF E0 00 10 4A 46 49 46
GIF47 49 46 38 39 61
(相当于文本的GIF89a)
PNG89 50 4E 47绕过方法给上传脚本加上相应的幻数头字节就可以,php引擎会将 <?之前的内容当作html文本,不解释而跳过之,后面的代码仍然能够得到执行比如下面:(一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符。)
GIF89a
如果是其他类型的二进制文件,也有响应的头字节,如下表
![](https://i-blog.csdnimg.cn/blog_migrate/a0a6387b2c5fc3ed61f7e693982c3e45.png)
5.限制Web Server对于特定类型文件的行为
导致文件上传漏洞的根本原因在于服务把用户上传的本应是数据的内容当作了代码,一般来说,用户上传的内容都会被存储到特定的一个文件夹下,比如我们很多人习惯于放在 ./upload/ 下面要防止数据被当作代码执行,我们可以限制web server对于特定文件夹的行为。
大多数服务端软件都可以支持用户对于特定类型文件的行为的自定义,以Apache为例:
在默认情况下,对与 .php文件Apache会当作代码来执行,对于 html,css,js文件,则会直接由HTTP Response交给客户端程序对于一些资源文件,比如txt,doc,rar等等,则也会以文件下载的方式传送的客户端。
我们希望用户上传的东西仅仅当作资源和数据而不能当作代码,因此可以使用服务器程序的接口来进行限制,以Apache为例,我们可以利用 .htaccess 文件机制来对web server行为进行限制禁止脚本执行有多种方式可以实现,而且分别有不同的效果:
1).指定特定扩展名的文件的处理方式,原理是指定Response的Content-Type可以加上如下几行AddType text/plain .pl .py .php这种情况下,以上几种脚本文件会被当作纯文本来显示出来,你也可以换成其他的Content-Type
2).如果要完全禁止特定扩展名的文件被访问,用下面的几行
Options -ExecCGI
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi识别
在这种情况下,以上几种类型的文件被访问的时候,会返回403 Forbidden的错误
3).也可以强制web服务器对于特定文件类型的处理,与第一条不同的是, 下面的方法直接强行让apache将文件识别为你指定的类型,而第一种是让浏览器
<FilesMatch ".(php|pl|py|jsp|asp|htm|shtml|sh|cgi)$">
ForceType text/plain
符合上面正则的全部被认为是纯文本,也可以继续往里面加入其他类型。
4).只允许访问特定类型的文件
<Files ^(.jpeg|.jpg|.png|.gif)>
order deny,allow
deny from all
在一个上传图片的文件夹下面,就可以加上这段代码,使得该文件夹里面只有图片扩展名的文件才可以被访问,其他类型都是拒绝访问。
这又是一个白名单的处理方案,永远记得,白名单是最有保障的安全措施绕过方法可以通过 move_uploaded_file 函数把自己写的.htaccess 文件上传,覆盖掉服务器上的文件,来定义文件类型和执行权限如果做到了这一点,将获得相当大的权限。
6.文件系统00截断
原理:在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束。利用00截断就是利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00上传截断漏洞。
绕过方法:通过抓包截断将【evil.php.jpg】后面的一个【.】换成【0x00】。在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束,从而将【evil.php.jpg】的内容写入到【evil.php】中,从而达到攻击的目的。
7.其它方式—绕过
原理:部分程序员的思维不严谨,并使用逻辑不完善的上传文件合法性检测手段,导致可以找到方式绕过其检测方式。
绕过方法:
1). 后缀名大小写绕过
用于只将小写的脚本后缀名(如php)过滤掉的场合;
例如:将Burpsuite截获的数据包中的文件名【evil.php】改为【evil.Php】
2). 双写后缀名绕过
用于只将文件后缀名过滤掉的场合,例如"php"字符串过滤的;
例如:上传时将Burpsuite截获的数据包中文件名【evil.php】改为【evil.pphphp】,那么过滤了第一个"php"字符串"后,开头的'p'和结尾的'hp'就组合又形成了【php】。
3). 特殊后缀名绕过
用于检测文件合法性的脚本有问题的场合;
例如:将Burpsuite截获的数据包中【evil.php】名字改为【evil.php6】,或加个空格改为【evil.php 】等。
五、文件上传漏洞实例分享
1.结合iis5.x/6.0解析漏洞上传文件
先上传一个asp文件,抓包看看返回结果是什么
![](https://i-blog.csdnimg.cn/blog_migrate/3be7feac1f927cafda3d2744d71f85ea.png)
![](https://i-blog.csdnimg.cn/blog_migrate/af7fcde29acf9ce26fc16259fdefaaf2.png)
由上图我们可以知道服务器是iis6.0,接下来我们利用iis6.0解析漏洞来上传我们的一句话,添加一个asp目录
![](https://i-blog.csdnimg.cn/blog_migrate/97a637982b353cb1bac7edf1acd8ea0b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/df57f29798a07e52efb5eedab0ed117d.png)
2.一句话木马图片
![](https://i-blog.csdnimg.cn/blog_migrate/11743cf5b5d1dd4bd03c6630ca5c32f5.png)
分析上图,先上传php文件,不允许,那么改下后缀名为png,还是不行,看来是对文件内容做了检查,做个图片马,上传
![](https://i-blog.csdnimg.cn/blog_migrate/3df4c5de2725e181480c263870663093.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4dce4ecc8d4a26a8af841afbf4698a8d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9e6f0cf2007814a82545f7f3645dd23e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1fefb497e54267788e53e958b8baaadb.png)
菜刀连接
![](https://i-blog.csdnimg.cn/blog_migrate/348e96c6f3e06627c54828d97f8f3edc.png)
3.绕过前端验证
先上传php文件
![](https://i-blog.csdnimg.cn/blog_migrate/005ae184aed9d9efc98bd55e00acdfe6.png)
从上图可以看到上传的时候弹出一个弹窗,只让我们上传上面格式的文件,那么我们把我们的文件名后缀改成png,上传抓包,在包里将我们的文件再改回php文件
![](https://i-blog.csdnimg.cn/blog_migrate/484b2415a64c2a5752789768b717addc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/483fff4d5285cf2f84007381ac162e9f.png)
上图显示我们上传成功,那么最后就是菜刀拿shell了
![](https://i-blog.csdnimg.cn/blog_migrate/a52953f4f7e3155b4f6a867975666f2f.png)
4.修改Content-Type绕过
上传一句话抓包
![](https://i-blog.csdnimg.cn/blog_migrate/7c9bea10f07ab901688dc6cca51037a3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/14634860050ef9746013625ccb59c394.png)
从上图可以指看到,Content-Type字段是application/octet-stream,来到Repeater,将Content-Type: application/octet-stream改成Content-Type: image/jpeg
![](https://i-blog.csdnimg.cn/blog_migrate/aaa0413361c34a11dd523b6591a62989.png)
成功上传,菜刀连接,getshell
![](https://i-blog.csdnimg.cn/blog_migrate/2f3c153d37c8573635c909f68364513e.png)
5.特殊的上传方式
没有任何可以上传的页面,但是页面显示的是有上传的地址的,所以扫描一下,或者可以猜一下路径
![](https://i-blog.csdnimg.cn/blog_migrate/0391448afc956362c613eae8cb011f00.png)
没有显示错误,说明这个目录下应该可以找到我们想要的的
![](https://i-blog.csdnimg.cn/blog_migrate/3814784249a4fa8922351356d35f9f22.png)
猜一下上传目录,一开始写的是upload.php,进入之后就直接跳转到upload1.php,并且提示无权访问,抓包看一下吧
![](https://i-blog.csdnimg.cn/blog_migrate/8772f5bffa7abf92669b8f2a776f5132.png)
下面就是无限的抓包重放,看返回包中有没有什么我们需要的东西
![](https://i-blog.csdnimg.cn/blog_migrate/83c3991606ef1d33edc3cf500141c964.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0416707fc5780ceba06138b9e2fad302.png)
下图这个返回包中我们可以看到upload.php下一跳应该是upload_file.php,但是由于权限问题,不能进去
![](https://i-blog.csdnimg.cn/blog_migrate/a3a1d7297adfefdd361f6c67776494e6.png)
但是,forward之后就出现了上传界面,神奇啊,那就上传一句话
![](https://i-blog.csdnimg.cn/blog_migrate/c7f8951f535b526a91d6af13a4a98ba3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/40081762213f1fe24eb4694ed924d629.png)
接下来只要知道绝对路径就可以上传我们的一句话了,这个cookie挺让我在意的,把它改成upload_file.php,go一下,返回包直接显示了上传路径,文件上传之后被重新命名了,命名规则也很简单:verify_当天日期_你上传的文件名,前面我们上传文件的时候,有个verify,它的值就在下面
![](https://i-blog.csdnimg.cn/blog_migrate/fe2d59cebc9fa9ef3076f38d751e3c09.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a3c4416b18c156c6b1cee192c7b538b6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/59ef12fdc9cb92b19f10c86d64599dfb.png)
成功getshell
![](https://i-blog.csdnimg.cn/blog_migrate/a3833a1c77d49ccc0b864bea0ff2484e.png)
六、文件上传漏洞防御防范
文件上传漏洞常见的几种防御方法:
**1.**文件上传的目录设置为不可执行只要web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响,因此这一点至关重要。
**2.**判断文件类型在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。
**3.**使用随机数改写文件名和文件路径文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。
**4.**单独设置文件服务器的域名由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含script的XSS利用等问题将得到解决。
最后
从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。
因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。
干货主要有:
①1000+CTF历届题库(主流和经典的应该都有了)
②CTF技术文档(最全中文版)
③项目源码(四五十个有趣且经典的练手项目及源码)
④ CTF大赛、web安全、渗透测试方面的视频(适合小白学习)
⑤ 网络安全学习路线图(告别不入流的学习)
⑥ CTF/渗透测试工具镜像文件大全
⑦ 2022密码学/隐身术/PWN技术手册大全