通常是针对文件的扩展名后缀进行检测,主要是通过黑白名单进行过滤检测,如果不符全过滤规则则不允许上传。
BurpSuite
火狐/谷歌浏览器
AntSword(蚁剑)
靶 机: windows10虚拟机:
192.168.15.133
upload-labs-master
闯关游戏
攻击机: 物理机
1、通过实验,学习掌握文件的扩展名检测的原理;
2、通过实验,学习扩展名检测的绕过的方法技巧。
黑名单检测:一般有个专门的
blacklist 文件
,里面会包含常见的危险脚本文件。
例如: fckeditor 2.4.3 或之前版本的黑名单:
白名单检测:一般有个专门的
whitelist 文件
,里面会包含的正常文件。
Jpg
png
GIF
- .htaccess文件解析漏洞
- apache解析漏洞
- IIS7.0 | IIS7.5 | Nginx的解析漏洞
- IIS6.0解析漏洞
点击进入:解析漏洞绕过
虽然web应用做了校验,但是由于文件上传后的
路径用户可以控制
,攻击者可以利用手动添加字符串标识符0X00
的方式来将后面的拼接的内容进行截断
,导致后面的内容无效,而且后面的内容又可以帮助我们绕过黑白名单的检测。
点击进入: 【文件上传绕过】——后端检测_文件名检测00截断绕过
在
C语言
中,空字符
有一个特殊含义,代表字符串的拼接结束。
这里我们使用的是php语言
,属于高级语言,底层靠C语言
来实现的,也就是说空字符
的字符串拼接结束功能在PHP
中也能实现。但是我们在URL中不能直接使用空
,这样会造成无法识别;我们通过查看ASCII对照表
,发现ASCII对照表
第一个就空字符
,它对应的16进制是00
,这里我们就可以用16进制的00
来代替空字符
,让它截断
后面的内容。
使用burpsuite
进行抓包,因为这里是通过URL
进行传递的文件上传后存储路径,所以需要对16进制
的00
进行URL编码
,编码的结果就是%00
,通过这种方式,就可以%00
截断后面的内容,让拼接的文件名不再进行生效:
点击进入:【汇总】文件包含漏洞合集详解
- .htaccess文件解析漏洞
- apache解析漏洞
- IIS7.0 | IIS7.5 | Nginx的解析漏洞
- IIS6.0解析漏洞
点击进入:解析漏洞绕过
虽然web应用做了校验,但是由于文件上传后的
路径用户可以控制
,攻击者可以利用手动添加字符串标识符0X00
的方式来将后面的拼接的内容进行截断
,导致后面的内容无效,而且后面的内容又可以帮助我们绕过黑白名单的检测。
点击进入: 【文件上传绕过】——后端检测_文件名检测00截断绕过
在
C语言
中,空字符
有一个特殊含义,代表字符串的拼接结束。
这里我们使用的是php语言
,属于高级语言,底层靠C语言
来实现的,也就是说空字符
的字符串拼接结束功能在PHP
中也能实现。但是我们在URL中不能直接使用空
,这样会造成无法识别;我们通过查看ASCII对照表
,发现ASCII对照表
第一个就空字符
,它对应的16进制是00
,这里我们就可以用16进制的00
来代替空字符
,让它截断
后面的内容。
比如:
aSp
和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",".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 . '文件夹不存在,请手工创建!';
}
}
通过上面的源码可以看出,没有对文件的大小写进行验证,可以通过大小写进行绕过,下面通过把文件修改为大写:
修改为大小写,发现绕过了黑名单,可以进行解析为脚本文件:
比如:
asa
和cer
之类
asp:
asa
cer
aspx
jsp:
jspx
jspf
php:
php
php3
php4
php5
phtml
pht
exe:
exee
访问:
192.168.15.133/upload-labs-master/Pass-03/index.php?action=show_code
1、上传一个1.php
的文件:
2、提示不允许上传:
3、文件名改为1.php2
:
4、发现能够上传,但无法解析为脚本文件:
5、删除后面的2,发现没有这个文件,因为服务器里面没有这个文件:
6、我们偿试上传一个1.php5
的文件:
7、无法进行解析:
8、通过偿试,发现上传php3
php4
php5
pht
几个文件都可以进行上传,但是无法进行解析为脚本文件。
偿试上传phtml文件
,首先我们进行重命名,发现这里可以解析为脚本文件:
9、偿试进行上传:
10、访问,可以正常进行解析:
shell.php.
shell.php空格
shell.php:1.jpg
shell. php::$DATA
shell.php:1.jpg
1、在windows中,后缀名后面的点和空格都会被删除掉。
把2.php
文件重命名为2.php. .
,如下图所示:
2、我们发现,空格和点都被删除了,如下图所示:
页面源码:
$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 = $_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
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 . '文件夹不存在,请手工创建!';
}
}
通过上面源码我们发现,里面有$file_ext = strtolower($file_ext); //转换为小写
代码,我们使用大小写进行绕过肯定不行。
但是我们发现,这个代码相比于前面一关来说,没有进行首尾去空的代码,可以使用命名机制进行绕过:
1、通过上传,发现只能上传以下几种文件后缀:
2、这里我们发现无法直接通过windows本地进行后缀加空格的修改,我们可以通过burpsuite抓包进行修改后缀名:
3、发现已经上传成功,并且可以正常解析:
注:我们可以把文件名称改为*.php空格
,它会把我们上传的文件和黑名单里面的后缀进行比对,发现黑名单没有*.php空格
这个文件的后缀名,后台就会进行放行,这样就可以进行成功进行上传。到达windows服务器后,windows发现文件后缀有空格,windows就会删除后面的空格,文件就变成*.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",".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_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 . '文件夹不存在,请手工创建!';
}
}
1、通过上面源码我们发现,这里的代码里面没有写删除文件后缀末尾的点
的这行代码,这里我们可以通过在文件后面加上点进行绕过,通过burpsuite进行抓包:
2、发现正常,可以进行解析为脚本文件:
页面源码:
$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 = 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 . '文件夹不存在,请手工创建!';
}
}
检测过滤过程:删除文件名末尾的点-->截取后缀名-->转换为小写-->去除字符串::$DATA-->首尾去空-->把过滤的结果和黑名单进行比对
通过上面的源码我们发现,它的验证过程是先删除删除文件名末尾的点
,最后首尾去空
,这样我们就可以构造为1.php. .
,这样在第一步的时候,先删除最后面的点,接着删除中间的空格,最后还剩下1.php.
,黑名单中也没有这个后缀名,可以进行绕过。
1、通过burpsuite进行抓包修改文件后缀名,如下图所示:
2、可以解析为脚本文件:
页面源码:
$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 = strtolower($file_ext); //转换为小写
$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 . '文件夹不存在,请手工创建!';
}
}
检测过滤过程:删除文件名末尾的点-->截取后缀名-->转换为小写-->首尾去空-->把过滤的结果和黑名单进行比对
通过上面源码我们发现,这里的代码里面没有写去除字符串::$DATA
的这行代码,这里我们可以通过在文件后面加上点进行绕过。
注:这关我们需要的了解的知识:$DATA是什么?
windows磁盘一般使用文件系统为NTFS文件系统,NTFS使用Master File Table (MFT) 来管理文件。windows系统中的每个文件都对应一个MFT记录。而每一个MFT记录由若干个属性
(attribute)组成,用来描述该文件的具体信息。比如:
$FILE_NAME
属性描述了该文件的文件名和创建修改访问时间;
$DATA
属性包含了该文件的具体内容,我们一般在创建文件,写入的内容都会默认存储在这个属性里面。这个默认的属性我们称为主数据流(primary data stream )。
举个例子,我现在有一个文本文件,名称为1.txt,文本内容为”Hello, world!”:
我们可以通过实验进行了解:
创建一个1.txt的文件:
通过上面操作,我们发现,通过两种方法写入的数据效果都是一样,其实都是存储在第一个$DATA
里面,我们正常创建的一个文件,默认写入的就是第一个$DATA
里面。通过在后面加上::$DATA
这样就可以绕过黑名单的检测,而且在绕过黑名单后,Windows会自动去掉末尾的::$DATA
变成*.php
。
可参考文章1
可参考文章2
1、通过burpsuite
进行抓包,修改文件后缀名:
2、我们复制图片链接地址,并进行访问,发现没有权限进行访问:
4、我们去文件上传路径看看文件的变化,发现文件名后面的::$DATA
没有了:
注:出现上面情况的原因是因为,根据windows的命名机制,文件名是不允许有:(冒号)
等一些字符存在的,当这个文件被转存到web服务器后,它会根据windows命名机制删除:(冒号)
后面的字符。
有时候在检测时,后台会把敏感字符替换成空格,这个时候,我们可以使用双写进行绕过。比如:
pphphp
页面源码:
$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");
$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 . '文件夹不存在,请手工创建!';
}
}
这关的验证方式和前面几关有所不同,主要看str_ireplace($deny_ext,"", $file_name);
这个代码,主要作用是把上传的文件和黑名单进行对比,如果黑名单里面存在,就把后缀名替换为空格。
通过这种方式进行过滤验证的,我们通常可以使用双写的方式进行绕过。
1、下面我们对文件进行重命名,命名为1.pphphp
: