文件上传之后端黑白名单绕过

文件上传常见验证

1. 后缀名

  • 黑名单:后端代码中明确不让上传的文件后缀名。
    比如:asp、php、jsp、aspx、cgi、war等
  • 白名单:后端代码中明确可以上传文件的类型
    比如:jpg、png、zip、rar、gif····

php5、phtml等格式未出现在黑名单中可以绕过,此类型与搭建平台的设置有关。

2. 文件类型

文件类型在http头信息中又称MIME信息。
具体表现在http头中的content-type信息中。

3. 文件头信息

文件头是位于文件开头的一段承担一定任务的数据,一般都在开头的部分。
常见文件的文件头:
JPEG (jpg), 文件头:FFD8FF
PNG (png),  文件头:89504E47 文件尾:0000000049454E44AE426082
GIF (gif), 文件头:47494638
ZIP Archive (zip), 文件头:504B0304 文件尾:00000000
TIFF (tif), 文件头:49492A00
Windows Bitmap (bmp),   文件头:424D
CAD (dwg), 文件头:41433130
Adobe Photoshop (psd), 文件头:38425053
Rich Text Format (rtf), 文件头:7B5C727466
XML (xml), 文件头:3C3F786D6C
HTML (html), 文件头:68746D6C3E
Email [thorough only] (eml), 文件头:44656C69766572792D646174653A
Outlook Express (dbx), 文件头:CFAD12FEC5FD746F
Outlook (pst), 文件头:2142444E
MS Word/Excel (xls.or.doc), 文件头:D0CF11E0
MS Access (mdb), 文件头:5374616E64617264204A
WordPerfect (wpd), 文件头:FF575043
Adobe Acrobat (pdf), 文件头:255044462D312E
Quicken (qdf), 文件头:AC9EBD8F
Windows Password (pwl), 文件头:E3828596
RAR Archive (rar), 文件头:52617221
Wave (wav), 文件头:57415645
AVI (avi), 文件头:41564920
Real Audio (ram), 文件头:2E7261FD
Real Media (rm), 文件头:2E524D46
MPEG (mpg), 文件头:000001BA
MPEG (mpg), 文件头:000001B3
Quicktime (mov), 文件头:6D6F6F76
Windows Media (asf), 文件头:3026B2758E66CF11
MIDI (mid), 文件头:4D546864


相关靶场分析

1. upload-labs第2关(MIME绕过)

查看源码:

$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.‘文件夹不存在,请手工创建!‘;
    }
}

通过代码分析,此关是判断上传的文件类型是否在白名单中,在就上传,否则上传失败。
绕过方法为修改上传文件类型为白名单中的任意一个即可。
文件上传之后端黑白名单绕过

2. upload-labs第3关(特殊解析后缀绕过)

查看源码:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(‘.asp‘,‘.aspx‘,‘.php‘,‘.jsp‘);//拒绝的后缀名
        $file_name = trim($_FILES[‘upload_file‘][‘name‘]);//去除接收过来的文件名中的空格
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, ‘.‘);//将“.”前面的内容截断
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if(!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.date("YmdHis").rand(1000,9999).$file_ext;            
            if (move_uploaded_file($temp_file,$img_path)) {
                 $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘不允许上传.asp,.aspx,.php,.jsp后缀文件!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

过滤条件为:

  • 过滤后缀名asp,aspx,php,jsp
  • 去除接收过来的文件名中的空格
  • 删除文件名末尾的点
  • 将“.”前面的内容截断
  • 后缀名转换为小写
  • 去除文件后缀含有::$DATA字符串变为空
  • 收尾去掉空格
    绕过方法为:使用特殊的后缀名,php5,phml等
    原因是apache服务器可以解析php5、php3、phtml格式的文件为php格式的文件。
    文件上传之后端黑白名单绕过

3. upload-labs第4关(.htaccess上传漏洞)

源码分析:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".pHp1",".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",".ini");
        $file_name = trim($_FILES[‘upload_file‘][‘name‘]);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, ‘.‘);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘此文件不允许上传!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

