目录
一、漏洞简介
二、上传的原理或本质
2.1 文件上传的本质
2.2 文件上传的过程及代码演示
三、文件上传常见触发点
四、文件上传常见检测方式
4.1 前端js检测
4.2 content-type (MIME)检测
4.3 黑名单检测
4.4 文件头检测
4.5 .htaccess文件解析漏洞
4.6 图片二次渲染上传
4.7 文件上传条件竞争漏洞
4.8 一些其他的方式
4.9 比较通用检测方法
五、文件上传防御方法
六、一些扩展
一、漏洞简介
文件上传的问题主要是由于程序员对用户文件上传部分的控制不足或者处理缺陷,从而导致用户可以越过其本身权限向服务器上传可执行的动态脚本文件了。这里是上传的问题包含但不限于木马、病毒、恶意脚本或者webshell等。文件上传的功能本身是没有问题的,有问题的是文件上传后,服务器怎么处理、解释文件。
二、上传的原理或本质
2.1 文件上传的本质
文件上传归根结底来自客户端的请求POST或者PUT请求,消息主体就是一些上传信息。比如上传页面指定的enctype为multipart/form-data或者 multipart/form-data
<form action='' enctype='multipart/form-data' method='POST'>
<input type='file' name='file'>
</form>
multipart 格式的数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域。在一般的表单输入域中,它所对应的部分中会放置文本型数据,但是如果上传文件的话,它所对应的部分可以是二进制,下面展现 multipart 的请求体:
ilename 字段是必要的,指定了上传时的那个文件的文件名。其他的可有可无
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
这里在每个字段之间使用 ———WebKitFormBoundaryxxx 隔开,boundary是一个字符串,用来切分数据。
这里就和 post 请求一样,可以自己增加参数,就形如下面这样,将参数名放到 name 里,参数值放到下面:
------WebKitFormBoundary1PkqXeou9aUAIMHr
Content-Disposition: form-data; name="filename"
1.php
2.2 文件上传的过程及代码演示
1、文件上传 的过程
- 客户端
选择发送的文件--》服务器接收--》网站程序判断--》临时文件--》移动到指定的路径
- 服务端
处理上传的文件--保存指定路径
2、部分代码
- 服务器接收资源代码
<?php
if($_FILES["file"]["error"] > 0){
echo "Error:".$FILES["file"]["error"]."<br/>";
}else {
echo "Upload:".$_FILES["file"]["name"]."<br/>";
echo "Type:".$_FILES["file"]["type"]."<br/>";
echo "Size:".($_FILES["file"]["size"]/1024)."Kb<br/>";
echo "Stored in:".$_FILES["file"]["tmp_name"];
}
?>
- 客户端文件上传的代码
<html>
<head>test</head>
<body>
<form action="upload.php" method="POST" encrype="multipart/form-data">
<label for="file">Filename:</lable>
<input type="file" name="file" id="file"/>
<br/>
</form>
</body>
</html>
文件上传时会返回一些代码 返回客户端 客户端根据这些值判断上传是否正常
- 值:0; 没有错误发生,文件上传成功。
- 值:1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
- 值:2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
- 值:3; 文件只有部分被上传。
- 值:4; 没有文件被上传。
三、文件上传常见触发点
存在文件上传功能的地方都有可能存在文件上传漏洞,比如相册、头像上传,视频、照片分享。论坛发帖和邮箱等可以上传附件的地方也是上传漏阔的高危地带,另外像文件管理器这样的功能也有可能被攻击者所利用。
- 相册、头像上传
- 视频、照片共享
- 附件上传
- 文件管理器
- 系统升级处
- 系统备份还原处
四、文件上传常见检测方式
上传代码分析
从代码处可知,直接获取文件名,把上传的临时文件移动到hackable/uploads/ 目录下
<?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>";
}
}
?>
直接上传文件,网页会返回路径 访问url即可getshell
这里用phpinfo函数测试,访问上传的文件
4.1 前端js检测
1、原理
在文件上传时,用户选择文件时,或者提交时,有些网站会对前端文件名进行验证,一般检测后缀名,是否为上传的格式。如果上传的格式不对,则弹出提示文字。此时数据包并没有提交到服务器,只是在客户端通过js 文件进行校验,验证不通过则不会提交到服务器进行处理。
2、绕过js检测方法
- 按 F12 使用网页审计元素,把校验的上传文件后缀名文件删除,即可上传。
直接删除代码中onsubmit事件中关于文件上传时验证上传文件的相关代码即可:
或者可以不加载所有js,还可以将html源码copy一份到本地,然后对相应代码进行修改,本地提交即可
- 把恶意文件改成 js 允许上传的文件后缀,如 jpg、gif、png 等,再通过抓包工具抓取 post 的数据包,把后缀名改成可执行的脚本后缀如php 、asp、jsp、net 等。即可绕过上传。 删除 js 文件
抓包修改后缀名
3、检测代码分析
客户段 html 上传文件时会调用 checkFile 函数,首先获取文件后缀名。如果文件为空,则弹出“请选择要上传的文件”,如果文件不为空,获取上传的文件后缀名不 .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 errMg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
4.2 content-type (MIME)检测
1、原理
有些上传模块,会对 http 的类型头进行检测,如果是图片类型,允许上传文件到服务器,否则返回上传失败。因为服务端是通过content-type 判断类型,content-type 在客户端可被修改。则此文件上传也有可能被绕过的风险。
2、绕过检测方法
- burp抓包修改请求请求包中的content-type类型为支持的的类型
text/plain
(纯文本)
text/html
(HTML文档)
text/javascript
(js代码)
application/xhtml+xml
(XHTML文档)
image/gif
(GIF图像)
image/jpeg
(JPEG图像)
image/png
(PNG图像)
video/mpeg
(MPEG动画)
application/octet-stream
(二进制数据)
application/pdf
(PDF文档)
HTTP content-type | 菜鸟教程
3、检测代码分析
<?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' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// 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>";
}
}
else {
// Invalid file
$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
在上述代码中,会检测文件类型是否是“image/jpeg" 或者 ”image/png",同时文件大小小于100000,即允许上传。
故绕过只要抓包修改content-type即可
4.3 黑名单检测
1、原理
上传模块,有时候会写成黑名单限制,在上传文件的时获取后缀名,再把后缀名与程序中黑名单进行检测,如果后缀名在黑名单的列表内,文件将禁止文件上传。
2、绕过方式
- 上传黑名单的外的文件后缀即可(主要在于黑名单是否够全)
在 iis 里 asp 禁止上传了,可以上传 asa cer cdx 这些后缀,如在网站里允许.net 执行 可以上传 ashx 代替 aspx。如果网站可以执行这些脚本,通过上传后门即可获取 webshell。
在不同的中间件中有特殊的情况,如果在 apache 可以开启application/x-httpd-php在 AddType application/x-httpd-php .php .phtml .php3 后缀名为 phtml 、php3 均被解析成 php 有的 apache 版本默认就会开启。
上传目标中间件可支持的环境的语言脚本即可,如.phtml、php3。
3、检测代码分析
首先是检测 submit 是否有值,获取文件的后缀名,进行黑名单对比,后缀名不在黑名单内,允许上传。
$if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = arry('.asp','.aspx','.php','.jsp'); #黑名单列表
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name); //删除文件末尾的点
$file_ext = strrchr($file_name,'.'); //文件名中最后出现. 的位置
$fiel_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.'/'.data("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. "文件夹不存在,请手工创建";
....
PS:上述代码中存在对文件小写的转化,以及去除首尾空字符和对文件末尾”."删除以及::DATA字符的检测,如果没有这些,那么就可以有新的绕过方式,比如大写绕过,以及空格绕过、windows系统特性绕过、NTFS交换数据流::$DATA绕过。
1、windows系统特性
在 windows 中文件后缀名. 系统会自动忽略.所以 shell.php. 像shell.php 的效果一样。所以可以在文件名后面机上.绕过。
2、
4.4 文件头检测
1、原理
有的文件上传,上传时候会检测头文件,不同的文件,头文件也不尽相同。常见的文件上传图片头检测 它检测图片是两个字节的长度,如果不是图片的格式,会禁止上传。 常见的文件头
- JPEG (jpg),文件头:FFD8FF
- PNG (png),文件头:89504E47
- GIF (gif),文件头:47494638
- TIFF (tif),文件头:49492A00
- Windows Bitmap (bmp),文件头:424D
128个常见的文件头信息对照表_常见文件头_致守的博客-CSDN博客
2、文件头绕过(如果是图片码要配合文件包含)
- 制作图片一句话,使用 copy 1.gif/b+moon.php shell.php 将php 文件附加再jpg图片上,直接上传即可
copy a.png /b + a.php /a 3.php
/b:指定以二进制格式复制、合并文件,用于图像或者声音类文件
/a:指定以ascii格式复制、合并文件用于txt等文本类文件
注:这条命令的意思是:通过copy命令,把a.png图片文件,以二进制文件形式添加到a.php文件中,以ASCII文本文件形式输出为3.php文件。
3、文件头检测代码分析
这个是存在文件头检测的上传,getReailFileType 是检测jpg、png、gif 的文件头
如果上传的文件符合数字即可通过检测。
4.5 .htaccess文件解析漏洞
1、原理
.htaccess文件(或者"分布式配置文件")
,全称是Hypertext Access(超文本入口)
。提供了针对目录改变配置的方法,即,在一个特定的文档目录中放置一个包含一个或多个指令的文件,以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
PS: web具体应用没有禁止.htaccess文件的上传,同时web服务器提供商允许用户上传自定义的
.htaccess文件
。
2、利用方式
上传覆盖.htaccess文件
,重写解析规则
,将上传的带有脚本马的图片以脚本方式解析。
ps:
<FilesMatch "evil.gif">
SetHandler application/x-httpd-php #在当前目录下,如果匹配到evil.gif文件,则被解析成PHP代码执行
AddHandler php5-script .gif #在当前目录下,如果匹配到evil.gif文件,则被解析成PHP代码执行
</FilesMatch>
3、代码检测分析
在 htaccess 里写入 SetHandler application/x-httpd-php 则可以文件重写成php文件。要 htaccess 的规则生效 则需要在 apache 开启 rewrite 重写模块,因为apache 是多数都开启这个模块,所以规则一般都生效。
4.6 图片二次渲染上传
1、原理
有些图片上传,会对上传的图片进行二次渲染后在保存,体积可能会更小,图片会模糊一些,但是符合网站的需求。例如新闻图片封面等可能需要二次渲染,因为原图片占用的体积更大。访问的人数太多时候会占用,很大带宽。二次渲染后的图片内容会减少,如果里面包含后门代码,可能会被省略。导致上传的图片马,恶意代码被清除。
2、利用方式
- 配合文件包含漏洞: 将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获取webshell。
- 可以配合条件竞争: 这里二次渲染的逻辑存在漏洞,先将文件上传,之后再判断,符合就保存,不符合删除,可利用条件竞争来进行爆破上传
ps:技巧,查看图片是否被二次处理?
对比要上传图片与上传后的图片大小,使用
16进制编辑器
打开图片查看上传后保留了哪些数据,查看那些数据被改变。
3、代码分析
只允许上传 JPG PNG gif 在源码中使用 imagecreatefromgif 函数对图片进行二次生成。生成的图片保存在,upload 目录下。
4.7 文件上传条件竞争漏洞
1、原理
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
比如:
在文件上传时,如果逻辑不对,会造成很大危害,例如文件上传时,用move_uploaded_file 把上传的临时文件移动到指定目录,接着再用rename 文件设置为图片格式,如果在 rename 之前 move_uploaded_file 这个步骤如果这个文件可被客户端访问,这里可能存在3种情况:
- 访问时间点在上传成功之前,没有此文件
- 访问时间点在刚上传成功但没有进行判断,该文件存在
- 访问时间点在判断之后,文件被删除,没有此文件
2、利用绕过
上传 php 后门脚本,上传之后用 burpsutie 设置访问,线程建议体提高一些。抓包上传 php 文件 设置变量不停的提交这包
需要知道 php 的访问路径,抓包 不停的提交访问。 首先提交访问上传后的 php 路径 第二提交上传的文件的数据包即可。
可以看到页面返回 200 证明上传成功.
ps:先批量提交访问php的包,然后提交上传的(都批量跑)
3、检测代码分析
采用白名单上传,$upload_file = UPLOAD_PATH . '/' . $file_name; 设置上传路径,后缀名没有限定为图片类型,接着 move_uploaded_file($temp_file, $upload_file) 将图片移动指定的目录,接着使用 rename 重名为图片类型。在重名之前如果被浏览器访问,可以得到一个 webshell。
4.8 一些其他的方式
- 数组绕过上传
- 文件名可控绕过
- 目录可控绕过
- 文件上传双写绕过
- 利用windows环境的叠加特性绕过上传
- 中间件解析漏洞(apache、iis6.0、iis7.0、iis7.5、nginx)
4.9 比较通用检测方法
判断是否为黑白名单,如果是白名单 寻找可控参数。如果是黑名单禁止上传,可以用有危害的后缀名批量提交测试,寻找遗留的执行脚本。
.php
.php5
.php4
.php3
.php2
.html
.htm
.phtml
.pht
.pHp
.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
五、文件上传防御方法
服务器端使用白名单防御,修复 web 中间件的漏洞,禁止客户端存在可控参数,存放文件目录禁止脚本执行,限制后缀名 一定要设置图片格式jpg、gif 、png 文件名随机的,不可预测。
六、一些扩展
1、文件名可控,导致rce漏洞
在部分上传的功能处,文件的后缀没法绕过,但是往往很多对文件名没有做限制,同时服务器在处理文件时,会直接将文件名拼接进系统命令函数中,比如移动文件的操作。
那么此时就可以通过构造文件名造成rce漏洞
2、上传文件名为压缩包,里面文件可控,导致rce
有部分功能处,比如升级,配置文件处,喜欢通过上传压缩包,比如tar、zip等类似的文件,但是服务器却忽略对压缩包里面文件的检测,导致存在安全问题。
假如服务器端直接解压缩文件,然后直接操作里面的文件,比如移动文件的操作,势必会拼接文件名,那么这里就可操作,导致rce。