upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。github地址:https://github.com/c0ny1/upload-labs

靶机包含漏洞类型分类:

如何判断上传漏洞类型:

以下是我做题的过程,建议首先黑盒测试,做不出的题再看源码。

pass-01 前端过滤

首先上传一个php文件,很快显示该文件不允许上传,请上传.jpg|.png|.gif类型的文件,当前文件类型为:.php,说明前端有过滤,先将文件名改为jps,再抓包改为php即可。(也可以在浏览器禁用修改js,或者自写html调用上传接口)

pass-02 Content-Type限制

直接上传jpg后缀的文件,burp抓包改回php格式,直接成功上传,这里应该是Content-Type验证,在上传jpg格式的时候,Content-Type默认为image/jpeg

pass-03 文件后缀黑名单

和上题一样的做法,显示是提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!,应该是文件后缀黑名单。修改后缀为php5,上传成功。在upload文件中查看,发现其还改了文件名。查看源码如下:

$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 . '文件夹不存在,请手工创建!';}
}

能够解析php5前提是apache的httpd.conf中有如下配置代码

AddType application/x-httpd-php .php .phtml .phps .php5 .pht

pass-04 htaccess修改配置绕过

这一次还是黑名单,但是黑名单加多了:

$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");```几乎过滤了各种后缀,但是没有过滤`.htaccess`。首先上传`.htaccess`,文件内容```
AddType application/x-httpd-php .ppp

然后上传ppp文件,就会被解析成php。

.htaccess还可以写成:

<FilesMatch "shell.ppp">SetHandler application/x-httpd-php
</FilesMatch>

这样文件名为shell.ppp就会被解析成php。(此题相应的未改上传的文件名,应该就是为了这种方法)

pass-05 后缀大小写绕过黑名单

这题还是后缀黑名单过滤,也过滤了.htaccess,但是没有将文件后缀名转换为小写,故大写绕过即可。

pass-06 文件名后添加空格绕过黑名单

查看源码,发现少了:

$file_ext = trim($file_ext); //收尾去空

这样我们可以在文件名后缀加上空格,来绕过黑名单的过滤。

pass-07 文件名后面加.绕过黑名单

查看源码,少了:

$file_name = deldot($file_name);//删除文件名末尾的点

少了对点的过滤,因此直接在文件名后面加上.即可。

pass-08 文件名后加::$DATA绕过

查看源码,没有对字符串::$DATA的过滤

$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA

直接在文件名后面加上::$DATA即可。这种方法仅适用于windows,原理参考: - https://www.owasp.org/index.php/Windows_::DATA_alternate_data_stream - https://bbs.pediy.com/thread-246118.htm

pass-09 文件名后加.[空格].绕过

首先需要了解deldot函数,当deldot函数检测到末尾的第一个点时将继续从后向前检测,当检测到空格时就停下来,因此当后缀是php.[空格].时,经过deldot函数过滤后,后缀变成php.[空格],最终绕过黑名单,且上传上去的文件名为php.,在windows下会自动去除点。

上面的题目应该也都适用这种方法。

此方法也是,仅适用于windows。

pass-10 双写后缀绕过黑名单替换

查看源码,遇到黑名单替换为空(现实中应该遇不到吧),双写后缀即可。

pass-11 %00截断

采用白名单模式,并且改了名字。。。

$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类型文件!";}
}

看起来似乎无法绕过了,看了wp这题时%00截断。

在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。

但是只存在于php5.3.4以下,属于鸡肋方法吧。】

pass-12 %00截断

同样是%00截断,但是这次不同的是save_path在post包里面,GET是可以把url自动转码的,但是POST方式不会自动将%00编码为空字符。

因此,我们需要在burp中选中%00右击->url->urldecode go即可。

pass-13 图片马

题目的要求是上传图片码,并不要求能够解析,所以上传成功即可

先看源码:

function getReailFileType($filename){$file = fopen($filename, "rb");//打开文件$bin = fread($file, 2); //只读2字节fclose($file);$strInfo = @unpack("C2chars", $bin);  //用unpack对二进制数据进行解包,C代表无符号字节型,后面的2代表个数,也可以用*代替  $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); //把两个chars连接起来再用intval转换为整数型   $fileType = '';    switch($typeCode){      case 255216:            $fileType = 'jpg';break;case 13780:            $fileType = 'png';break;        case 7173:            $fileType = 'gif';break;default:            $fileType = 'unknown';}    return $fileType;
}

直接构造图片码即可。

copy a.jpg/b + a.txt = a1.jpg

或者用二进制编辑器打开图片,在末尾添加一句话木马。

pass-14 图片马

换个种方式来验证文件是否为图片:

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){ //如果属于$types中的一个return $ext;}else{return false;}}else{return false;}
}

采用上题的图片马即可。

pass-15 图片马

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;}
}

换检测方法也没用啊,还是常规的图片马。

pass-16 图片马

将上传的图片通过imagecreatefromjpeg二次渲染生成了新的图片。相当于是把原本属于图像数据的部分抓了出来,再用自己的API 或函数进行重新渲染在这个过程中非图像数据的部分直接就隔离开了。详细的绕过解释可参考https://xz.aliyun.com/t/2657

pass-17 条件竞争

看源码:

$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 = '上传出错!';}
}

首先将文章上传,然后判断后缀是否是图片,如果不是图片文件则将其删除。

只要利用竞争上传,上传的php文件内容为写入shell文件,然后不断的访问该文件,只要访问成功,便可以写入shell,直接利用burp的intruder模块上传文件,同时不停的访问这个文件。

pass-18 条件竞争

//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 1if( $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 fileif( $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" );}
......
......
......
};

程序调用了一个MyUpload类,来判断即文件的状态,和上题一样,但是程序会首先调用isUploadedFile来判断是否属于白名单,然后会一步一步检查文件大小、文件是否存在等等,将文件上传后,对文件重新命名,同样存在条件竞争的漏洞。可以不断利用burp发送上传图片马的数据包,由于条件竞争,程序会出现来不及rename的问题,从而上传成功。

pass-19 利用/.绕过

$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 . '文件夹不存在,请手工创建!';}
}

上传文件和文件名可控,且文件名是黑名单限制。

题目有两种做法

  • 文件名改为19.php/.,move_uploaded_file函数遇到/.的时候会删除它。
  • 利用00截断绕过,参考CVE-2015-2348,应该是作者意图,我windows换个几个版本都没成功,应该是只能在linux上才能成功,可参考https://www.cnblogs.com/cyjaysun/p/4390930.html

pass-20 利用/.绕过

$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 = "请选择要上传的文件!";
}

对MIME和文件后缀都进行了检查。 但是取后缀的时候判断$file是不是数组,可以让$file为数组来绕过$file = explode('.', strtolower($file));

最后上传的时候文件名取的是$file_name = reset($file) . '.' . $file[count($file) - 1];

综上,$file数组["20.php","","jpg"],最后一个为jpg可以绕过白名单检查,文件名为:20.php.,再配合move_uploaded_file的特性,最终上传的文件名为20.php

