上传漏洞
Mirror王宇阳
2019年10月28日
Web网站通常存在文件上传(例如:图片、文档、zip压缩文件^等)只要存在上传功能,就有可能会有上传漏洞的危机。和SQL注入漏洞相比较而言,上传漏洞更加危险,因为该漏洞可以直接上传一个WebShell到服务器上。
解析漏洞
利用上传漏洞,通常需要结合Web容器(IIS、Nginx、Apache、Tomcat)的解析漏洞来让上传的漏洞得到实现
IIS解析漏洞
-
目录名中含有.asp 字符串的(目录下)均按照asp文件进行解析;例如:index.asp/ 目录中的所有文件都会asp解析
当出现xx.asp 命名的文件名,访问目录下任意一个文件,均会送给asp.dll解析(执行asp脚本)
-
文件名中含有.asp; 字符,即使时jpg格式文件,IIS也会按照asp对文件进行解析
当文件名xx.asp;xx.jpg ,IIS6会将文件送给asp.dll解析(按照asp脚本解析);
请求时:IIS从左往右检查. 号,查询到; 或/ 号则(内存)截断;如此执行后,IIS认识的就是xx.asp
-
默认解析:.asa .cer .cdx IIS6 同时默认解析前面三个文件后缀,都会给asp.dll解析
-
修复方案:
设置权限,限制用户创建、修改文件夹权限
更新微软的补丁或者自定义修改IIS的检测规则,阻止上传非法的文件名后缀
IIS7.0/7.5
Nginx解析漏洞
Nginx <= 0.8.37
影响版本:0.5/0.6/<0.7.65/<0.8.37
Apache解析漏洞
-
Apache中存在一个上传的判断逻辑:(自定义)
<?php
if(isset($_FILES['file'])){
$name = basename($_POST['name']);
$ext = pathinfo($name,PATHINFO_EXTNSION);
if(in_array($ext,['php','php3','php4','php5','phtml','pht'])){
exit("bad file");
}
move_uploaded_file($_FILES['file']['tmp_name'],'./'.$name);
}
?>
判断检查上传文件的后缀名,如果发现了,就进行拦截。
利用CVE-2017-15715,上传一个包含换行符的文件。注意,只能是\x0A ,不能是\x0D\x0A ,所以我们用hex功能在1.php后面添加一个\x0A :

访问/1.php%0A ,即课成功getShell;
客户端校验
-
客户端使用JavaScript检查上传文件的后缀名
# js验证文件后缀
extArray = new Array('.gif','.jpg','.png'); // 白名单
function LimitAttach(form,file){
allowSubmit = false;
if(!file)
return;
while(file.indexOf('\\')!=-1)
file = file.slice(file.indexOf('\\')+1);
ext = file.slice(file.indexOf('.')).toLowerCase();
for(var i = 0 ; i < extArray.length ; i++){
if(extArray[i] == ext){
allowSubmit = true ;
break ;
}
}
if(allowSubmit)
form.submit();
else
alert("bad Extension");
}
一般情况可以通过抓包绕过客户端的 js校验
# php接收文件(没有任何校验)
<?php
if(isset($_POST['submit'])){
$name = $_FILES['file']['name']; //文件名
$naem = md5(date('Y-m-d h:m:s')).strrchr($name,'.');// 文件重命名保留扩展
$size = $_FILES['file']['size']; //文件字节大小
$tmp = $_FILES['file']['tmp_name']; //临时路径
move_uploaded_file($tmp,$name); //移动文件到tmp目录下
echo '文件上传成功'.$name;
}
?>
-
绕过客户端校验:
使用FireBug开发者工具,在本地构造一个可以越过触发校验函数即可提交表单的内容;让校验函数不被调用即可绕过。
另外也可以通过抓包方式在通过客户端校验后修改数据包的内容。(改包过程中可能会改动数据包的大小,需要留意Content-Length 定义的长度要与实际相符)
服务端校验
MIME校验:Content-type
-
Content-type 字段显示文件的MIME类型,判断MIME类型可以对文件做简单的过滤
# 校验Content-type字段MIME类型
<?php
if($_FILES['file']['type'] != 'image/jpeg'){ // 判断文件的MIME格式
echo "Sorry!文件上传格式错误 Error";
exit;
}
?>
-
绕过MIME校验:
利用Burp抓包工具,将content-type 字段改为需要的MIME类型
扩展名检测
-
黑名单策略:
存在一个专门的文件,记录服务器不允许上传的文件名
-
白名单策略:
存在一个专门的文件,记录服务器允许上传的文件名
# 扩展名检测
<?php
if(isset($_POST['submit'])){
$name = $_FILES['file']['name']; // 获取文件名
$ext = substr(strrchr($name,"."),1); //获取扩展名[strrchr()找到符号"."并返回从该位置到结尾的所有字符(字符串),substr(str,1)获得扩展名字符串]
while($ext==xxx){}
// 调用黑白名单进行循环对比,一旦命中则执行相关的放过/拦截操作!
}
?>
目录验证
-
让上传的文件存储在一个统一的目录
# 目录验证
<?php
if(isset($_POST['submit'])){
$name = $_FILES['file']['name']; //文件名
$naem = date('Y-m-d h:m:s').strrchr($name,'.');// 文件重命名保留扩展
$tmp = "./root/"; //存储路径,可以是服务器指定或者用户原则或则机制选择
move_uploaded_file($tmp,$name); //移动文件到tmp目录下
}
?>
服务器校验文件实例代码
<?php
if(isset($_POST['submit'])){
$name = $_FILES['file']['name'] ;
$type = $_FILES['file']['type'] ;
$tmp = "./image/";
}
file_array = new array('jpeg','png','jpg','gif');// 白名单
for ($i=0; $i < file_array.length; $i++) {
if (substr(strrchr($name, "."),1) == file_array[i]) {
if( $type == "image/gif" | $type == "image/jpeg" ){
move_uploaded_file($tmp, $name);
echo "图片上传成功……".$name;
exit;
}
}
}
?>
绕过策略
- burp抓包改包,绕过校验机制,再利用包含漏洞进行getShell
文本编辑器上传漏洞
常见文本编辑器:FCKEditor、Ewebeditor、UEditor、KindEditor、XHditor;合俗称“富文本编辑器”
笔者接触文本编辑器不多,贡献一个不错的参考文章: https://blog./jszy/stcs/91.html
|