文件上传漏洞

目录

文件上传漏洞存在的原因

产生原因

漏洞危害

脚本及作用服务器类型

JS检查绕过原理及方法

案例

检查代码

绕过方式

浏览器删除过滤脚本

 BurpSuite抓包

 文件后缀绕过原理及方法

绕过方式1

案例

检查代码

 绕过方式2

案例

检查代码

绕过方法3

案例

检测代码对比

文件类型绕过原理及方法

绕过方式1

案例

检测代码

绕过方式2

案例

检测代码

绕过方法

文件截取绕过原理及方法

绕过方式

GET上传00截断

POST上传00截断

文件内容绕过原理及方法

检测原理

绕过方法


文件上传漏洞存在的原因

产生原因

上传文件时,如果未对上传的文件进行严格的验证和过滤,就容易造成文件上传漏洞,上传脚本文件(包括asp、aspx、php、jsp等)

漏洞危害

恶意上传行为可能导致网站甚至整个服务器被控制。恶意的脚本文件被称为WebShell,WebShell具有强大的功能,如查看服务器目录、服务器中文件、执行系统命令等。

脚本及作用服务器类型

asp、aspx:IIS

php:apache

jsp:tomcat

JS检查绕过原理及方法

案例

upload-labs Pass-01

检查代码

<script type="text/javascript">
    function checkFile() {
        var file = document.getElementsByName('upload_file')[0].value;//查询元素的 name 属性
        if (file == null || file == "") {
            alert("请选择要上传的文件!");
            return false;
        }
        //定义允许上传的文件类型
        var allow_ext = ".jpg|.png|.gif";
        //提取上传文件的类型;
        //substring截取字符串的某部分
        //lastIndexOf是从字符串末尾开始检索,检索到子字符,则返回子字符在字符串中的位置
        //截取最后一个.号后的字符串
        var ext_name = file.substring(file.lastIndexOf("."));
        //判断上传文件类型是否允许上传
        //indexOf搜索从指定字符位置开始,并检查指定数量的字符位置。
        //如果allow_ext不包含ext_name则执行if命令
        if (allow_ext.indexOf(ext_name) == -1) {
            var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
            alert(errMsg);
            return false;
        }
    }
</script>

绕过方式

浏览器删除过滤脚本

  • 查看源码并删除触发函数

 

  • 选择上传脚本

  • 上传

 BurpSuite抓包

  • 上传.png文件

 

  • BurpSuite抓包

 

  • 修改文件名

 

  • 查看文件是否上传成功

  • 登入大马

 文件后缀绕过原理及方法

绕过方式1

修改相似文件名

  • 例:php、php3、php5、phtml等
  • 条件:服务器可以解析该文件类型

打开配置文件 -- httpd-conf(PHPStudy配置文件解析)

Ctrl+F -- 搜索字符串:AddType -- 找到解析配置的内容位置

 添加我们需要的解析脚本后缀

案例

upload-labs Pass-03

选择上传文件

burpsuite抓包

修改包信息

将后缀名改为php5

上传脚本

通过BurpSuite重发器发送并获取重命名后的文件

验证大马是否上传成功

登入大马

检查代码

<code class="line-numbers language-php">$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']);//获取上传文件的name属性
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');//strrchr:查找字符在指定字符串中从右面开始的第一次出现的位置,如果成功,返回该字符以及其后面的字符,如果失败,则返回 NULL
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //trim:除去字符串开头和末尾的空格或其他字符

        if(!in_array($file_ext, $deny_ext)) {//in_array:检查数组中是否存在某个值
            $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 . '文件夹不存在,请手工创建!';
    }
}
</code>

 绕过方式2

结合Apache文件解析机制

  • Apache文件解析从右向左开始解析文件后缀,若后缀名不可识别,则继续判断直到遇到可解析的后缀为止。

案例

upload-labs Pass-04

选择上传文件

BurpSuite抓包

修改包信息并上传脚本

验证脚本

登入大马

检查代码

<li id="show_code">
    <h3>代码</h3>
<pre>
<code class="line-numbers language-php">$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, '.');//strrchr:查找字符在指定字符串中从右面开始的第一次出现的位置,如果成功,返回该字符以及其后面的字符,如果失败,则返回 NULL
        $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 . '文件夹不存在,请手工创建!';
    }
}
</code>
</pre>
</li>

