php反序列化及__toString()

昨天做华山杯遇到的这个题,涉及了php反序列化和一个魔术函数__toString()特性。简要记录一下。

主要两个文件

index.php

<?php
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];

if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
    echo "hello admin!<br>";
    if(preg_match("/f1a9/",$file)){
        exit();
    }else{
        include($file); //class.php
        $f = new Read();
        var_dump($f);
        echo serialize($f);
        echo "\n";
        $pass = unserialize($pass);
        echo $pass;
    }
}else{
    echo "you are not admin ! ";
}

?>

class.php

<?php

class Read{//f1a9.php
    public $file;
    public function __toString(){
        if(isset($this->file)){
            echo file_get_contents($this->file);    
        }
        return "__toString was called!";
    }
}
?>

题目的意思很明显,是通过get传入的三个参数来控制获取到f1a9.php文件里的flag。

第一个条件,通过file_get_contents($user,'r')获取$user参数传来的值,三等于,基本不存在什么弱比较类型的绕过,但我们知道该函数里是支持伪协议的,这里可以用php伪协议php://input,来使得其获取的值为我们post传递过去的值,如下:

接下来,看到后面有一个文件包含,利用该漏洞。可以把文件源码读下来,如下:

然后base64解密即可得到源码。但我们发现这里是不能直接读到flag文件的值的,做了过滤,再看看class.php文件:

里面是一个类,并且类里只有一个__toString()方法,我们看看__toString()方法的作用

  __toString()是快速获取对象的字符串信息的便捷方式,似乎魔术方法都有一个“自动“的特性,如自动获取,自动打印等,__toString()也不例外,它是在直接输出对象引用时自动调用的方法。
  当我们调试程序时,需要知道是否得出正确的数据。比如打印一个对象时,看看这个对象都有哪些属性,其值是什么,如果类定义了toString方法,就能在测试时,echo打印对象体,对象就会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。

简单的说,就是当类对象被输出引用时,就会自动调用该方法

我们看到class源文件的__toString()方法有一个file_get_contents()函数,而之前index文件还有一个pass参数还没用到

        $pass = unserialize($pass);
        echo $pass;

于是我们构造Read类的序列化对象,然后经过这里的反序列化,在echo输出时,不就会自动加载__toString()方法吗,然后就可以达到我们获取flag的目的了

最终exp如下:

posted on 2016-09-11 09:55  镱鍚  阅读(1641)  评论(0编辑  收藏  举报

导航