漏洞原理
大部分的网站和应用系统都有上传功能,而程序员在开发文件上传功能时,并未考虑文件格式后缀的合法性校验或者是否只在前端通过js进行后缀检验。
这时攻击者可以上传一个与网站脚本语言相对应的恶意代码动态脚本,例如(jsp、asp、php、aspx文件后缀)到服务器上,从而访问这些恶意脚本中包含的恶意代码,进行动态解析最终达到执行恶意代码的效果,进一步影响服务器安全。
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。一般都是指“上传Web脚本能够被服务器解析”的问题。
漏洞危害
可能会导致用户信息泄露,被钓鱼,甚至使攻击者可以直接上传WebShell到服务器,进而得到自己想要的信息和权限。最终达到对数据库执行、服务器文件管理、服务器命令执行等恶意操作,甚至完全控制服务器系统。
webshell:运行在web应用之上的远程控制程序 。 webshell分为大马、小马等。功能简易的webshell称为小马,拥有较完整功能的webshell,称为大马。
一句话木马:
<?php @eval($_POST[a]); ?>
漏洞利用
文件上传漏洞利用条件:
(1)能够成功上传木马。
(2)上传的木马能够被web容器解析执行,所以上传路径要在web容器覆盖范围内。
(3)用户能够访问上传的木马,所以得知道上传的木马准确路径。
将一句话木马上传至服务器,并能成功访问。(页面空白访问成功)
通过hackbar对变量a进行传值,即可完成服务端命令执行。
还可以执行系统命令。
此外,还可以配合如菜刀,蚁剑等工具使用。
打开蚁剑,选择添加数据。
输入好参数后测试连接,然后添加。
文件上传绕过
了解了漏洞的利用方式,那么如何绕过检测向服务器上传木马文件。
客户端JavaScript检测
开发者在前端使用JavaScript做了白名单验证,如果文件名不符合规则那么就不允许被上传。
JavaScript代码:
<script type="text/javascript">
function checkFile(){
var flag=false;
var str=document.getElementById("file").value;
str = str.substring(str.lastIndexOf('.')+1);
var arr=new Array('png','gif','jpg');
for(var i=0;i<arr.length;i++){
if(str==arr[i]){
flag=true;
}
}
if(!flag){
alert('文件不合法');
}
return flag;
}
</script>
提交表单:
<form action="low.php" method="post" onSubmit="return checkFile()" enctype="multipart/form-data">
<input type="file" name="file" id="file" /><br/>
<br/>
<input type="submit" vlue="提交" name="submit">
</form>
服务端PHP代码:
<?php
if (isset($_POST['submit'])) {
$target_path = "../uploads/";
$target_path = $target_path . basename( $_FILES['file']['name']);
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo'文件上传失败';
} else {
echo"$target_path 文件上传成功";
}
}
?>
绕过方式:
1.删除/禁用JavaScript代码。
2.先上传符合规则的文件,通过burp suite抓包修改其后缀名。
使用火狐插件禁用JavaScript代码
服务端MIME类型检测
MIME类型用来设定某种扩展名文件的打开方式,当具有该扩展名的文件被访问时,浏览器会自动使用指定的应用程序来打开。上传文件时可以通过服务端对上传文件的MIME类型进行判断。
服务端PHP代码:
<?php
if (isset($_POST['submit'])) {
$target_path = "../uploads/";
$target_path = $target_path . basename($_FILES['file']['name']);
$uploaded_name = $_FILES['file']['name'];
$uploaded_type = $_FILES['file']['type'];
if ($uploaded_type == "image/jpeg"){
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo'文件上传失败';
} else {
echo"$target_path 文件上传成功";
}
}
else{
echo'文件上传失败';
}
}
?>
绕过方式:
通过burp suite抓包修改Content-Type字段改为:Content-Type: image/jpeg
服务端 白名单检测
服务端取文件后缀名进行白名单比对,如果文件名不符合规则那么就不允许被上传。
服务端白名单检测算是相对安全的检测方式,但也有被利用的可能。
服务端PHP代码:
<?php
if (isset($_POST['submit'])) {
$target_path = "../uploads/";
$target_path = $target_path . basename($_FILES['file']['name']);
$uploaded_name = $_FILES['file']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1);
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "JPEG")){
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo'文件上传失败';
} else {
echo"$target_path 文件上传成功";
}
} else {
echo'文件上传失败';
}
}
?>
绕过方式:
首先将木马文件改为规则的后缀名,通过burp suite抓包,如果头文件中含有文件名以及存储路径。将路径改为xx.php后面跟%00,文件名不变。那么在存储路径和文件名拼接时%00及以后的信息将被丢弃。即符合白名单验证,文件又会被存储为xx.php。
(还可以配合服务器解析漏洞,以及文件包含漏洞形成漏洞链以达到攻击的目的。)
服务端文件头检测
文件头检测是在文件上传时取文件的前2个字节进行特征对比。
木马文件直接更改后缀名可以通过服务端白名单检测,但是无法绕过文件头检测。
服务端PHP代码:
<?php
header("Content-type: text/html; charset=utf-8");
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;
}
if (isset($_POST['submit'])) {
$target_path = "../uploads/";
$target_path = $target_path . basename($_FILES['file']['name']);
$uploaded_name = $_FILES['file']['name'];
$fileType = getReailFileType($_FILES['file']['tmp_name']);
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1);
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "JPEG" ) & ($fileType == 'jpg' || $fileType == 'png' || $fileType == 'gif')){
if(!move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo"文件上传失败";
} else {
echo"$target_path 文件上传成功";
}
}else{
echo"文件上传失败";
}
}
?>
绕过方式:
添加文件头:GIF89a
制作图片马:图片名称xx.jpg,木马名称xx.php。copy xx.jpg/b + xx.php/a xx.jpg
以文本格式打开2.jpg查看:
这样的文件无法即使被php解析也无法生效,解决办法就是在一句话木马的开头添加一个字符,然后重新制作即可。
解析漏洞
IIS解析漏洞
(1)当建立*.asp、*.asa格式的文件夹时,其目录下的任意文件都将被IIS当作ASP文件来解析。
(2)当文件名为*.sap;1.jpg时,IIS6.0同样会以ASP脚本来执行。
Apache解析漏洞
在Apache1.x和Apache2.x中存在解析漏洞,当碰到不认识的扩展名时,将会从后向前解析,直到碰到认识的扩展名为止,如果都不认识,则会暴露其源代码。
PHP CGI解析漏洞
在PHP的配置文件中有一个关键的选项:cgi_fi:x_pathinfo。这个选项在某些版本中默认是开启的,在开启时,PHP将会向前递归解析,于是就造成了解析漏洞。
如:访问https://www.xxx.com/1.jpg/x.php(x.php为不存在文件),此时1.jpg会被当作PHP脚本来解析。
在搭配Nginx,IIS7.0,IIS7.5等Web容器时都有出现此漏洞。
此外利用本地文件包含漏洞也可以达到服务器解析图片马的功能。
防范方法
(1)文件上传的目录设置为不可执行
只要web容器无法解析该目录下的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响。
(2)判断文件类型
通过MIME类型、后缀名检查等方式,判断文件类型。建议使用白名单。
(3)使用随机数改写文件名和文件路径
用户想要执行上传的脚本,就需要先访问到此文件。所以最好保证服务端在接收到文件后对其进行重命名,并不对外暴漏路径。