Pass-01
首先我们尝试上传php文件,他会提示可以上传的文件类型以及你的文件类型
我们发现他是前端验证的文件后缀名,所以我们可以直接上传结尾为.jpg
的shell文件,然后抓包修改后缀。
修改文件后缀:
右击图片获取路径:
http://192.168.252.168/upload-labs-master/upload-labs-master/upload/1.php
成功:
分析源码:
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$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 = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
<script>
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;
}
}
</script>
我们可以看到在php文件中没有对文件名过滤,这是判断文件路径是否存在,而过滤文件名放在了前端的js函数中,所以我们可以直接绕过过滤。
Pass-02
这一关中,我们还是先上传一个php文件,提示文件类型不正确,请重新上传,没有提示白名单的后缀。
我们继续测试,发现这一次是服务器验证文件类型,我们还是上传图片shell,修改文件名最后上传成功。
http://192.168.252.168/upload-labs-master/upload-labs-master/upload/Pass2.php
我们首先判断php和jpg上传的时候,两处明显的不同时文件类型和文件名,我们将文件名修改为php可以成功上传,说明后端只验证请求包中的文件类型,我们可以分析一下源码。
$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.'文件夹不存在,请手工创建!';
}
}
我们可以看到这次的上传判断中添加了请求包中的文件类型,如果文件类型是图片类型就可以成功上传。
Pass-03
这一关我们最开始还是测试php文件,看来是有黑名单。
我们这里尝试绕过黑名单,比如.phtml .phps .php5 .pht
,但是执行这种文件有条件,需要我们apache中的httpd.conf配置有如下代码:
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
这里我们没有配置这个参数,所以我们可以在虚拟机中的phpstudy中配置一下
首先:在phpstudy中点击其他选项->配置文件->httpd.conf,然后找到这一行,把注释删掉。
我们在这里上传.phtml类型的文件,尝试绕过其黑名单。
完成上传,我们尝试访问,成功。
http://192.168.252.130/upload/202007120956534008.phtml
Pass-04
我们首先还是尝试上传php文件,返回不允许上传此文件,我们接着将上传类型改为图片尝试,失败。
这一关我们尝试上传.htaccess文件,.htaccess文件(或者"分布式配置文件"),全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
概述来说,htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,我们可以让其将.jpg文件当做php文件来解析,所以我们可以尝试上这个文件,文件中的代码如下:
SetHandler application/x-httpd-php
成功上传:
接着我们直接上传一个后缀为jpg的shell文件,访问成功执行。
http://192.168.252.130/upload/1.jpg
我们本关测试完成之后记得把这个文件删除,因为这个文件会将这个文件夹下的所有文件当做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");
$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 = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
我们看了源码之后发现,phtml已经被过滤掉了,而且有大小写转换,但是没有过滤.htaccess文件,我们依靠这个漏洞完成了上传。
Pass-05
这一关,我们还是首先尝试上传php文件失败,图片类型失败,pthml类型失败,.htaccess文件失败。
经过测试前几个关卡的,都已将失效我们可以分析一下源码。
$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 = 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 . '文件夹不存在,请手工创建!';
}
}
我们看到源码之后首先看到黑名单中已经把.htaccess文件过滤掉了,但是我们发现这一关中后续处理过程出现了问题,没有将大小写统一转换,所以我们可以使用将后缀大小写转换来绕过,知道这一点之后我们就开始上传。
上传成功,尝试访问,成功:
http://192.168.252.130/upload/202007121018029172.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");
$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 . '文件夹不存在,请手工创建!';
}
}
我们可以看到,这次的大小写转换也已经添加,所以大小写的方法已经失效,但是我们发现,其去除空格的部分去掉了,我们可以尝试在后缀添加一个空格来绕过过滤。
开始上传,成功。
访问连接,成功执行。
http://192.168.252.130/upload/202007121026313857.php
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");
$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 . '文件夹不存在,请手工创建!';
}
}
这一关的套路是把之前多文件名中多余的点去除的那一项给删除了,导致没有去除多余的点,我们可以尝试在上传的时候在最后添加一个多余的点,这样它使用strrchr拿到最后一个点之后的内容就不是我们的后缀,而在windows系统中,会自动将文件名后缀最后多余的点删除,我们可以利用这一点。
开始上传:
成功上传,我们尝试访问链接,成功:
http://192.168.252.130/upload/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");
$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
,我们可以使用windows文件流的特性,这个必须结合php使用。php+windows的情况下如果文件名中包含::$DATA
,会把::$DATA
之后的数据当成文件流来处理,不会检测后缀且保持::$DATA
之前的文件名。
我们就在后面添加::$DATA
来尝试绕过
成功上传,我们尝试访问链接,成功执行php代码
http://192.168.252.130/upload/202007121131412162.php::$data
但是在访问的时候我们需要注意,将::$DATA
去掉才能正确访问。
Pass-09
我们还是尝试先分析源码:
$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 . '文件夹不存在,请手工创建!';
}
}
在这里我们首先发现文件名使用的是我们上传时候的原始文件名,而不是像之前随机生成文件名,然后加上我们的后缀,我们在根据其之前的过滤规则,我们可以找出入下绕过手法,首先其会过滤掉点,然后过滤过滤::$DATA
和空格,所以我们可以构造出1.php. .
尝试上传:
尝试访问链接,成功:
http://192.168.252.130/upload/1.php.
在尝试这一关上传的时候,我使用了1.php.::DATA.
的方式进行了上传,最终上传成功的文件名是1.php.
,奇葩的是这个文件无法打开,无法删除,只要一删除就提示不存在:
所以建议不要使用这种方式测试上传(靶机win7)。
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","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);
$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 . '文件夹不存在,请手工创建!';
}
}
我们看到源码之后,我们发现这一次的过滤是直使用str_ireplace函数将黑名单中的后缀进行替换,但是我们发现了问题所在
str_ireplace() 函数替换字符串中的一些字符(这个不区分大小写,str_replace() 区分大小写)。
该函数必须遵循下列规则:
如果搜索的字符串是一个数组,那么它将返回一个数组。
如果搜索的字符串是一个数组,那么它将对数组中的每个元素进行查找和替换。
如果同时需要对数组进行查找和替换,并且需要执行替换的元素少于查找到的元素的数量,那么多余元素将用空字符串进行替换
如果是对一个数组进行查找,但只对一个字符串进行替换,那么替代字符串将对所有查找到的值起作用。
经过我们测试,它仅仅会对字符串从头到尾做一次审查,测试结果如下:
第一种有多个匹配结果,全部替换,第二个只有一个匹配结果,但是替换之后又生成一个匹配的结果,但是没有进行替换,我们可以使用这这种方式进行绕过。
成功上传,我们尝试访问链接,成功。
http://192.168.252.130/upload/1.php