I knew little about code audit before. Now I just wanna combine these knowledge with code audit examples. It may help me have a better understandings of code audit. :)

0x00 上传检测流程概述

0x01 客户端检测绕过(js检测)

<script type="text/javascript">
       function checkFile() {
            var file = document.getElementsByName('upfile')[0].value;
            if (file == null || file == "") {
                alert("你还没有选择任何文件,不能上传!");
                return false;
            }
            //定义允许上传的文件类型
            var allow_ext = ".jpg|.jpeg|.png|.gif|.bmp|";
            //提取上传文件的类型
            var ext_name = file.substring(file.lastIndexOf("."));
            //alert(ext_name);
            //alert(ext_name + "|");
            //判断上传文件类型是否允许上传
            if (allow_ext.indexOf(ext_name + "|") == -1) {
                var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" +     ext_name;
                alert(errMsg);
                return false;
            }
        }
</script>

绕过姿势:burp抓包修改后提交

0x02 服务端检测绕过

mime类型检测(content-type)

文件头content-type字段检验。MIME类型格式

<?php
if($_FILE['userfile']['type'] != "image/gif"){ //检测content-type
    echo "sorry,we only allow uploading GIF images";
    exit;
}
else
{
    echo "Upload success!";
}
?>

绕过姿势:burp抓包,改content-type的值为image/gif,即可

目录路径检测

上传的数据包中,如果存在path(或者其他名称)等能够操作上传路径的参数,修改该参数配合解析漏洞Get Webshell,测试代码
条件:php版本5.3.4以下;gpc关闭

<?php
error_reporting(0);

if(isset($_POST['upload']))
{
    $ext_arr = array('flv','swf','mp3','mp4','3gp','zip','rar','gif','jpg','png','bmp');
    $file_ext = substr($_FILES['file']['name'],strpos($_FILES['file']['name'],".")+1);
    if(in_array($file_ext,$ext_arr))
    {
        $tempFile = $_FILES['file']['tmp_name'];
        //这里的$_REQUEST['jieduan']造成可以利用截断上传
        $targePath = $_SERVER['DOCUMENT_ROOT'].$_REQUEST['jieduan'].rand(10,99).
            date('YmdHis').".".$file_ext;
        if(move_uploaded_file($tempFile,$targePath))
        {
            echo '上传成功'.'<br>';
            echo '路径'.$targePath;
        }
        else
        {
            echo("上传失败");
        }
    }
else
{
    echo("上传失败");
}
}
?>

文件拓展名检测

<?php
$type = array("php","php3");
//判断上传文件类型
$fileext = fileext($_FILE['file']['name']);
if(!in_array($fileext,$type)){
    echo "upload success!";
}
else{
    echo "sorry";
}
?>

上传后文件名没有发生改变,还时常可以结合目录路径攻击,比如filename="test.asp/evil.jpg" 之类
绕过姿势:

  • 配合Apache的.htaccess文件上传解析漏洞
    将下面代码保存成*.htaccess文件,由于该配置文件一般不在黑名单内,所以可以成功上传。此文件可以让.jpg的文件以.php格式解析,达到可执行的效果
AddType application/x-httpd-php .jpg
  • Apache站上的解析缺陷绕过上传漏洞
    Apache是从后面开始检查后缀名,按最后一个合法后缀执行,只需要将木马的后缀修改为允许上传的类型,即可成功绕过
  • IIS6.0站上的目录路径检测解析绕过上传漏洞
  • 文件名大小写绕过黑名单检测
  • 名单列表绕过
  • 特殊文件名绕过test.asp(windows)
  • 0X00截断

检测文件内容(配合文件包含)

这种情况,一般是做了过滤,只校验文件后缀名为asp/php/jsp的文件内容。
绕过姿势:先上传内容为木马的.txt文件,然后上传一个带有include()的正常php文件,即可绕过。

利用php特性(数组绕过)

file_put_contents 第二个参数可以是数组,而且正则匹配无法匹配数组,可以达到绕过的目的
file_put_contents()

检测文件头

不同的图片文件都有不同文件头,如:
PNG: 文件头标识 (8 bytes) 89 50 4E 47 0D 0A 1A 0A
JPEG: 文件头标识 (2 bytes): 0xff, 0xd8 (SOI) (JPEG 文件标识)
GIF: 文件头标识 (6 bytes) 47 49 46 38 39(37) 61
PHP使用getimagesize函数验证图片文件头
绕过姿势:可以选择用010editor改文件头,也可以在恶意脚本之前直接加文件头,如

GIF89a
<?php phpinfo(); ?>

上传到服务端后验证(竞争上传)

Web中的条件竞争漏洞

0x03 各种CMS的上传漏洞

0x04 各种(富)文本编辑器上传漏洞

0x05 各种Waf

0x06 总结

条件: 寻找一个上传点,查看上传点是否可用。
利用:
首先判断是程序员自己写的上传点,还是编辑器的上传功能
如果是编辑器上传功能,goolge当前编辑器的漏洞

如果是程序员写的上传点
上传一个正常的jpg图片 查看上传点是否可用
上传一个正常的jpg图片,burp拦截,修改后缀为php (可以检测前端验证 MIME检测 文件内容检测 后缀检测)
上传一个正常的jpg图片,burp拦截, 00截断 1.php%00.jpg
判断服务器是什么类型,web服务器程序,是什么类型,版本号多少
利用解析漏洞

0x07 防护建议

  • 使用白名单限制可以上传的文件扩展(白名单比黑名单可靠多了)
  • 验证文件内容,使用正则匹配恶意代码限制上传
  • 对上传后的文件统一随机命名,不允许用户控制扩展名
  • 修复服务器可能存在的解析漏洞
  • 严格限制可以修改服务器配置的文件上传如:.htaccess
  • 隐藏上传文件路径
  • 升级Web Server
  • 及时修复Web上传代码(重要)
  • 不能有本地文件包含漏洞
  • 注意0x00截断攻击
  • 上传文件的存储目录禁用执行权限

0x08 参考资料

着重推荐一个gayhub的项目 upload-labs
文件上传漏洞利用与防御(解析漏洞)
WEB文件上传漏洞总结
简单粗暴的文件上传漏洞
文件上传漏洞(绕过姿势)
关于上传中的00截断分析