文件上传简介

前言

文件上传漏洞易于理解,且一旦成功破坏性极大,所以平时中用的会比较多,但是相对地,技巧也很多。

常见检测手法

  • 前端使用JavaScript进行检测
  • Content-Type检测
  • 文件内容头检测
  • 扩展名检测
  • 黑白名单检测
  • 自己写的正则表达式检测
  • WAF辅助检测

前端使用JavaScript检测

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
function checkFile() {
var file = document.getElementsByName('upfile')[0].value;
if (file == null || file == "") {
alert("你还没有选择任何文件,不能上传!");
return false;
}
var allow_ext = ".jpg|.jpeg|.png|.gif|.bmp|";
var ext_name = file.substring(file.lastIndexOf("."));
if (allow_ext.indexOf(ext_name + "|") == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
</script>

绕过姿势:直接删除这段代码或者使用burp等工具抓包进行提交

Content-Type检测

也被称为服务端MIME类型检测,在服务器端常见的验证代码有:

1
2
3
4
5
6
7
8
9
<?php
if($_FILE['userfile']['type'] != "image/gif"){
echo "sorry,we only allow uploading GIF images";
exit;
}
else{
echo "Upload success!";
}
?>

绕过姿势:抓包工具直接修改即可。

文件内容头检测

首先先来看看各种文件类型的文件头十六进制的内容吧

JPG

1575354185190

PNG

1575354116028

GIF

1575353783714

BMP

1575353822779

更多文件头可详见维基百科,如果想要绕过只需要在前面加上这些特征符即可。

文件扩展名检测

比如只允许.jpg扩展名的文件上传,参考代码见下:

1
2
3
4
5
6
7
8
9
10
<?php
$type = array("jpg");
$fileext = fileext($_FILE['file']['name']);
if(!in_array($fileext,$type)){
echo "upload success!";
}
else{
echo "sorry,can't upload!";
}
?>

如果后台所用服务器为Apache,可以考虑上传一个.htaccess文件,该文件默认情况下是不存在于Apache中的,但是默认是启用的,所以我们可以通过上传这个文件来绕过上面的验证并且上传一个webshell,这个文件在实际中还是不要使用的好,一来是为了安全,二来是这东西性能也不好。

具体步骤:

新建一个文件取名为.htaccess,在其中写入:

1
AddType application/x-httpd-php .jpg

然后将其上传至服务器,如果成功,那么之后你上传的任何.jpg文件都会被当成PHP文件来执行。

其他的文件上传问题

除了上面的在实际中遇到最多的问题,还有一些其他的文件上传存在的问题,因为比较简单,所以统一放到了这里进行阐述。

  1. DoS攻击。因为文件上传会消耗服务器的带宽,所以只需要连续上传超大体积的文件,就会导致此问题的发生。当然防范这种问题也很容易,只需要修改php.ini文件中的相关属性即可。