当前位置: 首页 > news >正文

upload-labs通关笔记-第10关 文件上传之点多重过滤(空格点绕过)

目录

一、源码分析

1、delot函数

2、strrchr函数

3、trim函数

4、代码审计 

5、渗透思路

 二、渗透实战

1、构建脚本test10.php

2、打开靶场

3、bp开启拦截

4、点击上传

5、bp拦截

6、文件名尾部增加“. .”

7、发包并获取脚本地址

8、访问脚本


本文通过《upload-labs靶场通关笔记系列》来进行upload-labs靶场的渗透实战,本文讲解upload-labs靶场第10关文件上传通关代码审计实现“点空格点”绕过的渗透实战。

一、源码分析

打开upload-labs靶场第10关,选择查看源码对其进行代码审计,这段代码依旧是黑名单过滤,具体如下所示。

1、delot函数

本关卡需要通过代码审计完成渗透,如上关卡的delot函数是自定义函数,函数主要功能是删除文件名末尾的点(.),从字符串尾部开始,从后向前删除点(.)字符 ,直到末尾的字符不是点为止。具体源码如下所示。

<?php
function deldot($s){for($i = strlen($s)-1;$i>0;$i--){$c = substr($s,$i,1);if($i == strlen($s)-1 and $c != '.'){return $s;}if($c != '.'){return substr($s,0,$i+1);}}
}
?>

2、strrchr函数

strrchr 是 PHP 中的字符串处理函数,其主要功能是查找字符串中某个字符(或子字符串)最后一次出现的位置,并返回从该位置开始到字符串末尾的所有字符。

strrchr ( string $haystack , mixed $needle ) : string|false
  • 参数说明
    • $haystack:这是要进行搜索的目标字符串。
    • $needle:这是要查找的字符或子字符串。如果 $needle 是一个长度大于 1 的字符串,实际上只会使用该字符串的第一个字符进行查找。
  • 返回值
    • 若 $needle 存在于 $haystack 中,函数会返回从 $needle 最后一次出现的位置开始到 $haystack 末尾的子字符串。
    • 若 $needle 不存在于 $haystack 中,函数会返回 false。

在文件上传靶场中,通常使用file_ext = strrchr($file_name, '.')函数用于获取上传文件的扩展名

$file_ext = strrchr($file_name, '.');

这里 $file_name 是上传文件的文件名,通过 strrchr 函数查找 点(.) 最后一次出现的位置,然后返回从该位置开始到文件名末尾的子字符串,也就是文件的扩展名。例如,若 $file_name 为 example.jpg,那么 $file_ext 就会是 .jpg。

3、trim函数

trim 是 PHP 里一个十分实用的字符串处理函数,其主要功能为去除字符串首尾处的空白字符或者其他指定字符。trim函数的基本语法如下所示。

trim ( string $str [, string $character_mask = " \t\n\r\0\x0B" ] ) : string
  • 参数说明
    • $str:这是需要处理的目标字符串。
    • $character_mask:这是一个可选参数,用于指定要去除的字符。若不提供该参数,默认会去除空格()、制表符(\t)、换行符(\n)、回车符(\r)、空字节(\0)以及垂直制表符(\x0B)。
  • 返回值:返回去除了指定字符后的新字符串

 在之前的文件上传代码里,trim 函数被调用了两次:

$file_name = trim($_FILES['upload_file']['name']);
$file_ext = trim($file_ext);
  • 第一次使用 trim 函数是为了去除上传文件原始文件名首尾的空白字符,避免因文件名前后存在空格而引发问题。
  • 第二次使用 trim 函数是对处理后的文件扩展名进行处理,去除其首尾的空白字符,确保扩展名的准确性。这样做能防止因空白字符的存在而导致文件类型的过滤出现误判。

4、代码审计 

详细注释的源码如下所示。第10关处理逻辑具体如下所示。

<?php
// 初始化变量,用于判断文件是否上传成功,初始值为 false
$is_upload = false;
// 初始化变量,用于存储上传过程中的提示信息,初始值为 null
$msg = null;// 检查是否通过 POST 方式提交了名为 submit 的表单数据
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']);// 调用 deldot 函数删除文件名末尾的点$file_name = deldot($file_name);// 获取文件的扩展名,从文件名中最后一个点开始截取$file_ext = strrchr($file_name, '.');// 将文件扩展名转换为小写$file_ext = strtolower($file_ext);// 去除文件扩展名中可能存在的字符串 "::$DATA"$file_ext = str_ireplace('::$DATA', '', $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.'/'.$file_name;// 尝试将临时文件移动到目标目录if (move_uploaded_file($temp_file, $img_path)) {// 如果移动成功,将 $is_upload 标记为 true$is_upload = true;} else {// 如果移动失败,设置提示信息为上传出错$msg = '上传出错!';}} else {// 如果文件扩展名在禁止列表中,设置提示信息为不允许上传该类型文件$msg = '此文件类型不允许上传!';}} else {// 如果上传目录不存在,设置提示信息为文件夹不存在,需要手工创建$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}
}
?>

