Upload-labs文件上传靶场通关---{更新第16关中}
upload-labs是一个使用php语言编写的、专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共21关,每一关都包含着不同上传方式。
以下是Upload-labs文件上传靶场中包含的文件上传漏洞类型:
注:Upload-labs文件上传靶场的搭建方法请查阅另一篇Blog:基于Ubuntu20.04搭建Upload-labs文件上传靶场。以下通关过程中,为了避免其它因素干扰,大部分关卡采用了upload-labs作者推荐的windows版傻瓜式集成包,个别关卡采用Ubuntu+phpstudy环境。
Pass-01 前端JS限制
首先制作一个一句话木马文件。本次通关中为快速验证靶场通关结果,以phpinfo()函数替代恶意函数。
即输入<?php phpinfo();?>
重命名为phpinfo.php
访问Upload-labs文件上传靶场的Pass-01,选择phpinfo.php文件
点击上传,发现上传失败,提示文件类型非法
将phpinfo.php文件后缀名更改为.jpg,再次上传
抓包修改文件名后缀,将.jpg改为.php,点击Forward
继续点击Forward,注意观察上传请求的路径信息
访问/upload/phpinfo.php,显示如下信息说明已执行了文件中已定义的phpinfo()函数,上传成功。
查看源代码
为了便于理解和上手操作,第1关文件上传流程记录得较为详细。后续将进行简化。
Pass-02 MIME绕过
选择phpinfo.php文件,上传失败,提示如下:
上传phpinfo.php文件,抓包将Content-Type: application/octet-stream
改为
Content-Type: image/jpeg
或
Content-Type: image/png
或
Content-Type: image/gif
此时可成功访问/upload/phpinfo.php。
查看源代码:
Pass-03 特殊后缀绕过黑名单
选择phpinfo.php文件,上传失败,提示如下:
上传phpinfo.php文件,抓包将文件名后缀更改为.phtml
或 .php3
均可。
继续点击Forward,注意观察请求路径中的文件名已重新命名。
此时可成功访问 http://192.168.3.21/upload/202307301634081208.php3,
但是访问原文件名 http://192.168.3.21/upload/phpinfo.php 失败。
查看源代码:
注:本次通关环境为windows版phpstudy、PHP5.2.17,并且Apache httpd.conf中的 AddType application/x-httpd-php .php .php3 .phtml .php5
配置生效。
Pass-04 .htaccess绕过黑名单 {“待更新”}
选择phpinfo.php文件,上传失败,提示如下:
使用上一关Pass-03的篡改文件名后缀为.phtml
或 .php3
的方法也提示失败。
.htaccess {“待更新”}。。。
查看源代码:
Pass-05 大写绕过黑名单
选择phpinfo.php文件,上传失败,提示如下:
将phpinfo.php文件重命名为phpinfo.phP,直接上传,访问成功。
查看源代码:
Pass-06 加空格绕过黑名单
选择phpinfo.php文件,上传失败,提示如下:
抓包在phpinfo.php文件后面加一个空格,直接上传,访问成功。
查看源代码:
Pass-07 加.绕过黑名单
选择phpinfo.php文件,上传失败,提示如下:
抓包在phpinfo.php文件后面添加一个.
不加空格,点击Forward上传。
此次后台未对文件名进行变更,访问 /load/phpinfo.php 或 /load/phpinfo.php. 均可成功。
查看源代码:
Pass-08 加::$DATA
绕过黑名单
选择phpinfo.php文件,上传失败,提示如下:
抓包在phpinfo.php文件后面添加::$DATA
,点击Forward上传。
访问 /upload/202308011129144699.php::$data
显示Fobidden,
访问 /upload/202308011129144699.php
成功。
查看源代码:
Pass-09 加. .
绕过黑名单
选择phpinfo.php文件,上传失败,提示如下:
抓包在phpinfo.php文件后面添加点空格点. .
,点击Forward上传。
访问成功:
查看源代码:
Pass-10 双后缀绕过黑名单
选择phpinfo.php文件,点击上传,未提示失败,但是无法访问。显示如下:
抓包将文件phpinfo.php
的后缀.php
改为.pphphp
点击Forward上传。
此时文件名后缀已经成功绕过,但是文件名中的php也去掉了,最终的文件名为info.php
访问 /upload/info.php
成功
查看源代码:
Pass-11 00截断
选择phpinfo.php文件,上传失败,提示如下:
抓包在第一行的save_path=../upload/
后面添加phpinfo.php%00
Content-Disposition处的form-data; name="upload_file"; filename="phpinfo.jpg"
文件名保持不变,点击Forward上传。
访问/upload/phpinfo.php
成功。
查看源代码:
注:利用00截断的前提条件
php版本小于5.3.4
php的magic_quotes_gpc为OFF状态
Pass-12 00截断
选择phpinfo.php文件,上传失败,提示如下:
抓包在../upload/
处添加phpinfo.php%00,
点击上传后访问失败。
接下来,抓包在../upload/
处添加phpinfo.php=
在Hex视图中找到=
对应的3d
并将其改为00
,点击Forward上传,访问成功。
查看源代码:
Pass-13 图片马 unpack()
首先试试能否上传一句话:选择phpinfo.php文件,上传失败,提示如下:
现在打开cmd窗口,使用copy命令copy OIP-C.jpg/b + phpinfo.php/a picma.jpg
制作.jpg后缀的图片马:
选择刚刚制作好的picma.jpg文件,上传成功。然后右键点击图片,选择“在新标签页中打开图片”,复制图片路径/upload/5220230802121409.jpg
备用。
回到主界面,点击超链接文件包含漏洞,跳转到/include.php
页面。
在include.php
后面添加?file=./
拼接图片路径upload/5220230802121409.jpg
,访问成功。
以下采用另一种姿势、上传.gif后缀的图片马。
将phpinfo.php重命名为phpinfo.gif,点击上传,抓包,在文件内容前添加GIF89A,点击Forward,上传成功。
接下来的步骤和利用.jpg后缀的图片马一样,可成功访问。
查看源代码:
Pass-14 图片马 getimagesize()
使用Pass-13的.jpg .gif
后缀的两种马均可通关。
查看源代码:
Pass-15 图片马 exif_imagetype()
使用Pass-13的.gif
图片马可通关。
查看源代码:
注:本关需开启php_exif功能。
Pass-16 二次渲染
{“待更新”}
查看源代码:
$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的图片文件!";
}
}
Pass-17
{“待更新”}
查看源代码:
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 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" );
}
......
......
......
};
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 . '文件夹不存在,请手工创建!';
}
}
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 = "请选择要上传的文件!";
}
Pass-21
{“待更新”}
查看源代码: