Upload-labs
文章目录
常见函数
strrchr(string,char)
string 必需。规定要搜索的字符串
char 必需。规定要查找的字符。如果该参数是数字,则搜索匹配此数字的 ASCII 值的字符。
返回值:返回从某个字符串在另一个字符串中最后一次出现的位置到主字符串结尾的所有字符
如果未找到此字符,则返回 FALSE
trim(string,charlist)
string 必需。规定要检查的字符串
charlist 可选。规定从字符串中删除哪些字符。如果被省略,则移除以下所有字符:
"\0" - NULL
"\t" - 制表符
"\n" - 换行
"\x0B" - 垂直制表符
"\r" - 回车
" " - 空格
即 如果只放一个变量代表将字符串首尾去空
deldot() 删除文件名末尾的点
strtolower() 函数把字符串转换为小写
str_ireplace()
示例:
把字符串 "Hello world!" 中的字符 "WORLD"(不区分大小写)替换成 "Shanghai":
<?php
echo str_ireplace("WORLD","Shanghai","Hello world!");
?>
date(format,timestamp)
格式化本地日期和时间,并返回已格式化的日期字符串:输出日、日期、月、年、时间 AM 或 PM
format 必需。规定输出日期字符串的格式。
例如:
YmdHis
Y - 年份的四位数表示
m - 月份的数字表示(从 01 到 12)
d - 一个月中的第几天(从 01 到 31)
H - 24 小时制,带前导零(00 到 23)
i - 分,带前导零(00 到 59)
s - 秒,带前导零(00 到 59)
2021 02 13 13 2021 18 77.php
rand() or rand(min,max)
min 可选。规定返回的最小数。默认是 0
max 可选。规定返回的最大数。默认是 getrandmax()
返回值: 介于 min(或 0)与 max(或 mt_getrandmax())之间(包括边界值)的随机整数
substr(字符串,位置,长度)
<?php
$rest = substr("abcdef", -1); // 返回 "f"
$rest = substr("abcdef", -2); // 返回 "ef"
$rest = substr("abcdef", -3, 1); // 返回 "d"
?>
注意:0开始
strrpos(string,find,start)
查找 字符串 最后一次出现的位置
Pass-01
前端限制与绕过
phpinfo.jpg
提交,然后抓包修改后缀名为 .php
Pass-02
服务端验证–MIME类型
上传
phpinfo.php
,抓包,修改 Content-Type: image/jpeg
Pass-03
方法一:黑名单绕过
前提: Apache 配置文件中
#AddType text/html .shtml 后面加上:
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
上传 phpinfo.php5 或者是 phpinfo.phtml
方法二:制作图片木马
Pass-04
由于黑名单过多,基本上将所有能绕过黑名单的选择都考虑到了,但是并没有过滤掉 .htaccess 文件
.htaccess 攻击
在确保 Apache配置文件 httpd.confg 文件当中 AllowOverride All
的情况下
先后上传 .htaccess 文件,hack.png 文件
将所有.png格式的图片都当作.php处理:hack.png
在 .htaccess 文件中写入:
AddType application/x-httpd-php .png
hack.png 中写入:
<?php
phpinfo();
?>
Pass-05
Apache 多后缀文件解析漏洞
上传
phpinfo.php.xxx.xx.x
Pass-06
将 .htaccess 文件过滤掉了,但与之前不同的是,文件名后缀的小写转换去掉了
大小写绕过
上传 phpinfo.PHP
Pass-07
对比之前,少了 $file_ext = trim($file_ext); //首尾去空
空格绕过
上传 phpinfo.php
(有空格)
Pass-08
对比之前,少了 $file_name = deldot($file_name);//删除文件名末尾的点
windows系统下默认,后缀名之后的点不会被执行
点绕过
上传 phpinfo.php.
Pass-09
对比之前,少了 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
windows系统下,如果文件名 + ::$DATA
会把 ::$DATA
之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,他的目的就是不检查后缀名
例如: phpinfo.php::$DATA
Windows会自动去掉末尾的::$DATA变成 phpinfo.php
Pass-10
$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); //首尾去空
$img_path = UPLOAD_PATH.'/'.$file_name;
根据文件后缀处理的顺序,由于并未给上传的文件进行重命名
逻辑绕过
上传 phpinfo.php. .
Pass-11
$file_name = str_ireplace($deny_ext,"", $file_name);
对黑名单当中的文件后缀名处理为空,但是只过滤了一次
双写绕过
Pass-12
白名单:jpg,png,gif
新路径:$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
GET 提交
00截断–GET
条件:php版本小于 5.3.4 且 魔术引号关闭
Pass-13
白名单:jpg,png,gif
新路径:$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
POST 提交
00截断–POST
图片木马
Pass-14
fopen(filename,mode,include_path,context) 函数打开一个文件或 URL。如果 fopen() 失败,它将返回 FALSE 并附带错误信息。您可以通过在函数名前面添加一个 '@' 来隐藏错误输出。
filename 必需。规定要打开的文件或 URL
mode 必需。规定您请求到该文件/流的访问类型
"r" (只读方式打开,将文件指针指向文件头)
"r+" (读写方式打开,将文件指针指向文件头)
"w" (写入方式打开,清除文件内容,如果文件不存在则尝试创建之)
"w+" (读写方式打开,清除文件内容,如果文件不存在则尝试创建之)
"a" (写入方式打开,将文件指针指向文件末尾进行写入,如果文件不存在则尝试创建之)
"a+" (读写方式打开,通过将文件指针指向文件末尾进行写入来保存文件内容)
"x" (创建一个新的文件并以写入方式打开,如果文件已存在则返回 FALSE 和一个错误)
"x+" (创建一个新的文件并以读写方式打开,如果文件已存在则返回 FALSE 和一个错误)
使用 "b" 来强制使用二进制模式,这样就不会转换数据。为了使用这些标记,请使用 "b" 或者 "t" 来作为 mode 参数的最后一个字符
fread ( resource $handle , int $length ) :从文件指针 handle 读取最多 length 个字节
fclose ( resource $handle ) : bool
将 handle 指向的文件关闭
unpack(format,data) :函数从二进制字符串对数据进行解包
intval() 函数用于获取变量的整数值
读取文件的前两个字节判断图片类型
图片木马绕过
使用文件包含 进行漏洞利用
Pass-17
basename() 函数返回路径中的文件名部分
<?php
$path = "/testweb/home.php";
//显示带有文件扩展名的文件名
echo basename($path);
//显示不带有文件扩展名的文件名
echo basename($path,".php");
?>
输出:
home.php
home
imagecreatefromjpeg(filename):由原文件路径生成一个信心的图像
filename
JPEG 图像的路径。
unlink(filename,context) :函数删除文件
若成功,则返回 true,失败则返回 false
二次渲染
条件竞争
Pass-18
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 = '上传出错!';
}
之前都是,首先判断 我们上传的文件 是否 符合白名单,或者是不在黑名单当中;只有当条件符合时,才会使用 move_uploaded_file($temp_file, $upload_file)
将我们上传的文件进行路径移动。
而本题时首先将我们上传的文件进行路径移动,然后再判断是否符合白名单,如果不符合的话,就会使用 unlink($upload_file);
将我们上传的文件进行 删除
。
因此如果我们想要上传 .php
文件的话,就需要 在 其服务器删除我们的文件之前进行访问利用。
方法:短时间内不断重复上传该文件,可使用 BurpSuite
Pass-19
Pass-20
Pass-21
explode() 函数使用一个字符串分割另一个字符串,并返回由字符串组成的数组
示例:
<?php
$str = "www.runoob.com";
print_r (explode(".",$str));
?>
运行结果:
Array
(
[0] => www
[1] => runoob
[2] => com
)
count() 函数返回数组中元素的数目
$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 = "请选择要上传的文件!";
}
分析:
1.首先判断 MIME 类型,必须为 jpg,png,gif
2.判断 $_POST['save_name']是否为空,不为空的话,就将 $_POST['save_name'] 赋值给 $file
3.判断 $file 是否为数组,不是的话,使用 . 将其分割为数组元素
4.判断文件后缀名:取 $file 数组的最后一个元素 作为 $ext 的值,判断是否符合白名单
5.符合的话,使用 reset($file)函数取 数组 $file的第一个元素,拼接一个".",然后再拼接上 该数组含有元素个数-1 的元素 作为文件名
绕过分析:
1.抓包更改 MIME类型--image/jpeg
2.将用户所输入的 "save_name" 更改为一个数组,并赋值:$save_name[0] = 2121.php/;$save_name[1] = NULL;$save_name[2] = jpg
3.则 $file 本身就成为了一个数组,不会被 . 分割;
reset($file) 将会是 $file 的第一个元素,即 2121.php/;
由于 $file[1] = NULL,则count($file) 将会是2,所以最终拼接而成的 $file_name = 2121.php/.
因此解析之后会自动忽略掉 /.
,则最终上传的文件名是 2121.php