文件上传漏洞
- 常见的漏洞分类
服务器配置不当导致文件上传
开源编辑器存在上传漏洞
本地文件上传限制可以上传被绕过
服务器端过滤不严可以被绕过
解析漏洞导致文件执行
文件路径截断
IIS6.0 解析漏洞
在 Windows 2003下 IIS 6.0有两个漏洞。
1、目录解析
/xx.asp/xx.jpg
利用方法:在网站下建立文件夹的名字为.asp、.asa的文件夹,其目录内的任何扩展名的文件都被iis当做是.asp的文件解析来执行。
2、文件解析
Abc.asp;.jpg
利用方法:在iis6.0下,分号后面的不被解析,也就是说网站上传图片的时候,将网页木马文件的名字改成“*.asp;.jpg”,也同样会被 IIS 当作 asp 文件来解析并执行。例如上传一个图片文件,名字叫“vidun.asp;.jpg”的木马文件,该文件可以被当作 asp 文件解析并执行。,默认可执行的文件还包含三种:
/abc.asa
/abc.cer
/abc.cdx
补充:
对于文件上传漏洞的防护来说,主要分为以下两类:
白名单限制和黑名单限制
对于黑名单的限制,我们只需要寻找一些较为偏僻的可执行后缀、大小写混写以及相关操作系统的特性(如windows文件名后缀的最后会自动过滤空格以及.等)来进行绕过;
对于白名单的限制来说,一般是结合解析漏洞、代码函数漏洞(icov(80-EF截断),造成00截断的相关函数以及相关操作系统特性(如windows10文件名长度总共为223包括后缀,win2012的为237,linux ubuntu0.16.04.1文件名长度252等)来进行绕过!
IIS解析漏洞1:
在网站下建立文件夹的名字为 .asp、.asa 的文件夹,其目录内的任何扩展名的文件都被 IIS 当作 asp 文件来解析并执行。例如创建目录 vidun.asp,那么 /vidun.asp/1.jpg 将被当作 asp 文件来执行
例子一:
http://219.153.49.228:49837/ 访问网站(墨者学院)
1、先确定服务器的类型,先随便上传一个.asp文件,抓包发送到repeater,从报错信息可以看到服务器类型为:Server: Microsoft-IIS/6.0
2、修改upload目录为abc.asp,点击go
3、到上传路径和文件名
4、访问上传的木马文件,用菜刀链接
例子二:
上传可以看到上传的时候弹出一个弹窗,只让我们上传上面格式的文件,先看一下源码
Upload
发现前端存在js验证,只能识别图片格式的文件进行上传,这里有两种方法:
第一种是:将一句话木马1.php的后缀名改成.jpg格式的然后进行上传,用burpsuit进行对文件格式改为1.php,上传成功后用菜刀进行链接获取shell,并找到key.
第二种是: 先在浏览器输入about:config(仅限于火狐浏览器),然后搜索java script .enabled将切换为false,这样就禁用了javascript,前端验证不起作用 ,创建一句话木马 ,直接上传,返回上传路径 uploads/1.php,然后菜刀链接
使用方法一进行测试,http://219.153.49.228:42415/ 访问网站
随便上传一张图片用burpsuite抓包,修改文件夹后缀以及在内容里面添加一句话木马
访问返回木马的路径
菜刀连
例子三:
1、上传很多次,都显示 不允许上传,后来把一句话木马写入到图片里面,然后通过burpsuit进行修改后缀,上传成功
burpsuit进行修改后缀
查看返回地址
菜刀连接
例子四:
浏览器设置代理,上传一张正常的图片,burp抓包
修改burpsuite抓到的包,在内容区域写入一句话木马,最好不要写在最前面,有可能上传的时候会检测文件头,尽量在中间写入木马
菜刀链接,找打key
例子五:
文件后缀名绕过
前提是:黑名单校验
黑名单检测:一般有个专门的 blacklist 文件,里面会包含常见的危险脚本文件。
绕过方法:
(1)找黑名单扩展名的漏网之鱼 - 比如 asa 和 cer 之类
(2)可能存在大小写绕过漏洞 - 比如 aSp 和 pHp 之类
能被解析的文件扩展名列表:
jsp jspx jspf
asp asa cer aspx
php php php3 php4
exe exee
1、上传是php文件的解析规则
所以构造好php一句话木马
2、使用burpsuit进行截断攻击
简单的更改文件后缀名字发现有相应的过滤规则
3、尝试进行截断
随便构造一个后缀名字。
4、成功上传,菜刀链接
例子六:
这道题也是借助大佬的帮助才成功,具体我们来看:
先扫描一波目录看看
发现了几个比较有用的目录,特别是upload1.php跟upload2.php两个上传页面
我们先来访问upload1.php:
点击确定后是upload2.php,竟然是一片空白
不过中间好像有个上传的页面一闪而过,我们用burp抓包,来一页一页看页面
果然有这个页面,但是抓包的cookie引起了我们的注意:
Cookie: uploadmd5=verify%2F2b10f3817a8604ef.txt
我们查看源代码:
竟然还有一个隐藏的提交表单
我们解码这个 :2b10f3817a8604ef-----> 结果是 : 1543390594
感觉好像跟题目没有一点关系的好吧
但是我们又突然发现它是以 .txt结尾的,这是不是会存在任意文件读取漏洞,我们稍后尝试,我们进行下一步上传
我们直接构造 shell.php 内容为 进行上传
ok!已经成功了,可以用菜刀连接了 等等,咦路径呢?
分析数据包可能是upload_file.php....我们访问试一下
然而并不是刚刚上传的木马,木马虽然传上去了,但是路径呢,路径呢
突然想到还有一个可能包含任意文件读取的点,我们重新抓包
把 verify%2F2b10f3817a8604ef.txt ------> upload_file.php
分析源代码
源码中发现包含了上传路径
$result=move_uploaded_file($_FILES["filename"]["tmp_name"],$file2);
关键在这一句,$file2 可能保存的就是文件的上传路径
$file2 = $path.$time.'_'.$verify.'_'.$file1;
其中:
$path="uploadfile/"
$verify=$_POST["verify"]; 我想到了那个隐藏的提交表单,其中value="2b10f3817a8604ef"
$time=date("Ymd"); Ymd不就年月日,那今天就是20181128
按照这样解释的话,路径也就是admin/uploadfile/20181128_2b10f3817a8604ef_shell.php
这样猜想的,试试看
访问,使用菜刀连接,获取key
后来才发现还有upload.php,御剑估计老了,我们用任意代码的漏洞查看
竟然是cookie的生成过程,哈哈哈
到此为止,掌握方法,顺便告诉我们cookie的重要性
墨者学院文件上传的题目到这里就全部做完,这样就够了,显然是不够的,我又本地搭建了Upload-labs靶场进行练习
开始你的表演,先来张图压压惊
-
pass-01
上传文件,显示只能上传什么类型的
审查元素发现:是js验证
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;
}
}
这时要猜测判断文件后缀的代码是在前端还是后端,打开burp进行拦截,发现点击上传后,并没有进行发包。可知判断后缀的代码在前端,即用js代码判断的,打开浏览器的审查元素,找到文件上传的js代码
发现有一个checkFile()函数,推测可能是这个函数进行判断的,我们把它删除后再上传,或者也可以通过抓包的方式修改文件后缀进行绕过
上传之后查看源码,得到上传文件的路径
访问连接,菜刀连接
- pass-02
第二关先进行黑盒测试,发现可以上传正常图片、修改后缀名的(shell.php改为shell.jpg)进行上传、抓包修改后缀名(上传shell.jpg抓包改为shell.php)、修改文件类型(上传shell.php,修改Content-Type: image/gif)成功上传木马。
这就说明只是服务器对后缀名进行验证,绕过问题不大。我们查看原代码分析下
$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["file"]["name"] – 被上传文件的名称
$_FILES["file"]["type"] – 被上传文件的类型
$_FILES["file"]["size"] – 被上传文件的大小,以字节计
$_FILES["file"]["tmp_name"] – 存储在服务器的文件的临时副本的名称
$_FILES["file"]["error"] – 由文件上传导致的错误代码
move_uploaded_file(file,newloc) 函数将上传的文件移动到新位置。
参数 描述
file 必需。规定要移动的文件。
newloc 必需。规定文件的新位置。
如果 file 不是合法的上传文件,不会出现任何操作,move_uploaded_file() 将返回 false。
如果 file 是合法的上传文件,但出于某些原因无法移动,不会出现任何操作,move_uploaded_file() 将返回 false,此外还会发出一条警告。
可以看到这里采用的是后端验证文件类型, 但是他只过滤的文件类型, 并没有过滤文件后缀名, 所以可以上传 php 文件修改 content-type 绕过, 可以看到成功执行了 phpinfo
- pass-03
禁止上传.asp|.aspx|.php|.jsp后缀文件
用上面方法发现上传都不行,发现对.asp|.aspx|.php|.jsp后缀名进行了严格的限制。
用[.htaccess]从新解析.htaccess的内容是,意思是让jpg格式的文件也当成php文件运行
AddType application/x-httpd-php .jpg
当然也需要apache支持
配置文件LoadModule rewrite_module modules/mod_rewrite.so前的注释去掉,寻找关键词:AllowOverride,并把后面的参数从None全部改成All
首先上传.htaccess文件,再上传jpg文件解析成功
注.htaccess基础知识重点内容
.htaccess文件(或者”分布式配置文件”),全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。
它里面有这样一段代码:AllowOverride None,如果我们把None改成All
- pass-04
查看源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".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");
$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 = '此文件不允许上传!';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
虽然还是黑名单,但几乎过滤了所有有问题的后缀名,除了.htaccess,于是首先上传一个.htaccess内容如下的文件:
SetHandler application/x-httpd-php
这样所有文件都会解析为php,然后再上传图片马,就可以解析:
访问
- pass-05
查看源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
现在这个.htaccess是上传是不行的。分析下代码发现,他少了这么一行,出现比较严重的问题。
$file_ext = strtolower($file_ext); //转换为小写
可以看到在第五关代码中没有这个
于是可以通过大小写绕过:
发现成功上传,可以访问一下,发现成功执行:
- pass-06
查看源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
$file_name = $_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
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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
发现依然是黑名单,但这次程序没有对文件后缀去空(其实如果程序没有对文件进行重命名的话,可以借one.php .jpg绕过白名单的)
上传一个php文件,抓包将文件名后缀加上空格,如下图
访问:
- pass-07
查看源代码:
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
$file_name = trim($_FILES['upload_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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
还是黑名单,但是没有对后缀名进行去”.”处理,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过:
访问
- pass-08
查看源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
说实话第八关这个绕过方式我之前根本不知道的,就是在php+windows的情况下:如果文件名+"::DATA之后的数据当成文件流处理,不会检测后缀名.且保持"::$DATA"之前的文件名。
具体原理还不是很清楚。。
- pass-09
这关算是一个逻辑漏洞
查看源码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
$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 . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
黑名单过滤,注意第15行和之前不太一样,程序先是去除文件名前后的空格,再去除文件名最后所有的.,再通过strrchar来寻找.来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,导致可以利用类似shell.php. .(两个点号之间有一个空格)绕过,如果重名名了文件的话应该会用$file_ext来进行拼凑文件,这样保存在服务器中的文件将没有后缀(去除了.空格)
$img_path = $UPLOAD_ADDR . '/' . $file_name;
访问
- pass-10
查看源码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {
$img_path = $UPLOAD_ADDR . '/' .$file_name;
$is_upload = true;
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
依旧是黑名单过滤,注意到,这里是将问题后缀名替换为空,于是可以利用双写绕过:
$file_name = str_ireplace($deny_ext,"", $file_name);
返回
- pass-11 采用00截断GET方式
最初并不了解这种方式,是看了大佬的笔记之后才做出来的,当然也要借鉴大佬的笔记啦,主要是大佬笔记做的很全面
$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);
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类型文件!";
}
}
基础补充两个函数:substr()、strrpos()
strrpos()
定义和用法
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。
注释:strrpos() 函数对大小写敏感。
相关函数:
stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
语法
strrpos(string,find,start)
参数 描述
string 必需。规定被搜索的字符串。
find 必需。规定要查找的字符。
start 可选。规定在何处开始搜索。
substr()
这里写代码片语法
substr(string,start,length)
参数 描述
string 必需。规定要返回其中一部分的字符串。
start 必需。规定在字符串的何处开始。正数 - 在字符串的指定位置开始 负数 - 在从字符串结尾开始的指定位置开始0 - 在字符串中的第一个字符处开始
length 可选。规定被返回字符串的长度。默认是直到字符串的结尾。正数 - 从 start 参数所在的位置返回的长度负数 - 从字符串末端返回的长度
理解测试代码:
返回jpg
分析代码:
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
发现那个路径没有处理直接拼接上去的。所以可以利用00截断绕过。但是发现怎么截断都没有用。查阅资料得知:
截断条件:
php版本小于5.3.4 详情关注CVE-2006-7243
php的magic_quotes_gpc为OFF状态 //如果不修改将无法上传成功,默认为ON
我本地的版本为5.2.17
开始测试:
上传文件—截断—修改文件后缀—看返回的路径
访问,成功上传
- pass-12 采用00截断POST方式
查看并分析源码
$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);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_POST['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类型文件!";
}
}
和十一关不同的是这次的save_path是通过post传进来的,还是利用00截断,但这次需要在二进制中进行修改,因为post不会像get对%00进行自动解码
或者你也可以使用url-decode进行编码之后进行上传文件,同样可以解析成功
我们依然使用00截断方法:
来到+号对应的二进制2b将他改为00
点击go进行上传
访问
上面这种方式有一点点繁琐,下面这种方式比较好上手
选中%00—编码—点击go—即可上传成功—访问
- pass-13 图片马上传
查看源码
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;
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_type = getReailFileType($temp_file);
if($file_type == 'unknown'){
$msg = "文件未知,上传失败!";
}else{
$img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
else{
$msg = "上传失败";
}
}
}
发现主要是取上传文件的头两个字节判断文件类型,因此直接上传图片马即可
图片马的制作
copy normal.jpg /b + shell.php /a webshell.jpg
上传图片马: