文章目录
- 一、靶场介绍
- 二、靶场搭建
- 三、关卡挑战
- Pass-01(前端JS绕过/客户端校验绕过)
- Pass-02(MIME绕过)
- Pass-03(黑名单绕过)
- Pass-04(黑名单绕过 .htaccess攻击)
- Pass-05(黑名单绕过 后缀双写逻辑绕过)
- Pass-06(黑名单绕过 大小写文件名混淆)
- Pass-07(黑名单绕过 空格绕过)
- Pass-08(黑名单绕过 填点绕过)
- Pass-09(黑名单绕过 Win文件流特性绕过)
- Pass-10(黑名单绕过 点空格点代码逻辑绕过)
- Pass-11(黑名单绕过 双写绕过)
- Pass-12(白名单绕过 00截断GET型绕过)
- Pass-13(白名单绕过 00截断POST型绕过)
- Pass-14(图片马+文件包含绕过)
- Pass-15(图片马+文件包含绕过 getimagesize())
- Pass-16(图片马+文件包含 exif_imagetype())
- Pass-17
- Pass-18(竞争条件)
- Pass-19(竞争条件)
- Pass-20(黑名单 move_uploaded_file /.绕过)
- Pass-21(白名单绕过 构造数组绕过)
一、靶场介绍
PHP语言编写,持续收集渗透测试和CTF中针对文件上传漏洞的靶场,总共21关,每一关都包含着不同的上传绕过方式。
(绕过点脑图总结:)
二、靶场搭建
2.1 靶机环境
- Win2008R2 + PHPStudy2018(php5.2.17) + upload-labs源码
2.2 搭建过程
- GitHub项目地址:https://github.com/c0ny1/upload-labs
- 百度网盘备用地址,pass: easy
》》下载
》》将文件解压到PHPStudy站点目录下,并设置建议的php版本5.2.x
》》浏览器访问,如下所示安装成功
2.3 相关函数
move_uploaded_file(file,newloc)
- 将上传的文件移动到新位置
- 通过HTTP POST上传文件
- 如果目标文件已存在,则会被覆盖
file:要移动的文件
newloc:规定文件的位置
unlink(file)
- 删除文件
in_array(search,array)
- 搜索数组中是否存在指定的值
search:规定在数组中搜索的值
array:数组
pathinfo()
- 以数组形势返回文件路径信息,可以提取后缀,但存在绕过风险
explode()
- 将字符串打散成数组
reset(array)
- 返回数组中的第一个元素并输出
empty()
- 检查变量是否为空
count(array)
- 返回数组中元素的数目
三、关卡挑战
Pass-01(前端JS绕过/客户端校验绕过)
上传限制演示
》》判断站点开发语言(PHP,也可以参考开发语言的其它判断方法)
(我们先通过操作和抓取数据包方式走一边正常的上传流程)
》》正常上传一图片文件上传成功
》》上传成功,服务器的upload目录下会存放上传的对应文件(操作过程中用户看不到此目录,这里用于理解)
》》前端会和后端进行交互,抓取的上传数据包流量
》》我们上传一个小马文件,提示该文件不允许上传,需要特定后缀类型文件
一句话php小马文件内容
源码分析
》》通过上边源码和网页源代码可看到JS脚本,判断使用文件类型在前端进行了限制
》》因此只要绕过了前端的JS校验就可以直接提给后端
绕过方法
- 方法一:数据包文件后缀绕过
》》查看服务器允许上传类型
》》将一句话木马后缀改为服务器允许上传的类型(以上三种皆可)
》》点击上传,先截取到请求数据包
》》将原来已经绕过前端的“common_php.jpg”文件改为“common_php.php”文件,向服务器发送篡改后的数据包,发送成功
现在小马文件已经上传至服务器,现在我们拿到小马的执行路径就完好了(后端允许解析执行的情况下)
》》通过浏览器检查页面元素即可拿到上传文件的相对路径(->网页右击 ->检查)
》》也可以通过返回数据包中查看上传的地址,这两个一样的
》》拼接得到上传文件的主目录
Q&A
Q1:只要上传完文件都会在返回包中拿到文件的相对/绝对路径吗?
A1:非也,需要看开发人员安全意识是否足够,后端代码中是否回显出路径
Q2:怎么通过返回的相对路径拼接成文件的绝对路径?
A2:根据经验!
》》如这里返回的绝对路径为:
》》暂且将返回的路径和当前地址的路径copy到编辑器中
》》对网页目录进行分析
》》通过点击不同的网页目录,我们发现绿色部分是不变/相同的,当我们点击目录时只有后边的内容在变,因此可判断upload-labs是站点www目录下的主目录文件
(网站站点目录和URL地址图)
(上传文件地址和. ./上级目录图)由上可拼接出上传文件的绝对路径
Q3:如何判断上传的脚本被成功解析?
A3:脚本被解析代码会运行!
》》我们在站点目录下新建一个普通文本的文件
》》浏览器访问php文件会被解析执行因此什么都不显示
判断技巧
查看网页源代码是否有限制的JS代码,点击上传后直接弹框提示,但是没有发送数据包,即用了客户端认证方法
Pass-02(MIME绕过)
上传限制演示
》》上传一句话,提示文件类型不正确
(上传数据包的MIME类型)
Tips:能抓到数据包,证明不是前端JS校验,是服务端进行校验
》》上传照片,上传成功
》》MIME类型
源码分析
》》服务端对文件的扩展类型进行了判断
绕过方法一
》》上传一合格的图片文件,记录其MIME类型
Content-Type: image/jpeg
》》上传一句话木马文件,点击上传时抓包修改文件的MIME类型为图片的MIME类型即可
绕过方法二:修改上传文件名 》》将上传文件名后缀改为图片后缀进行上传
》》点击上传后抓包修改文件后缀为php文件后缀
Pass-03(黑名单绕过)
上传限制演示
》》上传一图片文件
》》可抓取数据包,返回的相对路径
》》上传一php文件,提示不允许上传如下文件
》》上传图片文件改后缀改MIME类型皆报错
源码分析
》》这里使用了黑名单进行限制
绕过方法
后端采用了黑名单机制,只要不在黑名单中的后缀即可绕过
》》上传一php文件,抓取数据包,对文件后缀进行遍历绕过(添加至intruder模块)
》》导入后缀文件
》》依次查看不同的文件后缀中哪些文件能上传
》》点击任意一个可上传的文件浏览器查看未被解析
(条件利用苛刻需要开启SSI)
如绕过中,服务器需对绕过的文件进行解析,其apache配置文件httpd.conf中有如下配置(这里为了演示手动添加!)
》》重启服务
》》成功被解析
》》连接菜刀
Pass-04(黑名单绕过 .htaccess攻击)
上传限制演示
限制:
- 黑名单中未过滤 .htaccess
- apache配置文件httpd.conf中启用了AllowOverride All
- 服务端未处理文件名(否则上传到htaccess到目录下成为其它文件名则不奏效)
》》上传一图片文件,成功
(返回的路径信息)
》》上传一php文件,提示此文件不允许上传
源码分析
》》黑名单中限制了绝大部分的后缀文件
绕过方法
》》由于上传的文件名未经过处理,这里使用.htaccess文件攻击
Tips:.htaccess:apache服务器配置文件,负责相关网页针对每个目录下的配置,即在一个特定目录下放置一个包含指令的文件,其中的指令作用于此目录及其所有子目录。(这里我们利用这个未过滤的文件来上传一个修改后缀的php文件为jpg,然后让服务器去解析)
》》未对.htaccess文件进行限制
》》上传一1.htaccess文件,文件内容如下
(将上传的文件后缀名为.jpg格式的文件以php格式来解析)
AddType application/x-httpd-php .jpg
》》点击上传,抓包修改文件名为 .htaccess
》》上传成功(客户端显示)
(服务器目录下显示)
》》将php文件后缀由php改为jpg上传,上传成功
》》服务器访问成功被解析
》》菜刀成功连
Pass-05(黑名单绕过 后缀双写逻辑绕过)
上传限制演示
》》上传一图片文件成功,并返回文件的相对路径
》》上传一php文件
提示此文件类型不允许上传
源码分析
》》查看源码
依旧采用黑名单方式,过滤了文件后缀的点,和空格,且将.htaccess加入黑名单
绕过方法
(这里”投其所好“,双写点和空格绕过)
》》上传一php文件,抓包修改后缀,上传成功
Pass-06(黑名单绕过 大小写文件名混淆)
上传限制演示
》》上传一正常照片文件,上传成功返回相对路径
》》上传php文件,显示此类型不允许上传
》》依旧采用黑名单方式且过滤掉了.htaccess文件
源码分析
》》采用黑名单,没有转换大小写
绕过方法
利用黑名单过滤不严且没有对文件名大小写进行处理进行绕过
》》上传成功
Pass-07(黑名单绕过 空格绕过)
上传限制演示
》》上传正常图片文件,上传成功并返回相对路径
》》上传php文件,显示如下
源码分析
》》缺少对首尾去空校验
$file_ext = trim($file_ext); //首尾去空
绕过方法
》》上传php文件,抓包添加一空格,成功上传
Pass-08(黑名单绕过 填点绕过)
上传限制演示
》》上传正常的图片,返回相对路径
》》上传php文件
》》禁止上传所有可解析后缀
源码分析
(后台代码中缺少删除文件名末尾点)
绕过方法
Tips:利用Windows下文件后添加的点会自动忽略
》》点击上传php文件,抓包修改文件后缀多一个点,成功上传
Pass-09(黑名单绕过 Win文件流特性绕过)
上传限制演示
》》上传普通的图片文件,上传成功返回相对路径
》》上传php文件,显示不允许上传
源码分析
(这里未使用str_ireplace()替换字符函数去除 ::$DATA 字符)
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
绕过方法
Tips:采用Windows流特性绕过,在这里意思是php运行在Windows上时如果文件名+":: D A T A " 会 把 : : DATA"会把:: DATA"会把::DATA之后的数据当作文件流处理,不会检测后缀名,且保持“::$DATA”之前的文件名,目的即使不检查后缀名
》》上传php文件,修改文件后缀添加::$DATA,即可上传成功
》》菜刀文件管理查看上传的文件
Pass-10(黑名单绕过 点空格点代码逻辑绕过)
上传限制演示
》》上传正常的图片文件
》》上传php文件
》》提示
源码分析
(这里黑名单严格、删除文件名末尾点、大小写转换为小写、去除::$DATA字符、首尾去空)
绕过方法
Tips:代码逻辑绕过(这里代码逻辑先删除文件名末尾点,再首尾去空都只进行一次,因此可构造点空格点绕过。利用windows特性)
》》上传php文件,修改后缀如下即可绕过
》》站点目录下的上传文件
Tips:从第三关到第十关目标服务器是Windows的话皆可用此方法绕过
Pass-11(黑名单绕过 双写绕过)
上传限制演示
》》上传正常的图片文件,上传成功并返回图片相对路径
》》上传php文件,上传能成功但是文件后缀被切掉了
》》 关卡提示:去除掉上传文件名中以下字符
源码分析
(通过str_ireplace()函数将黑名单中的文件后缀名进行了替换,换为空字符)
》》因此上传的文件名在站点下变成了:
绕过方法
str_ireplace() 函数不区分大小写,因此大小写绕过不适用,这里我们使用双写文件名绕过
》》抓取上传的php文件,双写文件名(和xss双写绕过类似),上传成功
》》成功解析
Pass-12(白名单绕过 00截断GET型绕过)
上传限制演示
》》上传一正常的图片文件,上传成功
》》上传一php文件
》》查看提示
源码分析
这里用了白名单进行限制,只允许上传jpg/png/gif文件格式,拼接的文件路径为随机数+时间+文件后缀。构造文件存储路径使用GET传入,导致服务器最终存储的文件名可控。
绕过方法
》》使用00截断绕过
Tips:条件
- php版本<5.3.4
- php.ini的magic_quotes_gpc为OFF
》》将php后缀文件改为服务器允许上传的文件后缀,上传成功
将123.php后的内容忽略掉,使用common_php.jpg文件中的内容上传到123.php中
》》查看站点目录中文件名
》》因此构造的文件绝对路径为:
Pass-13(白名单绕过 00截断POST型绕过)
》》上传正常的图片文件,上传成功返回文件相对路径
》》上传php文件,对文件后缀进行限制
》》查看提示
源码分析
》》这里的save_path是通过POST传参过来
绕过方法
00截断绕过,POST不会像GET自动解码,因此这里需要对进行编码
》》将php文件后缀改为jpg,上传抓包,123.php后加一个空格(16进制为20):
》》16进制查看修改,将空格20改为00(70后边)
(改完如下显示:)
》》上传成功
》》成功解析
Pass-14(图片马+文件包含绕过)
Tips:和DVWA 文件上传 high类似
》》上传php文件,上传失败
》》上传提示传图片马
》》查看提示
源码分析
(先读文件前两个字节,通过对比文件头来确定文件类型,即只对文件头检测)
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_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
绕过方法
通过将一句话包含到图片文件中,上传图片马到目标站点下,通过文件包含漏洞执行php代码
》》制作图片马
(common_php.php文件内容)
<?php fputs(fopen("hack.php","w"),"<?php @eval(\$_POST['duang']) ?>") ?>
》》一句话包含隐匿于图片马中
》》上传图片马,上传成功,拿到返回的相对路径(如果直接访问相对路径只是一张照片并不能解析php语句)
》》站点目录下的上传对应文件
使用文件包含访问图片马(站点需存在文件包含漏洞才可利用此漏洞,这里我使用同站点下的DVWA靶场的文件包含漏洞进行的演示)
》》使用同站点下的DVWA靶机文件包含爆出站点绝对路径
》》通过文件包含爆出的站点路径结合上传给的相对路径,构造访问一句话木马文件
》》hack.jpg会运行hack.php中的代码在文件包含目录下生成hack.php一句话文件
》》文件包含目录成功解析此文件
》》菜刀连接此地址
http://192.168.226.130/DVWA/vulnerabilities/fi/hack.php
Pass-15(图片马+文件包含绕过 getimagesize())
》》上传正常的图片文件,返回站点的相对路径
》》上传php文件,报错
》》查看提示
源码分析
》》使用 getimagesize()函数 验证文件头信息
绕过方法
》》生成图片马
》》将图片马上传到服务器站点下
》》使用DVWA的文件包含解析此文件
》》爆出站点路径
》》文件包含执行此文件
》》查看生成的一句话是否能解析
Pass-16(图片马+文件包含 exif_imagetype())
源码分析
(使用exif_imagetype()函数来判断是否为图片文件)
绕过方法
图片马绕过
Pass-17
上传限制演示
》》上传图片马尝试,上传成功
》》使用文件包含访问该文件,发现文件中并没有我们写入的php代码
源码分析
(对文件的类型进行判断,再使用imagecreatefromjpeg|gif|png判断是否为图片文件,是的话对其进行二次渲染)
if (isset($_POST['submit'])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['upload_file']['name'];
$filetype = $_FILES['upload_file']['type'];
$tmpname = $_FILES['upload_file']['tmp_name'];
$target_path=UPLOAD_PATH.'/'.basename($filename);
// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);
//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);
if($im == false){
$msg = "该文件不是jpg格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagejpeg($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
绕过方法-gif
》》首先制作gif图片的图片马
》》将文件上传到服务器
》》上传到服务器的照片另存到本地
》》通过16进制编辑器寻找和图片马文件相同的地方
》》蓝色位置是相同的
》》在相同的位置插入php代码
Pass-18(竞争条件)
上传限制演示
》》上传一正常图片
》》上传php文件
》》查看提示
源码分析
(先使用move_uploaded_file()将上传的文件临时保存到服务器,再进行判断,如果在数组中就保存重命名,如果不在就直接删除)
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
绕过方法
(这里可以通过条件竞争方式进行绕过)
(设置上传请求) 》》点击上传,抓取请求数据包 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200519145717756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Fhcm9uX01pbGxlcg==,size_16,color_FFFFFF,t_70)
》》使用Burp的Intruter模块重放
(设置访问请求)
》》浏览器构造url进行访问
》》设置线程和访问,然后观察响应即可
Pass-19(竞争条件)
源码分析
(对文件进行检查后重命名文件)
绕过方法
程序来不及rename时通过竞争条件上传shell
Pass-20(黑名单 move_uploaded_file /.绕过)
上传限制演示
》》上传图片文件,并自定义保存文件名称
》》上传成功并生成文件路径
》》上传php文件,定义文件名为php
》》查看提示
源码分析
(定义一个数组,使用pathinfo()函数提取文件后缀,和白名单中对比,如果不在其中则返回文件路径)
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = $_POST['save_name'];
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!in_array($file_ext,$deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
}else{
$msg = '上传出错!';
}
}else{
$msg = '禁止保存为该类型文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
绕过方法1 - 图片马+文件包含
》》生成图片马(phpinfo)
》》将图片马上传到站点
》》文件包含进行访问
**绕过方法2 - move_uploaded_file()函数00截断CVE-2015-2348**
(move_uploaded_file会自动忽略文件末尾的/.因此可构造保存路径为1.php/.这样file_ext的值即可空这样便可绕过黑名单)
(windows中文件不允许加/ \ 因此自动删掉)
》》上传一句话文件,使用 /. 进行绕过
》》上传成功
》》利用了windows特性结合move_uploaded_file()成功处理/.的问题
》》成功解析
Pass-21(白名单绕过 构造数组绕过)
上传限制演示
》》上传一正常图片文件,上传成功
》》上传php脚本文件
》》该关卡提示代码审计
源码分析
(首先使用白名单判断文件MIME类型必须为数组中的图片类型; 检查文件名如果不是数组使用explode分割成数组; 提取上传文件名的最后一后缀,再次白名单判断保存文件名是否为图片; 文件名返回数组中第一个元素并输出文件名,如果没有定义数组的话则输出后缀;)
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//检查MIME
$allow_type = array('image/jpeg','image/png','image/gif');
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//检查文件名
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
if (!is_array($file)) {
$file = explode('.', strtolower($file));
}
$ext = end($file);
$allow_suffix = array('jpg','png','gif');
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1];
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$msg = "文件上传成功!";
$is_upload = true;
} else {
$msg = "文件上传失败!";
}
}
}
}else{
$msg = "请选择要上传的文件!";
}
绕过方法
(这里我们可以定义一个数组,利用如下代码构造数组来绕过)
$file_name = reset($file) . '.' . $file[count($file) - 1];
》》正常上传一句话(这里需要将一句话改成图片文件来绕过MIME校验)
》》抓取数据包,构造数组如下成功上传
Q&A
Q:为何这里使用数组save_name[2]那
A:由后台站点代码可知:$file_name = reset($file) . '.' . $file[count($file) - 1];
count(file)=2
$file[count(file)-1]=1,而
$file[1]为空,所以
$file_name=upload-21.php