1. 前端:
JS检测绕过:
前端网页JS对文件格式进行验证:
<script type="text/javascript">
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
//获取到文件名
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
var allow_ext = ".jpg|.png|.gif";
//定义允许上传的文件类型
var ext_name = file.substring(file.lastIndexOf("."));
//提取上传文件的类型。
//通过lastIndexOf取到“.”的索引,再使用substring函数截取 .后缀名
if (allow_ext.indexOf(ext_name) == -1) {
//如果 allow_ext 中没有 ext_name字符串,则返回-1
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
//判断上传文件类型是否允许上传
}
</script>
绕过方法:
1.抓包将原“合法”文件后缀名改回 php再forward就可以上传WebShell到服务器。
2.禁用浏览器JS脚本(浏览器插件)。
后端验证:
1.服务端MIME绕过:
相关概念:Content-Type,即互联网媒体类型,也叫做MIME类型。在互联网中有成百上千中不同的数据类型,HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签,用于区分数据类型。
在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。
常见的content-type有:
- HTML文档标记:text/html;
- 普通ASCII文档标记:text/html;
- JPEG图片标记:image/jpeg;
- GIF图片标记:image/gif;
- js文档标记:application/javascript;
- xml文件标记:application/xml;
burp抓包,将报文中的Content-Type改成允许的类型即可
2.文件头绕过:
相关概念:文件均有一个特殊的、可识别的文件头(又称文件幻数)。图片格式往往不是根据文件后缀名去做判断的。文件头是文件开头的一段二进制,不同的图片类型有不同的文件头。
常见的文件头:
JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
XML (xml),文件头:3C3F786D6C
HTML (html),文件头:68746D6C3E
绕过方法:
在脚本文件开头补充图片对应的头部值,或在图片后写入脚本代码。
3.服务器扩展名黑名单绕过:
1.大小写绕过:
服务端没有对后缀名转化为统一格式进行对比,导致可以上传后缀为pHp的文件,又因为windows对大小写不敏感,所以.pHp扔回被当成PHP文件解析。
2.Apache文件解析漏洞:
2.1黑名单不允许上传.asp,.aspx,.php,.jsp
后缀的文件,apache的httpd.conf中如果配置如下代码,就可以上传.phtml .phps .php5 .pht文件。
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
2.2 .htaccess这个文件作为一个配置文件,可以用来控制所在目录的访问权限以及解析设置。如下,所有的jpg后缀会被当做php执行。
- AddType application/x-httpd-php.jpg
4.服务器白名单绕过:
绕过方法:文件截断
00截断利用的是php的一个漏洞。在 php<5.3.4>版本中,存储文件时处理文件名的函数认为0x00是终止符。于是在存储文件的时候,当函数读到 0x00(%00) 时,会认为文件已经结束。
比如,当我们上传一个1.php%00.jpg 的文件时,前端检测的后缀名检查结果为jpg,可以绕过前端的检测;后端判断文件名后缀的函数会认为其是一个.jpg格式的文件;但是保存的时候,处理文件名的函数在遇到%00字符认为这是终止符,于是1.php%00.jpg文件被保存为1.php储存在服务器里。