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

BUU44 [BJDCTF2020]ZJCTF,不过如此1 [php://filter][正则表达式get输入数据][捕获组反向引用][php中单双引号]

题目: 

 我仿佛见到了一位故人。。。也难怪,题目就是ZJCTF

按要求提交/?text=data://,I have a dream&file=next.php后: 

......不太行,好像得用file=php://filter/convert.base64-encode/resource=next.php 

耶?那 file=php://filter/convert.base64-encode/resource=next.php 和 file=next.php在这里有啥区别啊 

file=php://filter/convert.base64-encode/resource=next.php 和 file=next.php

示例:如果next.php为 <?php echo "hello"; ?>

1.file=next.php: 直接输出hello(include函数会将括号内的文件内容当作php来解析)

2.file=php://filter/convert.base64-encode/resource=next.php

  • php://filter 是PHP的流包装器,允许在读取文件时对内容进行过滤处理。
  • convert.base64-encode 过滤器会将文件内容转换为Base64编码格式。
  • 当使用 include 包含此路径时,PHP会先读取 next.php 的内容,经过Base64编码后,再尝试将编码后的内容作为PHP代码执行。

关键点在于base64编码后的东西不再是有效代码,php无法解析,在面对无效代码这种情况下php可能会将编码后的内容作为“原始输出”返回

这样就能直接返回next.php的源代码了 

 源代码

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;function complex($re, $str) {return preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str);
}foreach($_GET as $re => $str) {echo complex($re, $str). "\n";
}function getFlag(){@eval($_GET['cmd']);
}

代码一些地方需要注意:

preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str);

preg_replace($要搜索的正则表达式的模式, $用于替换匹配项的字符串, $被进行搜索和替换的字符串); 所以关于这里的正则表达式模块:'/('.$re.')/ei',

注意preg_replace在调用的时候需要将参数用 ' ' 括起来

其中$re代表用户传入的正则表达式模式,通过字符串拼接的方式,将$re嵌入到整体正则表达式中  / 用于表示正则表达式的开始和结束,( 和 ):是捕获组的符号,用于将匹配到的内容捕获起来,以便后续引用,e 修饰符会使 preg_replace 在替换字符串时执行其中的 PHP 代码,i 修饰符表示不区分大小写进行匹配。

strtolower("\\1")

\\1:这是对捕获组的引用,代表第一个捕获组匹配到的内容。strtolower用于将字符串转换为小写。所以这句话意思是将捕获到的内容转换成小写

捕获组和反向引用

主要用于引用之前匹配的捕获组的内容。它允许在同一个正则表达式中复用已匹配的文本,常用于模式重复匹配或替换操作。

捕获组:()括起来的内容就是捕获组,比如说(\d+)匹配一个或者多个内容,并记录匹配的内容

反向引用:\n 表示引用第n个捕获组的内容

foreach函数触发漏洞

遍历$_GET数组,键名作为$re,键值作为$str,并将这两个值传入complex函数中

foreach($_GET as $re => $str) {echo complex($re, $str). "\n";
}

对于php中双引号和单引号的区别

双引号:

<?php echo "{${phpinfo()}}"; ?>

会返回phpinfo的界面 

因为双引号里面如果包含有变量,php解释器会将其替换为变量解释后的结果(允许变量解析)。任何 ${...} 内的表达式会被执行,其返回值作为变量名

具体实现:

  1. phpinfo() 函数会被立即执行,输出PHP配置信息(返回值为 true,即 1)。
  2. PHP尝试解析 ${phpinfo()} 的结果(即 1),等价于变量 $1
  3. 由于变量名 $1 非法(不能以数字开头),会触发一个 Notice级错误(若未关闭错误提示),最终输出空字符串。

实际效果

输出 phpinfo() 的完整信息。输出空字符串(因 $1 未定义),并可能伴随错误提示。

单引号:

<?php echo '{${phpinfo()}}'; ?>

单引号内不解析变量,所以内容按字面量输出  {${phpinfo()}}

再返回到next.php中,其基本思路就是get个键名键值都是自己输入的东西&cmd命令,其中get内容要触发getflag()函数进而触发eval()函数,cmd才有用武之地

php会将传入的非法的参数名转成下滑线

当非法字符为首字母时,只有点号会被替换成下划线 

 上传的$re=$str,传入  .*=${getflag()}   代入代码中就是:

preg_replace('/(.*)/ei','strtolower("\\1")',${getflag()});

getflag() 是一个函数调用,意味着会先执行 getflag 函数,然后将该函数的返回值作为目标字符串传递给 preg_replace 进行处理。

也就是说会这样

好傻啊这个函数,还会先跑去执行一下代码然后再匹配,怪不得e被弃用了 

残留几个问题:

1.为什么要加上${  }? ,这个东西有什么用?

${ }用于变量替换、字符串模板、表达式嵌入

这里${getflag()}外面套上一个${ }就表示执行函数,如果不套这个${ }那么就变成

strtolower("getflag()")

此时单纯把这个当成字符串,而不能把他当成函数去解析

2.为什么 \S* 能表示 .? ?

因为大写表示取反操作

这里\s 表示匹配任意空白字符,而\S表示匹配任意非空白字符(等价于 [^\s]

3.捕获组和反向引用干什么用的?

主要是为了匹配重复的字符,比如说

\b(\w+)\b\s+\1\b

\b表示单词边界,\w表示任意一个单词字符,+是个量词,表示前面的 \w 可以出现很多次,\s+表示任意一个或多个空白符号

这里就能匹配到诸如"pig pig"这样的字符串

也可以匹配标签,这里的 < 和 > 都代表真实的<>

<([a-z]+)>(.*?)</\1>

反向引用还在输出! 


http://www.mrgr.cn/news/93124.html

相关文章:

  • 【c语言指针精选题】
  • stable-diffusion-webui 加载模型文件
  • 计算机网络——子网掩码
  • 解锁MacOS开发:环境配置与应用开发全攻略
  • 【文献阅读】The Efficiency Spectrum of Large Language Models: An Algorithmic Survey
  • 专业 英语
  • Android14 串口控制是能wifi adb实现简介
  • 日常开发记录-radio组件
  • Python----数据分析(Matplotlib二:绘图一:折线图,条形图,直方图)
  • DeepSeek 系列模型:论文精读《A Survey of DeepSeek Models》
  • v-code-diff 配置
  • 【第13节】C++设计模式(行为模式)-Template(模板)模式
  • 【每日学点HarmonyOS Next知识】web滚动、事件回调、selectable属性、监听H5内部router、Grid嵌套时高度设置
  • 双目系统求坐标系A到坐标系B的旋转矩阵和平移向量——C++代码实现
  • 测试工程师的DeepSeek提效3:质保中的应用
  • io标准函数和时间函数day2
  • 认识线程
  • SpaCy处理NLP的详细工作原理及工作原理框图
  • 《AJAX:前端异步交互的魔法指南》
  • Qt之QGraphicsView图像操作