Upload-Labs靶场
第一关 js 绕过
源码如下:
lasIndexOf是返回函数最后一次出现的地方(从右到左)
substring是用来截取函数的
indexOf是返回
表示从.出现的地方开始截取并判断是否在允许的字符串内
绕过方法:
直接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.'文件夹不存在,请手工创建!'; } }
判断文件类型是否为图片
绕过方法
通过burp捉包修改Content-Type:
上传php文件
第三关
采用黑名单限制
上传后文件保存为路径加时间加随机数加后缀
绕过方法
使用别名php3,php5,phtml进行绕过
首先打开phpstudy工具中的httpd.conf文件进行修改使他解析别名
上传php文件并修改后缀
第四关
增加了对别名的过滤
文件保存为路径加上传文件名
绕过方法
上传.htaccess文件(注: .htaccess文件生效前提条件为1.mod_rewrite模块开启。2.AllowOverride All)
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能IIS平台上不存在该文件,该文件默认开启,启用和关闭在httpd.conf文件中配置。
文件内容为AddType application/x-httpd-php .jpg使jpg文件用解析成php
第五关
与前面相比这一关的过滤代码缺少了将后缀转换成小写的代码
绕过方法
后缀使用大小写绕过
第六关
这一关少了首位去空的代码
绕过方法
在window下1.jpg[空格] 和1.jpg.是不允许存在的,会强制删除空格和.
第七关
少了删除文件名末尾的点
绕过方法
和第六关差不多不过这次换成了点
第八关
少了去除::$data的代码
绕过方法
这道题利用的是Windows下NTFS文件系统的一个特性,即NTFS文件系统的存储数据流的一个属性 a.asp::DATA 时,就是请求 a.asp 本身的数据,如果a.asp 还包含了其他的数据流,比如 a.asp:lake2.asp,请求 a.asp:lake2.asp::$DATA,则是请求a.asp中的流数据lake2.asp的流数据内容。
简单讲就是在php+windows的情况下:如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名.且保持"::$DATA"之前的文件名。
第九关
这里的代码逻辑是先删除末尾点,在截取点后面的字符串,将字符串转换成小写并首尾去空
绕过方法
这里我们可以使用点空格点的形式,同样利用了window下的特性,如果我们是在window下的环境那么3-9都可以利用点空格点
burp修改后缀为1.php为1.php. . 过滤后为1.php.
浏览器访问1.php.实际访问的是1.php可以直接访问1.php
第十关
代码中只是对敏感后缀进行了一次替换
绕过方法
对后缀进行双写如 pphphp
第十一关
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置
substr() 函数返回字符串的一部分
文件保存的方式是上传路径+随机时间+截取的文件后缀
其中上传路径可控,可以利用这一点
$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 . '文件夹不存在,请手工创建!';
}
}
绕过方法
利用00截断进行绕过,即move_uploaded_file函数的底层实现类似于C语言,遇到0x00会截断
截断条件:
1、php版本小于5.3.4
2、php.ini的magic_quotes_gpc为OFF状态
第十二关
和上一个关一样不过路径上传方式由GET变成POST
绕过方法
00截断 post方式中需要修改成二进制的00而不是直接在请求数据中修改00
#在二进制中为23,为了好找,下一步在hex将23改成00
修改成00后会在数据包显示像口这样的字符
第十三关
读取上传文件中的两个字节
将读取的内容解包(unpack() 函数从二进制字符串对数据进行解包返回数组一个字节为一个值)
返回解包后的整数值(intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值)
绕过方法
我们在一句话木马的开头添加两个11也就是二进制的3131,将HEX
编码 3131 改为 FFD8 点Go
后成功上传JPG
上传了马后缀为jpg想要利用需要配合另一种漏洞文件包含,靶场专门有一个文件让我们测试文件内容为
第十四关
getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组
索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
stripos — 查找字符串首次出现的位置
绕过方法
与上一关一样使用图片马
第十五关
exif_imagetype() — 判断一个图像的类型
返回值:
图像类型常量 值 常量
1 IMAGETYPE_GIF
2 IMAGETYPE_JPEG
3 IMAGETYPE_PNG
4 IMAGETYPE_SWF
5 IMAGETYPE_PSD
6 IMAGETYPE_BMP
7 IMAGETYPE_TIFF_II(Intel 字节顺序)
8 IMAGETYPE_TIFF_MM(Motorola 字节顺序)
9 IMAGETYPE_JPC
10 IMAGETYPE_JP2
11 IMAGETYPE_JPX
12 IMAGETYPE_JB2
13 IMAGETYPE_SWC
14 IMAGETYPE_IFF
15 IMAGETYPE_WBMP
16 IMAGETYPE_XBM
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 = "上传出错!";
}
}
}
绕过方法
本关一样使用图片马
第十六关
图片经过渲染肯定与原来的照片不一样了
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 = "上传出错!";
}
}
}
绕过方法
最简单的GIF图片
合成图片马上传,在把上传后的图片保存下来会发现一句话不见了,把图片马和下载下来的图片进行对比找到没有渲染的部分直接将一句话写进去
1.gif是我一开始上传图片马对比上传后的图片找出来一段没有经过修改的,我把其中一段空白修改成一句话代码,注意图片会失真
左边.gif是我上传修改后的1.gif保存的可以看到一句话完整的保存了下来
第十七关
通过move_uploaded_file保存文件在判断是否后缀是否是图片,如果是则重命名保存,如果不是删除
$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的图片文件!";
}
}
绕过方法
上传一个php文件里面代码进行创建一个新的文件
用burp捉包,选择爆破那个模块原包发送5000次,线程50
访问上传的文件
同样再发5000个请求包去访问未删除前的地址,一但成功则会生成一个shell文件
当请求页面返回200停止,此时由于我们代码理有生成shell文件,所以直接访问
第十八关
对文件后缀名做了白名单判断,然后会一步一步检查文件大小、文件是否存在等等,将文件上传后,对文件重新命名,同样存在条件竞争的漏洞。可以不断利用burp发送上传图片马的数据包,由于条件竞争,程序会出现来不及rename的问题,从而上传成功
import requests
url="http://127.0.0.1/upload-labs/upload/37.php"
while True:
web_result=requests.get(url)
if web_result.status_code == 200:
print("Success")
break
else:
print("Failed")
绕过方法
本Pass先创建了一个只包含图片文件的白名单,随后提取出文件的后缀名,将文件移动至上传目录后再判断是否合法,不合法就删除。我们可以使用条件竞争方法(即在文件被删除之前访问该文件)绕过。此方法需要不停且迅速地上传、访问文件。
第十九关
文件名可控,
pathinfo() 返回一个关联数组包含有 path 的信息。
包括以下的数组元素:
- [dirname]
- [basename]
- [extension]
绕过方法
使用点加空格 1.php. 获取到的后缀为点空格 在window中点空格默认会去除所以剩下1.php
第二十关
先检查文件类型,后检查是否上传了文件名没有则为文件的名字,判断是否为数组,若不是则以点分割返回一个数组,取数组最后一位数为后缀,文件保存为reset输出数组第一个数,和最后一位数保存
绕过方法
php修改后缀jpg上传捉包
文件类型已经为image/jpeg
修改上传路径为一个数组,当获取文件后缀时为jpg,合成文件名为数组第一个,和最后一个,当我们修改jpg为数组的2时,1此时是空的数组一共有三位数,但是实际只有两位,所有获取到的值为空
此时上传后的文件为1.php.
第二十一关
$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 = "请选择要上传的文件!";
}
1.验证MIME类型(这个很好解决)
2.验证文件名。
验证文件名操作如下:
1.empty()配合三运运算符检查文件名是否为空。
2.如果$file不为数组则将$file打散为数组。(这很关键)
3.end()函数提取数组最后一个元素为后缀名。
4.确定白名单
5.将文件名设置为数组索引为零的元素与数组索引为元素总个数减一的元素合并。
6.上传、改名、移动。
第二步使用if判断$file是否为数组,是则跳过,不是则打散为数组。所以我们可以在上传中途控制save_name参数,随意操作POST数组索引进行绕过,这样$file已经是数组,不会被重新打散。
操作:
先将Content-type改为image/jpeg
reset()取数组索引为0的元素为文件名,所以将save_name[0]设置为“37.php”。
save_name[1]不设置,使count()结果为2。
save_name[2]为jpg。
拼接结果为37.php,$ext值为jpg。