c0ny1/upload-labs
c0ny1/upload-labs是一个文件上传漏洞靶场,地址:https://github.com/c0ny1/upload-labs
以docker方式安装并启动,在这里我启动的是81端口,可以自行设置端口:
$ docker pull c0ny1/upload-labs
$ docker run -d -p 81:80 upload-labs:latest
启动后,打开靶场 127.0.0.1:81,可以看到一共有20关:
upload-labs
创建upload文件夹
随意上传一个png文件进行测试,提示“../upload文件夹不存在,请手工创建!”
提示
进入docker容器创建文件夹
### 查看运行的docker id
docker ps -a
### 进入docker bash
docker exec -it dockerId /bin/bash
### 在 /var/www/html路径下创建upload文件夹
mkdir upload
### 修改文件夹的所有者为 www-data:www-data
chown www-data:www-data upload
此时重新上传png图片,能够成功上传。
成功上传
Pass-01
随意上传一个php文件,可以看到提示只允许上传.jpg .png .gif
类型的文件,属于白名单检测
将一句话木马文件名修改为test.png
,抓包获取数据包,修改文件后缀为.php
,判断是否只是前端验证,以及能够控制的输入是什么
从数据包中可以看到,能控制的输入是文件名,修改文件后缀为.php
可以看到能够成功上传,进行元素审查,获取上传的路径为
../upload/test.php
上传结果
浏览器访问
../upload/test.php
,能够成功访问访问成功
使用curl,执行post请求访问一句话木马,可以看到成功执行
访问一句话木马执行成功
查看源码
从源码中看,在前端进行了后缀检测
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;
}
}
Pass-02
随意上传.php文件,提示文件上传类型不正确
随意修改文件后缀为
.php3 .phpt .phptml .123
判断是否是黑名单,发现提示均为文件类型不正确
,上传.png
,可以成功上传,猜测应该为白名单检测,且是后台进行检测。抓包查看数据包,发现仅能控制文件名,不能控制文件后缀。
对文件名后缀尝试00截断,能够成功上传,且能够成功访问我们的一句话木马
文件名尝试00截断
查看源码
查看源码发现,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.'文件夹不存在,请手工创建!';
}
}
再次尝试,抓包,修改文件类型,文件名仍为test.php
,可以看到能够成功上传。
Pass-03
随意上传php文件,提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!
尝试修改后缀名
修改文件后缀为.php3
,能够成功上传,进行图片审查,找到文件路径,可以看到这里对文件进行了重命名
访问
../upload/202212121105064700.php3
,发现服务器把该文件当作文本文件进行处理,无法对.php3
后缀进行解析。服务器无法解析.php3后缀
尝试.htaccess
上传
上传.htaccess
文件
查看上传结果,可以看到成功上传,但是文件名被修改,该方法失败
上传结果
尝试大小写绕过
修改文件后缀为.pHp
上传失败,提示:
不允许上传.asp,.aspx,.php,.jsp后缀文件!
查看源码
查看源码,可以看到对文件后缀名进行了大小写转换和黑名单限制
$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 . '文件夹不存在,请手工创建!';
}
}
在网上查看了一些通关方法,发现都是修改文件后缀名为.php3 .php5 .phpt
等特殊后缀,同时修改服务器的解析配置让服务器能够解析这样的特殊后缀。
如果是这样,尝试的第一种方法就对了,有疑问的是在实战中是无法直接修改服务器的解析配置的,那么这种方法也就无效了。
Pass-04
随便上传php文件,提示 :此文件不允许上传
随便上传.test
后缀的文件,可以成功上传,且文件名没有被修改
上传.htaccess文件,文件内容为:AddType application/x-httpd-php .test
,成功上传
访问phpinfo.test,可以看到成功访问,成功绕过
访问phpinfo.test
查看源码
查看源码,代码限制了特殊后缀,对后缀进行了大小写转换,去除了末尾加点。
文件名没有被修改,如果文件名被修改,.htaccess文件就不能被成功利用。
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.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
注意:这里直接点击页面的显示源码
,显示的是下面的代码,在下面的代码里,文件名被随机修改,如果是这样,那么.htaccess文件上传是不能被利用的,进入docker容器,查看Pass-04的实际代码,是上面的代码,没有修改文件名,注意这里的差别。
$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 . '文件夹不存在,请手工创建!';
}
}
Pass-05
随意上传.php文件,提示:此文件类型不允许上传
首先尝试一遍黑名单检测绕过的方法,大小写、特殊后缀、.htaccess等方法,发现都不可以上传;
尝试白名单检测绕过的00截断方法,查看数据包,只能够控制文件名,尝试进行文件名00截断,无法绕过;
尝试apache解析漏洞绕过,上传
.php.abc
后缀上传.php.abc后缀
可以成功上传,但是文件名被修改为
xxx.abc
,文件名被随机修改,文件后缀为.abc
成功上传
猜测文件源码为获取最后一个点后面的后缀名,然后进行随机命名。
没有思路,最后看了别人的通关方法,发现是最简单的大小写绕过,.Php
即可绕过,自己在尝试时只尝试了.pHp
,所以以后要多尝试,或者可以尝试使用自动化工具进行尝试。
查看源码
从源码中可以看到,进行了各样的限制,包括.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 . '文件夹不存在,请手工创建!';
}
}
Pass-06
随意上传php文件,提示:此文件不允许上传
尝试各种后缀绕过,发现无法绕过
尝试文件名00截断,提示:此文件不允许上传
尝试apache 解析漏洞,上传.php.test
后缀,apache解析漏洞在无法解析后缀时会向前进行解析,直到遇到能解析的后缀为止。
该文件能成功上传,文件名被修改
访问上传的文件,可以看到文件被解析为.php文件
成功访问
查看源码
$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 . '文件夹不存在,请手工创建!';
}
}
看了别人的通过攻略,都是在文件末尾加空格, 可以进行绕过,文件能够上传,源码里缺少了对空格的检测,自己动手实际操作了一下,文件确实可以上传成功。
上传.php
在浏览器里进行访问,发现文件以文件格式被解析,并没有以php的格式被解析。这里注意空格要进行url编码,输入%20,否则无法识别。
文件无法被解析
再次查看了其他人的通关攻略,可能是版本的原因,说是windows在存储时会自动去掉空格,所以能够成功解析。我的是docker版本,所以可能这是没有绕过的原因。
Pass-07
随意上传.php文件,提示:文件类型不允许上传
在文件名后缀加一个.
,比如上传文件名为test.php.
,即可上传成功
(我这里依旧是不能解析这个.结尾的文件)
查看源码
$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 . '文件夹不存在,请手工创建!';
}
}
从源码看,限制了对文件后缀点的限制。
Pass-08
这一关考察windows文件流特性。
在文件名后缀加上::$DATA
,比如test.php::$DATA
,能够成功上传。
windows文件流可以绕过后缀名的检查,且不改变文件内容。
源码:
$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 . '文件夹不存在,请手工创建!';
}
}
可以看到,源码确实去掉了windows文件流特性的检查。
Pass-09
这一关代码把所有的限制都加上去了,查看源码和通关攻略可知,虽然代码对后缀进行了全面的限制,但是在拼接文件路径时,使用的是上传的文件名进行拼接,这样就有了操作的空间,可以对文件名进行构造来绕过限制。
源码
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 . '文件夹不存在,请手工创建!';
}
}
代码先对后缀名进行检查和转化,最后拼接路径时,使用上传的文件原名进行拼接,对文件名进行处理的是下面两行代码,因此只要绕过下面两行代码即可。因此选择对文件名进行构造,比如test.php. .
即可上传成功且访问成功。
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
Pass-10
首先上传一个文件名为phpinfo.php
的文件,成功上传,查看文件路径,发现文件名为info.
查看提示可知,代码会去除文件名中相应的字符。
对文件名进行构造即可,构造
info.pphphphpp
,即php三个字符中间夹杂一个php,这样等程序去除php后,留下来的仍然是php后缀,经测试,能成功上传且访问image.png
源码
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 . '文件夹不存在,请手工创建!';
}
}
网友评论