Windows利用系统本身的命名规则绕过:
先看一下利用Windows特性绕过
-
大小写绕过:针对对大小写不敏感的系统如 windows 例如test.PhP
-
以下为不符合规则的Windows文件
shell.php. | 文件名后加 ‘.‘ | 适用于上传的文件名没有被修改 |
---|---|---|
shell.php空格 | 文件名后加空格 | |
shell.php.空格. | 文件名+‘.‘+空格+‘.‘ | 适用于上传的文件名没有被修改 |
shell.php:1.jpg | 文件名后加冒号 | 适用于上传的文件名没有被修改 |
shell.php::$DATA | 文件名加NTFS ADS特性::$DATA | |
shell.php::$DATA...... | 文件名::$DATA..... |
均会被windows系统自动去掉不符合规则符号后面的内容
ADS是nfts磁盘格式的一个特性,由于NTFS交换数据流,在上传文件时,如果系统对请求正文的filename匹配不当的话可能会导致绕过
上传的文件名 | 服务器表面现象 | 生成的文件内容 |
---|---|---|
test.php:a.jpg | 生成test.php | 空 |
test.php::$DATA | 生成test.php | <?php phpinfo():?> |
test.php::$INDEX_ALLOCATION | 生成test.php文件夹 | |
test.php::$DATA.jpg | 生成0.jpg | <?php phpinfo():?> |
test.php::$DATA\aaa.jpg | 生成aaa.jpg | <?php phpinfo():?> |
在php环境下可以上传test.php::$DATA
Linux也可利用系统本身的命名规则绕过
linux命名规则
1、文件名最大长度为255
2、全路径长度最大为4096(16级最大文件长度)
3、区分大小写
4、除“/”之外所有字符都可以使用
5、linux不以文件扩展名区分文件类型,对linux来说一切皆文件。
源码分析
$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",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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",".htaccess");
$file_name = trim($_FILES[‘upload_file‘][‘name‘]);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, ‘.‘);
$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.‘/‘.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = ‘上传出错!‘;
}
} else {
$msg = ‘此文件类型不允许上传!‘;
}
} else {
$msg = UPLOAD_PATH . ‘文件夹不存在,请手工创建!‘;
}
}
-
首先 trim( )函数 移除字符串两侧的空白字符
- 假设上传
test.php+空格
,这时服务器获取到的后缀是.php+空格,该文件不再黑名单中,因此上传功。 - 由于windows文件系统的特性,会去除后面的空格,导致test.php+空格=test.php
- 假设上传
-
deldot( ) 删除文件名末尾的点
- 假设上传
test.php.
这时服务器获取到的后缀是空,不在黑名单中,因此文件上传成功 - 但是由于windows文件系统的特性导致test.php.=test.php
- 假设上传
-
strchr( $file_name,‘ . ‘)函数 是搜索
.
在文件名中的位置,并返回从该位置(包括此位置)到字符串结尾的所有字符-
从头开始,找到第一个满足的就开始截取
-
-
strrchr( $file_name,‘ . ‘)函数 函数和3中的strchr不同,看看下面的图体会一下,源码用的此函数
-
str_ireplace(‘::$DATA‘, ‘‘, $file_ext)
将::$DATA去掉 -
使用 trim($file_ext) 移除字符串两侧的空白字符
-
禁止上传如下后缀文件
- 文件重命名文年月日星期+1000~9000+后缀名
- 上传成功
上传
分析上面的源码后,思路逐渐清晰,前两步尾部去点,去空格,第五步去::$DATA,对于windows来说算致命打击,但是转换没转换大小写,可以用test.PHp
绕过windows系统
利用linux的特性,创建一个类似文件如test.\php
可以绕过linux系统
上传一个test.\php
,看到上传的后缀名没了,所以上传的不是linux系统,而是windows系统
因此利用windows不区分大小写特性来绕过
上传1.PHp
连接成功