中upload依赖包_upload-labs writeup相关推荐

  1. 使用govendor灵活管理Go程序中的依赖包

    业务痛点 使用Go开发程序的过程中,为了方便开发,往往会引用很多标准库或者第三方的依赖包,第三方依赖包往往比标准库功能更全面更强大更接地气,那么如何管理众多的第三方依赖包呢?如何更新其版本?在不需要时 ...

  2. pycharm中导出依赖包 在pycharm下边的Terminal打开命令行终端执行命令

    pycharm中导出依赖包 1 在pycharm下边的Terminal打开命令行终端执行命令 D:\nlp\salary\aSalary>pip freeze > d:\nlp\salar ...

  3. dependency报红_解决IDEA中Maven依赖包导入失败报红问题(总结最有效8种解决方案)...

    问题描述: 真的,说来话长,这应该是我花最多时间去解决关于Maven依赖包导入的问题,以前粘贴复制导入,自动下载成功了, 这次怎么搞,怎么让他自动下载都还是红红的一片, 花了大半天,各种尝试,只为搏得 ...

  4. jcenter库中的依赖包无法下载

    jcenter库中的依赖包无法下载 react-native打包失败 解决办法 react-native打包失败 今天突然发现react-native项目打包失败,仔细查看发现是因为jcenter库中 ...

  5. IDEA中Maven依赖包无法下载,maven使用阿里源无法Could not transfer artifact xx.xx from/to alimaven(aliyun)-

    方式一: 大部分人会有这种问题,直接修改即可,请参考持.之.以.恒 IDEA中Maven依赖包无法下载或导入问题解决办法 二 maven使用阿里数据源不能生效,如这种 Could not transf ...

  6. 在IDEA中为项目引入maven中央仓库中的依赖包

    如果是maven项目直接在pow.xml文件中引入依赖即可,这些依赖包将会下载到maven配置好的仓库中.但是有些时候我们并不希望其下载到全局的仓库中而是只在项目中使用,或者项目根本不是maven项目 ...

  7. IDEA中Maven依赖包下载不了的问题解决方案汇总

    这个依赖包下载不了的问题真的是很烦,之前一直把下载不上的依赖剪切再粘贴到pom.xml文件中,保存它就自动下载了,但是今天怎么剪切粘贴都没用,所以就花了点时间在网上各种搜解决方案,试了一些之后终于从根 ...

  8. ssm+shiro+jsp标签。关键字:shiro的jsp标签,访问拦截。本次ssm和以前的ssm整合中的依赖包不一样。写根据不同用户出现不同的按钮内容就用这shiro标签来解决。Set集合在sql中

    shiro标签只能在jsp和ftl页面文件中使用,无法在html文件中使用 shiro认证后的在jsp页面中的标签: 使用shiro标签就一定要搭配shiro框架使用,即一定要有自定义realm,因为 ...

  9. maven-项目中引入依赖包

    maven项目中引入testng.selenium,在pom.xml中添加 <dependencies><dependency><groupId>org.testn ...

最新文章

  1. Palo Alto 亚太区首席安全官:未来中国五大安全问题突出...
  2. linux下创建和删除软、硬链接
  3. 好代码是管出来的——使用Jenkins搭建CI服务器
  4. 避免流量高峰期CDN问题的10个方法
  5. 北大核心期刊2012《科技通报》杂志简介《科技通报》论文范文
  6. ASP静态HTML(局部)生成类
  7. JAVA虚拟机垃圾回收算法原理
  8. React 开发常见报错解决方法
  9. [渝粤教育] 泉州师范学院 弦管传奇 古乐南音 参考 资料
  10. WhereHows 数据发现和管理工具
  11. 使用spreadjs vue版本
  12. 用iPad编写C/C++代码(计算机考研党也能用iPad写算法题)
  13. 一 、单片机IO实验
  14. 2018拼多多校招笔试贪心编程题小熊吃糖详解
  15. SQL查询优化方法 提高SQL查询效率 数据库的哪些字段适合添加索引
  16. 自主研发编程语言Mulan(木兰)评测(附视频讲解)
  17. RabbitMQ 进阶 -- 阿里云服务器部署RabbitMQ集群
  18. Oracle实现金额小写转大写函数
  19. 云速建站:关于企业版的几点说明
  20. __getattr__和__setattr__

热门文章

  1. 苹果官网下架 iPhone 8 全系;阿里推出“阿里云会议”;深度操作系统 20 BETA 发布 | 极客头条...
  2. 远程办公 4 大坑,坑坑“致命”!
  3. 钉钉辟谣“老师能打开学生摄像头”;HTC 关闭官方社区;​Node.js 安全版本发布 | 极客头条...
  4. “不会Linux,怎么当程序员?”面试官:等着被淘汰吧!
  5. 4599 的 iPhone 11,拼多多如何从「真香」到「更香」
  6. 你的 App 在 iOS 13 上被卡死了吗?
  7. 横扫阿里、滴滴、美团后,阿里程序媛整理出这份厚厚的面经!
  8. 揭开 Python 内存分配时的小秘密!
  9. BAT 为首的中国互联网公司为何陷入技术焦虑的怪圈?
  10. 前端很慌!React 称霸,Vue 凶猛,TypeScript 威逼 JavaScript