每个程序员都应该警惕的文件上传漏洞!!

每个程序员都应该警惕的文件上传漏洞!!

2019年09月13日 07:30:00 菜V菜 阅读数 4241

Hack:专注于网络安全攻防黑客技术的研究及思考,带领新手走进黑客世界的大门。

 

 

文件上传漏洞是指网络攻击者上传了一个可执行的文件到服务器并执行。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。

网站上传文件并且存储的过程:

假如某网站有一个允许用户上传图片的功能,用户上传的图片最终会被存储到 /upload/ 目录下,并且以上传文件时的时间日期命名,上传文件的后缀为后缀。小明这时上传了一个1.jpg的文件,当服务器收到用户上传的数据时,会在 /upload/ 目录下新建一个以当前时间日期命名的文件,后缀为.jpg 。然后将接收到的用户上传的1.jpg图片里的数据写入到新建的文件里面。

漏洞成因:

由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致用户可以越过其本身权限向服务器上传可执行的动态脚本文件。打个比方来说,如果你使用 php 作为服务器端的动态网站环境,那么在你的网站的上传功能处,就一定不能让用户上传 php 类型的文件,否则他上传一个一句话木马,你服务器上的文件就可以被他任意更改了。因此文件上传漏洞带来的危害常常是毁灭性的,Apache、Tomcat、Nginx等都曝出过文件上传漏洞。

一般我们会利用文件上传漏洞上传一句话木马,然后用菜刀连接获取 webshell。但是这里有两个问题:

  • 第一你的文件能上传到web服务器

  • 第二你的文件能被当成脚本文件执行,所以要想让上传文件被当成脚本执行,我们经常会和文件包含漏洞和文件解析漏洞一起利用

 

  •  

服务器上传文件命名规则:

 

  • 第一种:上传文件名和服务器命名一致

  • 第二种:上传文件名和服务器命名不一致(随机,时间日期命名等)

 

服务器对上传文件的过滤

  1. 前端脚本检测文件扩展名。当客户端选择文件点击上传的时候,客户端还没有向服务器发送任何消息,前端的 js 脚本就对文件的扩展名进行检测来判断是否是可以上传的类型


 
  1. #前端脚本检测,只允许上传 .jpg格式的文件

  2. <script type="text/javascript">

  3. function selectFile(fnUpload) {

  4. var filename = fnUpload.value;

  5. var mime = filename.toLowerCase().substr(filename.lastIndexOf("."));

  6. if(mime!=".jpg")

  7. {

  8. alert("请选择jpg格式的照片上传");

  9. fnUpload.outerHTML=fnUpload.outerHTML;

  10. }

  11. }

  12. </script>

2.后端脚本检测文件扩展名,数据提交到后端,后端的函数对上传文件的后缀名进行检测,比如黑名单检测不允许上传 .php 、.asp 后缀格式的文件;白名单检测只允许上传 .jpg 格式的文件


 
  1. #后端php检测

  2. $info=pathinfo($_FILES["file"]["name"]);

  3. $ext=$info['extension'];// 得到文件扩展名

  4. if (strtolower($ext) == "php") { #黑名单检测,不允许上传php格式的文件

  5. exit("不允许的后缀名");

  6. }

3.后端通过对上传文件的 Content-Type 类型进行黑白名单检测过滤


 
  1. #后端对上传文件的 Content-Type类型进行检测,只允许上传 image/gif、image/jpeg、image/pjpeg格式的文件

  2. if (($_FILES["file"]["type"] != "image/gif") && ($_FILES["file"]["type"] != "image/jpeg")

  3. && ($_FILES["file"]["type"] != "image/pjpeg")){

  4. exit($_FILES["file"]["type"]);

  5. exit("不允许的格式");

4.通过函数比如 getimagesize()  函数检测你上传的图片的大小是否是正常的图片大小,防止上传一句话木马。通过分析图片头部来判断这个是不是一个有效的图片格式,比如 jpg 格式图片头部是 JFIF ,gif头部是GIF89a,png头部是%PNG


 
  1. #后端检测上传的文件是否是正常大小的图片

  2. if(!getimagesize($_FILES["file"]["tmp_name"])){

  3. exit("不允许的文件");

  4. }

注意:在生产环境中的过滤,往往是这些方法都会结合的,而不只是单单的某一个过滤方法。生产环境中的过滤是很严格的

上传文件过滤的绕过

  • 对于第一种前端脚本检测过滤,上传的时候上传 jpg 后缀的文件,然后用butpsuite进行抓包修改为.php的即可绕过。

  • 对于第二种后端过滤,如果是后端黑名单过滤的话,我们可以想尽任何办法绕过黑名单进行上传。比如如果目标服务器是windows系统的话,我们可以利用windows系统的解析漏洞,用burpsuite抓包,将文件名后缀改为 .php. 或者 .php ,因为在windows系统内是不允许文件以 . 或者空格结尾的。所以在绕过上传之后windows系统会自动去掉 点和空格。所以,该文件最终还是会被解析成 .php 。或者还可以将php三个字母变换大小写,因为在windows系统里面是不区分大小写的。如果是白名单检测的话,我们可以采用00截断绕过。00截断利用的是php的一个漏洞。在 php<5.3.4 版本中,存储文件时处理文件名的函数认为0x00是终止符。于是在存储文件的时候,当函数读到 0x00(%00) 时,会认为文件已经结束。

        例如:我们上传 1.php%00.jpg 时,首先后缀名是合法的jpg格式,可以绕过前端的检测。上传到后端后,后端判断文件名后缀的函数会认为其是一个.jpg格式的文件,可以躲过白名单检测。但是在保存文件时,保存文件时处理文件名的函数在遇到%00字符认为这是终止符,于是丢弃后面的 .jpg,于是我们上传的 1.php%00.jpg 文件最终会被写入 1.php 文件中并存储在服务端。

  • 对于第三种过滤,可以使用burpsuite进行抓包修改 Content-Type 类型

  • 对于第四种过滤,可以将一句话木马写入到正常的图片中:copy  /b  1.jpg+1.php  2.jpg 。然后在利用burpsuite修改后缀为 .php ,或者利用文件包含漏洞或者文件解析漏洞,将其解析成 php脚本即可

  • 还有其他的过滤,比如多文件上传时,有时服务器只对第一个上传的文件进行了检查,这时通过上传多个文件并将恶意文件掺杂进其中也可绕过服务器的过滤。

00截断实验:http://ctf5.shiyanbar.com/web/upload/

这个实验对用户上传文件是这样处理的,首先会对用户上传文件的后缀名进行检测,只能上传 jpg/gif/png 格式的文件,然后会对上传后的文件路径进行判断,如果是以 php 为后缀的就会返回flag,如果是以 jpg/gif/png 为后缀就会显示存储路径为固定的:./uploads/8a9e5f6a7a789acb.php

文件上传的防御

  1. 客户端检测,使用 js 对上传图片检测,包括文件大小、文件扩展名、文件类型等

  2. 服务端检测,对文件大小、文件路径、文件扩展名、文件类型、文件内容检测、对文件重命名等

  3. 其他限制,如服务器端上传目录设置不可执行权限

  4. 检查网站有没有文件解析漏洞和文件包含漏洞

posted @ 2019-09-18 19:41  grj001  阅读(202)  评论(0编辑  收藏  举报