可以看到限制上传的文件后缀名增多。
我们在本地创建.htaccess文件,
文件上传之后端黑白名单绕过
先将此文件上传至服务器。目的是在.htaccess文件所在的目录中所有格式文件按.htaccess文件规定的方式执行。
再上传一个名为shana.jpg的马即可。
访问http://127.0.0.1/upload-labs/upload/shana.jpg
文件上传之后端黑白名单绕过

4. upload-labs第5关(只进一次过滤检验)

源码分析:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $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($_FILES[‘upload_file‘][‘name‘]);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, ‘.‘);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘此文件类型不允许上传!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

可知,过滤掉更多后缀名,且将.htaccess也过滤掉了。
只进行了一次过滤检验,可以使用".php. ."绕过
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

5. upload-labs第6关(大小写绕过)

源码:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $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",".ini");
        $file_name = trim($_FILES[‘upload_file‘][‘name‘]);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, ‘.‘);
        $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空

        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘此文件类型不允许上传!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

源码中没有大小写过滤。
上传".PHp"可绕过
文件上传之后端黑白名单绕过

6. upload-labs第7关(后缀名末尾加空格绕过)

源码;

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $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",".ini");
        $file_name = $_FILES[‘upload_file‘][‘name‘];
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, ‘.‘);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file,$img_path)) {
                $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘此文件不允许上传‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

源码中没有删除后缀名末尾空格,可增加空格进行绕过。
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

7. upload-labs第8关(后缀名加点绕过)

源码:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $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",".ini");
        $file_name = trim($_FILES[‘upload_file‘][‘name‘]);
        $file_ext = strrchr($file_name, ‘.‘);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘此文件类型不允许上传!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

分析得缺少删除末尾的点的操作。
抓包加点进行过滤。
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

8. upload-labs第9关(::$DATA绕过)

源码:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $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",".ini");
        $file_name = trim($_FILES[‘upload_file‘][‘name‘]);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, ‘.‘);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
            $img_path = UPLOAD_PATH.‘/‘.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = ‘上传出错!‘;
            }
        } else {
            $msg = ‘此文件类型不允许上传!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

分析得,少了去除文件名中的::$DATA字符串。
后缀名加::$DATA即可绕过。
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

9. upload-labs第10关(一次验证绕过)

方法同第5关
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

10. upload-labs第11关(后缀名重写绕过)

源码:

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit‘])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini");

        $file_name = trim($_FILES[‘upload_file‘][‘name‘]);
        $file_name = str_ireplace($deny_ext,"", $file_name);
        $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
        $img_path = UPLOAD_PATH.‘/‘.$file_name;        
        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = ‘上传出错!‘;
        }
    } else {
        $msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
    }
}

分析得,若上传是黑名单中的后缀则删除后缀名。
只需复写后缀名即可绕过。
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

11. upload-labs第12关(%00截断)

$is_upload = false;
$msg = null;
if(isset($_POST[‘submit‘])){
    $ext_arr = array(‘jpg‘,‘png‘,‘gif‘);
    $file_ext = substr($_FILES[‘upload_file‘][‘name‘],strrpos($_FILES[‘upload_file‘][‘name‘],".")+1);
    if(in_array($file_ext,$ext_arr)){
        $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘];
        $img_path = $_GET[‘save_path‘]."/".rand(10, 99).date("YmdHis").".".$file_ext;

        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = ‘上传出错!‘;
        }
    } else{
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
    }
}

分析是取最后一个点后面的格式与白名单进行对比。
使用get传参,可用%00截断。绕过
文件上传之后端黑白名单绕过
文件上传之后端黑白名单绕过

文件上传之后端黑白名单绕过

上一篇:《手写PHP编译器》之实现echo_expr


下一篇:.NetCore中Elasticsearch组件NEST的使用