绕过方法3

利用windows特性

  • 在程序开发部署的时候,没有考虑到系统的特性会导致限制被绕过。利用Windows特性,可以在后缀名后加“.”或者“::$DATA”绕过

案例

upload-labs Pass-07:通过文件名后缀加空格绕过

上传脚本并抓包

修改包信息并发送到服务器

验证脚本上传

因为在windows服务器中会自动去除空格。所以访问的是重命名后的.php文件,没有空格

upload-labs Pass-08:通过文件名加后缀名“.”绕过

上传脚本并抓包

修改包信息并发送到服务器中

验证脚本

因为在windows服务器中会自动去除.所以访问的是hack.php文件,没有“.”

upload-labs Pass-09:通过文件名后缀加::$DATA绕过

上传脚本并抓包

修改包信息并发送到服务器中

验证脚本

因为在windows服务器中会自动去除::$DATA。所以访问的是重命名后的.php文件,没有::$DATA

检测代码对比

//Pass-07验证代码:通过添加空格可以绕过原因是代码没有对首尾去空
$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
//Pass-08验证代码:通过添加空格可以绕过原因是代码没有对后缀名后面的"."进行删除
$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); //首尾去空
//Pass-09验证代码:通过添加空格可以绕过原因是代码没有对后缀名后面的"::$DATA"进行删除
$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); //首尾去空

文件类型绕过原理及方法

绕过方式1

MIME绕过

案例

upload-labs Pass-02

选择上传文件

burpsuite抓包

修改文件名和文件格式

上传

验证上传脚本

检测代码

//后台代码对上传的文件格式进行了设置,只允许服务器规定的文件格式上传。$_FILES["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.'文件夹不存在,请手工创建!';
    }
}

绕过方式2

文件头检测

案例

upload-lads Pass-14

上传脚本并抓包

将修改包信息发送到服务器

给脚本加上gif的头部值

验证脚本

http://xxx.xxx.xxx.xxx/upload-labs/include.php?file=upload/2320230224033250.gif访问图片马

检测代码

通过getReailFileType函数获取文件的文件头部值来识别文件类型

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
    $fileType = '';    
    switch($typeCode){      
        case 255216:            
            $fileType = 'jpg';
            break;
        case 13780:            
            $fileType = 'png';
            break;        
        case 7173:            
            $fileType = 'gif';
            break;
        default:            
            $fileType = 'unknown';
        }    
        return $fileType;
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_type = getReailFileType($temp_file);

    if($file_type == 'unknown'){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}

绕过方法

  • 在图片后添加脚本代码

  • 在脚本文件开头补充图片对应的头部值

jpg:FF D8 FF E0 00 10 4A 46 49 46

gif:47 49 46 38 39 61

png:89 50 4E 47

文件截取绕过原理及方法

绕过方式

00截断

检测原理

  1. 由于00表示结束符,PHP会把00后面的所有字符删除
  2. 配置条件
  • PHP版本 > 5.3.4

  • magic_quotes_gpc(魔术引号)为OFF状态

绕过条件

  1. 用户文件被重命名了
  2. 文件上传路径是用户可控的

GET上传00截断

案例

upload-labs Pass-12

上传脚本并抓包

修改包信息并发送到服务器中

验证脚本

页面存在没有显示,通过查看靶机upload目录可以查看

检测代码

//从代码中可以发现红线处,对上传的文件名进行重新拼接,使用$_GET传参
//可以通过%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类型文件!";
    }
}

POST上传00截断

案例

upload-labs Pass-13

上传脚本并抓包

修改包信息并发送到服务器中

  1. 修改文件名后缀确保符合白名单,然后在上传路径/upload后添加文件2.php以做00截断

  1. 进入Hex中找到之前修改的.php后修改为00

修改前

修改后

上传脚本成功

脚本验证

文件内容绕过原理及方法

检测原理

一些网站文件检测逻辑是先允许上传任意文件,然后检查文件内容是否包含可执行脚本,如果包含则删除。

绕过方法

利用成功上传到删除文件的时间差,上传一个.php文件,在未删除之前立即访问,则会自动生成一个新的php文件,新文件不会被删除

<?php
    fputs(fopen('./1.php','w'),'<?php phpinfo();?>');
?>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值