1、编写一个上传图片的功能页面
2、针对上传的文件进行验证(后缀验证、文件头验证、文件名验证等)
3、文件上传通常会与文件解析漏洞相结合,可以收集整理存在解析漏洞的组件和相关版本,无法部署相关环境,可以学习相关技术,不用实际操作
扩展学习:学习如何绕过黑名单验证、文件头验证,如何杜绝上传图片的功能无法利用获取 shell ?
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 errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
getElementsByName()
方法可返回带有指定名称的对象的集合。
document.getElementsbyname(name)[0].value
document.getElementsbyname(name)的意思就是获取当前页面上指定name名称的对象集合
页面上有可能不止一个叫name的对象,所以[0]就是获取第一个
Substring()
例如:
string front = null;
string back = null;
string str = "abcdefg";
front = str.Substring(0, 1);//从第一个开始截取,共截取一位
back = str.Substring(str.Length - 1, 1);//从最后一个开始截取,共截取一位
Response.Write(front + "***" + back);
输出效果:a***g
lastIndexOf()
例如:
string str = "abcdefg";
str = str.Substring(0, str.LastIndexOf("c"));
Response.Write(str);
输出效果:ab
就是截取c前面的字符串。
indexOf()
stringObject.indexOf(searchvalue,fromindex)
该方法将从头到尾地检索字符串 stringObject,看它是否含有子串 searchvalue。开始检索的位置在字符串的 fromindex 处或字符串的开头(没有指定 fromindex 时)。如果找到一个 searchvalue,则返回 searchvalue
的第一次出现的位置。stringObject 中的字符位置是从 0 开始的。indexOf() 方法对大小写敏感!如果要检索的字符串值没有出现,则该方法返回 -1。
可以利用burp抓包改包,先上传一个gif类型的木马,然后通过burp将其改为asp/php/jsp后缀名即可
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR))
{
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
{
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name']))
{
$img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
$is_upload = true;
}
}
else $msg = '文件类型不正确,请重新上传!';
}
else $msg = $UPLOAD_ADDR.'文件夹不存在,请手工创建!';
}
$_FILES['myFile']['type']
文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。
move_uploaded_file() 函数将上传的文件移动到新位置。若成功,则返回 true,否则返回 false。
语法move_uploaded_file(file,newloc) 其中newloc是新的位置。
检测上传到服务器的文件类型,在 burp 抓包可以看到类似于 Content-Type: image/gif
使用 burp 抓包,上传本地文件 muma.php
在 burp 的 request 包里可以看到Content-Type: text/plain
修改:Content-Type: text/plain -> Content-Type: image/gif
像这种服务端检测http 包的Content-Type 都可以用这种类似的方法来绕过检测
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array('.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))
{
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name']))
{
$img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name'];
$is_upload = true;
}
}
else $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
else $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
(1)trim() 函数移除字符串两侧的空白字符或其他预定义字符。
trim(string,charlist)
string 必需。规定要检查的字符串。
charlist 可选。规定从字符串中删除哪些字符。如果被省略,则移除以下所有字符:
“\0” - NULL
“\t” - 制表符
“\n” - 换行
“\x0B” - 垂直制表符
“\r” - 回车
" " - 空格
(2)strrchr() 函数查找字符在指定字符串中从后面开始的第一次出现的位置,如果成功,则返回从该位置到字符串结尾的所有字符,如果失败,则返回 false。
(3)str_ireplace() 函数替换字符串中的一些字符(不区分大小写)
语法str_ireplace(find,replace,string,count)
参数 描述
find 必需。规定要查找的值。
replace 必需。规定替换 find 中的值的值。
string 必需。规定被搜索的字符串。
count 可选。一个变量,对替换数进行计数。
(4)in_array() 函数搜索数组中是否存在指定的值。
注释:如果 search 参数是字符串且 type 参数被设置为 TRUE,则搜索区分大小写。
语法in_array(search,array,type)
不允许上传.asp,.aspx,.php,.jsp
后缀文件,但是可以上传其他任意后缀
.php .phtml .phps .php5 .pht
前提是apache的httpd.conf
中有如下配置代码
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
或者上传.htaccess
文件:
需要条件:
1.mod_rewrite模块开启
2.AllowOverride All
文件内容
SetHandler application/x-httpd-php
或者
AddType application/x-httpd-php .jpg
另外基本上所有的黑名单都可以用Apache解析漏洞绕过。
$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);//找到.的位置+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;
if(move_uploaded_file($temp_file,$img_path))
{
$is_upload = true;
}
else $msg = '上传失败!';
}
else $msg = "只允许上传.jpg|.png|.gif类型文件!";
}
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。返回字符串在另一字符串中最后一次出现的位置,如果没有找到字符串则返回 FALSE
注释:strrpos() 函数对大小写敏感。
strrpos(string,find,start)
参数 | 描述 |
---|---|
string | 必需。规定被搜索的字符串。 |
find | 必需。规定要查找的字符。 |
start | 可选。规定在何处开始搜索。 |
substr() 函数返回字符串的一部分。
注释:如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。
语法:substr(string,start,length)
CVE-2015-2348影响版本:
5.4.x<= 5.4.39, 5.5.x<= 5.5.23, 5.6.x <= 5.6.7
exp:move_uploaded_file($_FILES['name']['tmp_name'],"/file.php\x00.jpg");
源码中move_uploaded_file
中的save_path
可控,因此00截断即可。
可以利用burp抓包改包,先上传一个gif类型的木马,然后通过burp将其改为asp/php/jsp后缀名即可。
我们可以通过抓包,将content-type字段改为image/gif
在木马内容基础上再加了一些文件信息,有点像下面的结构
GIF89a
还有PE的MZ头,JPG的JFIF等等,GIF的GIF89a
前提:黑名单校验
黑名单检测:一般有个专门的 blacklist 文件,里面会包含常见的危险脚本文件。
绕过方法:
(1)找黑名单扩展名的漏网之鱼 - 比如 asa 和 cer 之类
(2)可能存在大小写绕过漏洞 - 比如 aSp 和 pHp 之类
能被解析的文件扩展名列表:
jsp jspx jspf
asp asa cer aspx
php php php3 php4
exe exee
前提:校验规则只校验当文件后缀名为asp/php/jsp的文件内容是否为木马。
绕过方式:(这里拿php为例,此漏洞主要存在于PHP中)
(1)先上传一个内容为木马的txt后缀文件,因为后缀名的关系没有检验内容;
(2)然后再上传一个.php的文件,内容为
此时,这个php文件就会去引用txt文件的内容,从而绕过校验,下面列举包含的语法:
#PHP
\#ASP
\#JSP
or
<%@include file="上传的txt文件路径"%>
详细可参考:http://thief.one/2016/09/21/服务器解析漏洞/
(1)上传不符合windows文件命名规则的文件名
test.asp.
test.asp(空格)
test.php:1.jpg
test.php::$DATA
shell.php::$DATA…….
会被windows系统自动去掉不符合规则符号后面的内容。
(2)linux下后缀名大小写
在linux下,如果上传php不被解析,可以试试上传pHp后缀的文件名。
(1)CMS漏洞:比如说JCMS等存在的漏洞,可以针对不同CMS存在的上传漏洞进行绕过。
(2)编辑器漏洞:比如FCK,ewebeditor等,可以针对编辑器的漏洞进行绕过。
这两方面的漏洞以后单独成文汇总,这里点到为止。
(1)0x00截断:基于一个组合逻辑漏洞造成的,通常存在于构造上传文件路径的时候
test.php(0x00).jpg
test.php%00.jpg
路径/upload/1.php(0x00),文件名1.jpg,结合/upload/1.php(0x00)/1.jpg
伪代码演示:
name= getname(httprequest) //假如这时候获取到的文件名是 help.asp.jpg(asp 后面为 0x00)
type =gettype(name) //而在 gettype()函数里处理方式是从后往前扫描扩展名,所以判断为 jpg
if(type == jpg)
SaveFileToPath(UploadPath.name, name) //但在这里却是以 0x00 作为文件名截断
//最后以 help.asp 存入路径里
垃圾数据
有些主机WAF软件为了不影响web服务器的性能,会对校验的用户数据设置大小上限,比如1M。此种情况可以构造一个大文件,前面1M的内容为垃圾内容,后面才是真正的木马内容,便可以绕过WAF对文件内容的校验;
文件上传验证绕过技术总结
upload-labs
图片马二次渲染
upload超全