前言
记录学习反序列化进阶知识:pop链的学习
之前在isctf也遇到过pop链的题,有关fate的,也是无从下手,今天就来学习一下相关的知识。
仅供个人学习,如有冒犯请尽快联系
一、前置知识
常见的魔术方法
->
的使用
对象运算符 ( ->
) 可用于为变量赋值和调用方法。
<?php
class Demo_Class {
public $demo;
public $demo1 = "This is delftstack";
public function Demo_Method() {
echo "This is delftstack from demo method.";
}
}
$demoinstance = new Demo_Class();
$demoinstance->demo="delftstack"; // 把delftstack赋值给demo这个变量
echo $demoinstance->demo; //输出demo的值
echo "<br>";
echo $demoinstance->demo1; //输出demo1的值
echo "<br>";
$demoinstance->Demo_Method(); // 调用Demo_Method这个函数方法
?>
输出
delftstack
This is delftstack
This is delftstack from demo method.
二、做题思路
这一类的题目没有固定的、公式化的解法,一开始只能了解大致方向,更细致的只能通过不断做题累积经验
<?php
class Rd
{
public $ending;
public $cl;
public $poc;
public function __destruct()
{
echo "All matters have concluded" . "</br>";
}
public function __call($name, $arg)
{
foreach ($arg as $key => $value) {
if ($arg[0]['POC'] == "0.o") {
$this->cl->var1 = "getttt";
}
}
}
}
class Poc
{
public $payload;
public $fun;
public function __set($name, $value)
{
$this->payload = $name;
$this->fun = $value;
}
function getflag($paylaod)
{
echo "Have you genuinely accomplished what you set out to do?" . "</br>";
file_get_contents($paylaod);
}
}
class Er
{
public $symbol;
public $Flag = 'aHR0cDovLw==';
public function __construct()
{
$this->symbol = True;
}
public function __set($name, $value)
{
if (preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/', base64_decode($this->Flag))) {
$value($this->Flag);
} else {
echo "NoNoNo,please you can look hint.php" . "</br>";
}
}
}
class Ha
{
public $start;
public $start1;
public $start2 = 'o.0';
public function __construct()
{
echo $this->start1 . "__construct" . "</br>";
}
public function __destruct()
{
if ($this->start2 === "o.0") {
$this->start1->Love($this->start);
echo "You are Good!" . "</br>";
}
}
}
function getttt($url)
{
echo ("<script>alert('you got it!!!');</script>");
}
if (isset($_POST['pop'])) {
$a = unserialize($_POST['pop']);
} else {
die("You are Silly goose!");
}
1.找切入点
pop链就是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击者的目的
所以找php函数的可控点,也就是魔术方法,以及链的出口和入口,这里有__destruct(),__call,__set,__construct()以及一个unserialize()
__destruct()用于对象销毁时输出"All matters have concluded"
这里的__call()用于在调用不存在的方法时执行一些操作,这里根据传入的参数判断是否满足条件,如果满足则修改$cl对象的属性
__set()用于在给不存在的属性赋值时执行一些操作,这里将传入的变量name赋值给变量payload,将变量value赋值给变量fun
getflag()方法输出"Have you genuinely accomplished what you set out to do?",并调用file_get_contents()函数
__construct()允许在实例化一个类之前先执行构造方法,这里用于拼接start1变量和__construct()字符以及设定symbol的值为True
其中var1变量以及Love函数不存在,可以作为切入点
所以我们的思路是:Ha#__destruct()=>Rd#__call()=>Er#__set()
其中Poc的__set()没有用,因为只是赋了个值,没有其他操作;Rd的__destruct()没有用,只是输出一条语句
2.构造pop链
start2的值已经被赋值成了o.0,是自动进if语句的,所以不用管
先new一个Ha,让其中的__destruct()在销毁时可以运行
注意这里的start1要赋值,不然链就断了,把对象Rd赋值给start1,以此产生联系
这里的var1是不存在的变量,会触发__set()函数
在Rd中有判断语句,所以我们需要进行赋值
接着new一个Er,前文提到触发了__set()函数
foreach是遍历给定的数组语句
再把Er赋值给Rd中的cl,这时Er中的正则表达式就会字符检测是否为网址开头,检测通过,getttt函数中也是url,这时就会跳you got it
我们把构建好的pop链序列化,搭建环境验证一下
在post栏中输入序列化的pop链
构建成功
代码:
序列化:
O:2:“Ha”:3:{s:5:“start”;a:1:{s:3:“POC”;s:3:“0.o”;}s:6:“start1”;O:2:“Rd”:3:{s:6:“ending”;N;s:2:“cl”;O:2:“Er”:2:{s:6:“symbol”;b:1;s:4:“Flag”;s:12:“aHR0cDovLw==”;}s:3:“poc”;N;}s:6:“start2”;s:3:“o.0”;}