安全-Pass11之黑名单双写绕过(upload-labs)

Posted 小狐狸FM

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安全-Pass11之黑名单双写绕过(upload-labs)相关的知识,希望对你有一定的参考价值。

前言

  • phpHypertext Preprocessor超文本预处理器,多用于web后端
  • BUUCTF的upload-labs在线靶场和本地的靶场有点差别,如果用文章的方法没法绕过时,注意看一下源码是否一致

相关介绍

PHP 百度百科

PHP: PHP 手册 - Manual

其他介绍

文件上传绕过思路集合

upload-labs靶场下载

upload-labs在线靶场-BUUCTF

蚁剑AntSword

菜刀Cknife

Seay

一、题目


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

二、WriteUp

[1]. 函数介绍

PHP函数介绍
file_exists(路径)判断指定的文件或目录是否存在,不存在返回true,否则返回false
isset(变量)如果变量存在且值不为null返回true,否则返回false
move_uploaded_file(文件路径,文件夹路径)将文件移动到指定文件夹下
str_ireplace(字符串1,字符串2,字符串3)在字符串3中搜索,如果含有字符串1的子串就替换成字符串2
trim(字符串)删除字符串前后的空白符,空白符: 空格、制表符(\\t)、换行符(\\n)、回车符(\\r)、空字节符(\\0)和垂直制表符(\\x0B

[2]. 源码审计

(1). 变量判断

  • php代码进行审计,if语句比较多最好从外往内分析
  • 第一条if语句只是判断了一下提交的post请求中submit参数是否被设置且非空
    PHP:isset - Manual

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {//第一条if语句
	//代码
}

(2). 路径判断

  • 第二条语句判断了一下文件上传的路径存不存在,存在的话就执行里面的代码,不存在就给$msg设置回显信息
  • 通过Seay审计的全局搜索功能可以找到UPLOAD_PATH是在config.php中被定义的
    Pass-02\\index.php的代码中包含了上一级目录下的config.php
    然后这个变量就可以在Pass-02\\index.php中直接使用
  • ../表示访问上一级的目录,所以upload-labs-master\\Pass-02\\index.php包含的是upload-labs-master\\config.php
  • UPLOAD_PATH变量在upload-labs-master\\Pass-02\\index.php中被调用时,就会设置上传的父文件夹为upload-labs-master\\upload

$is_upload = false;
$msg = null;
if (xxx) {//第一条if语句
    if (file_exists(UPLOAD_PATH)) {//第二条if语句
    	//代码
    }else {//第二条if语句为假
        $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    }
}

(3). 黑名单

$deny_ext是一个数组类型,存储了需要被过滤的后缀名

"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"
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	$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");
		//代码
   	}else {//第二条if语句为假
        //代码
    }
}  

(4). 首尾去空

  • $_FILES['upload_file']['name']会获取上传文件的名称,如下图的test3.txt
  • trim($_FILES['upload_file']['name'])就是删除文件名称首尾的空白符,然后赋值给变量$file_name
    PHP:trim - Manual

//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_name = trim($_FILES['upload_file']['name']);
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(5). 黑名单过滤

"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"
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_name = str_ireplace($deny_ext,"", $file_name);
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(6). 文件存储路径设置

  • 在上传文件的时候,文件都会被存储在一个临时的文件夹下
    我们不需要知道具体路径,只需要通过tmp_name参数获取路径即可
    UPLOAD_PATH的值为../upload,在config.php文件中定义
  • PHP: in_array - Manual
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = UPLOAD_PATH.'/'.$file_name;  
        //代码
	}else{//第二条if语句为假
		//代码
	}
}

(7). 移动临时文件

//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        if (move_uploaded_file($temp_file, $img_path)) {//第三条if语句
            $is_upload = true;
        } else {//第三条if语句为假
            $msg = '上传出错!';
        }
	}else{//第二条if语句为假
		//代码
	}
}

[3]. 双写绕过

可以构造一个后缀为.pphphp的一句话木马文件,在服务端处理的过程和结果如下

变量传入的值处理后代码代码作用
$file_nametest11.pphphptest11.pphphp$file_name = trim($_FILES['upload_file']['name'])删除首尾空白符
$file_nametest11.pphphptest11.php$file_name = str_ireplace($deny_ext,"", $file_name)置空操作

因为置空的操作只执行一次,所以删除了一次中间的php字符串后,php仍然组成了.php后缀

复制返回的图片链接并访问,访问成功无报错表示test11.php文件被解析了


使用菜刀或蚁剑连接木马

以上是关于安全-Pass11之黑名单双写绕过(upload-labs)的主要内容,如果未能解决你的问题,请参考以下文章

安全-Pass07之黑名单空格绕过(upload-labs)

安全-Pass08之黑名单点绕过(upload-labs)

安全-Pass09之黑名单::$DATA绕过(upload-labs)

安全-Pass05之黑名单.user.ini绕过(upload-labs)

安全-Pass10之黑名单点空点绕过(upload-labs)

安全-Pass04之.htaccess绕过(upload-labs)