这段代码首先定义了一个数组 $deny_ext,包含了一系列不允许上传的文件扩展名 ,然后获取并处理上传的文件名以及扩展名,具体逻辑如下所示。

  • 从 $_FILES['upload_file']['name'] 获取上传文件的原始文件名,并去除首尾空格。
  • 调用 deldot 函数删除文件名末尾的点。
  • 使用 strrchr 函数获取文件的扩展名。
  • 将扩展名转换为小写,以避免大小写绕过。
  • 去除扩展名中可能存在的字符串 ::$DATA。
  • 再次去除扩展名首尾的空格。

5、渗透思路

假设我们要上传的文件名为test10.php,我们在文件名的后缀尾部添加[点+空格+点],那么要上传的文件名被修改为[test10.php.空格.],上传到服务器之后会保留文件名test.php,整个处理流程如下所示。

  • 第一步:deldot的函数先去除了一个最末尾的点,但是由于deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来,因此可以得到$file_name值为test10.php.空格,即“test10.php. ”
filename:“test10.php. ”
  • 第二步:$file_ext = strrchr($file_name, ‘.’);这个函数的功能是获取字符点最后出现的位置后面的所有字符,因此在判断完以上语句后,可以得到$ file_ext值为点空格,即“. ”
ext:". "
  • 第三步:$file_ext = trim($file_ext); //首尾去空,原$file_ext中的空格全都删掉,变为了点,这样文件扩展名为“.”,这样可以绕过黑名单的检测。而此时文件名为"test10.php",这类文件传入window服务器,会被默认删掉.所以可以成功上传php后缀的文件。
​filename:"test10.php. "
ext:"."

 二、渗透实战

1、构建脚本test10.php

<?php
phpinfo();
?>

2、打开靶场

 打开靶场第10关,浏览选择该脚本,但不点击上传。

3、bp开启拦截

4、点击上传

5、bp拦截

bp捕获到上传报文,下图红框的部分即为需要修改的文件名,需要将".php"后缀改为".php. ",修改之前文件名为”test10.php “,如下所示

6、文件名尾部增加“. .”

test11.php改为“test11.php. .”,修改后效果如下所示。

7、发包并获取脚本地址

将bp的inception设置为off,此时修改后的报文发送成功。

回到靶场的Pass11关卡,图片已经上传成功,在图片处右键复制图片地址。

右键图片获取图片地址,如下所示获取到图片URL。 

http://127.0.0.1/upload-labs/upload/test10.php.

8、访问脚本

 如下所示访问上传脚本获取到服务器的php信息,证明文件上传成功。

相关文章:

  • 【JavaWeb】MySQL
  • Github 2025-05-17 Rust开源项目日报 Top10
  • STM32 | FreeRTOS 递归信号量
  • 理解 plank 自动生成的 copyWithBlock: 方法
  • java函数内的变量问题
  • 永久免费!专为 Apache Doris 打造的可视化数据管理工具 SelectDB Studio V1.1.0 重磅发布!
  • 素数筛(欧拉筛算法)
  • 游戏引擎学习第288天:继续完成Brains
  • 遨游科普:三防平板是什么?有什么功能?
  • 使用Langfuse和RAGAS,搭建高可靠RAG应用
  • AI编码代理的崛起 - AlphaEvolve与Codex的对比分析引言
  • Redis 事务与管道:原理、区别与应用实践
  • 深入理解桥接模式:解耦抽象与实现的设计艺术
  • 给你的matplotlib images添加scale Bar
  • DataX:一个开源的离线数据同步工具
  • 计算机视觉与深度学习 | Python实现EEMD-LSTM时间序列预测(完整源码和数据)
  • Predict Podcast Listening Time-(回归+特征工程+xgb)
  • 基于C语言的歌曲调性检测技术解析
  • NX二次开发——设置对象的密度(UF_MODL_set_body_density)
  • redisson分布式锁实现原理归纳总结
  • 知名中医讲师邵学军逝世,终年51岁
  • 美国新泽西客运公司遭遇罢工:40年来首次,35万人受影响
  • 澎湃与七猫联合启动百万奖金征文,赋能非虚构与现实题材创作
  • “朱雀玄武敕令”改名“周乔治华盛顿”?警方称未通过审核
  • 特朗普促卡塔尔说服伊朗放弃核计划,伊朗总统:你来吓唬我们?
  • MSCI中国指数5月调整:新增5只A股、1只港股