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如下: