安全-Pass04之.htaccess绕过(upload-labs)
Posted 小狐狸FM
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安全-Pass04之.htaccess绕过(upload-labs)相关的知识,希望对你有一定的参考价值。
文章目录
前言
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
、.htaccess
、phP
等
但是如果采用了小写的转换时,PHP
和phP
就没办法大小写绕过了
".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). 首尾去空
trim($file_ext)
删除$file_ext
变量首尾的空白符- PHP: trim - Manual
//代码
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). 移动临时文件
- 剩余的代码仅是用于移动上传的文件,没有对文件进行过滤操作
- PHP: move_uploaded_file - Manual
//代码
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绕过
- 我本地的靶场环境有点问题,使用的是BUUCTF的靶场
.htaccess
文件,这种文件用于配置网页信息,可以设置重定向页面、设置默认文档等功能。- upload-labs在线靶场-BUUCTF
htaccess 百度百科
- 现在对
.htaccess
的命令还不大了解,命令是参考的upload-labs第四关 pass-04 htaccess绕过- 作用是将当前目录下的
test4.jpg
文件当成php文件来处理
<FilesMatch "test4.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
先上传一个
.htaccess
文件到服务器
然后上传一个一句话木马的文件,文件名称需要和
.htaccess
中写的一致以上是关于安全-Pass04之.htaccess绕过(upload-labs)的主要内容,如果未能解决你的问题,请参考以下文章