9-::$DATA后缀绕过
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",".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 = 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 文件系统的备用数据流(Alternate Data Stream, ADS) 的语法。当一个文件名末尾加上 ::$DATA 时,Windows 会强制将其解释为主数据流 (即普通文件内容),而忽略 ::$DATA 自身。
绕过原理 :
上传时,如果程序只对 $_FILES['upload_file']['name'] 进行简单的黑名单后缀检查,比如检测是否以 .php 结尾,那么你可以在文件名后面加上 ::$DATA,例如:
text
shell.php::$DATA
- 程序检测到的后缀可能是
.php::$DATA(如果直接取扩展名),黑名单里通常没有这个后缀,因此通过检查。 - 当文件被
move_uploaded_file()移动到 Windows 目标目录时,系统会忽略 ::$DATA ,实际保存的文件名变成shell.php。 - 最终得到可解析的 PHP 文件,从而完成上传绕过。
如果代码中有
str_ireplace('::$DATA', '', $file_ext)这样的过滤,这个绕过方法就会失效(例如你的第七关代码已经过滤了)。
为什么上传到 Windows 上之后,后面的 ::$DATA 不见了?
因为 ::$DATA 是 Windows 底层文件系统(NTFS)的一个特殊标识符,不是文件名的一部分。当系统创建文件时:
- 解析路径:
shell.php::$DATA→ 表示"文件shell.php的主数据流"。 - 最终文件系统只保存文件名
shell.php,而不保留::$DATA字符。
所以在文件夹中看到的是 shell.php,而不是带有 ::$DATA 的奇怪名字。
这个特性原本用于兼容性(比如从非 NTFS 系统访问文件),被攻击者利用来绕过简单的上传检测。