反序列化wp

xiaojinjin 发布于 15 天前 76 次阅读


从 0 开始的PHP反序列化入门靶场--探姬

靶场地址http://125.77.172.32:9090/

Level1--类的实例化

class FLAG{
   public $flag_string = "HelloCTF{????}";

   function __construct(){
       echo $this->flag_string;
  }
}

$code = $_POST['code'];

eval($code);

这一题的思路很简单

__construct()是一个构造函数,在对象创建时被调用,用于初始化对象

所以分析一下这段代码,想要拿到flag只需要创建一个新的对象就可以了

所以payload

code=new FLAG();

Level2--对象中值的传递

error_reporting(0);

$flag_string = "HelloCTF{????}";

class FLAG{
       public $free_flag = "???";

       function get_free_flag(){
           echo $this->free_flag;
      }
  }
$target = new FLAG();

$code = $_POST['code'];

if(isset($code)){
      eval($code);
      $target->get_free_flag();
}
else{
   highlight_file('source');
}

这一题有一个暴力解就是直接输出falg_string

code=echo $flag_string;

但是这样并没有去利用这个代码利用链

首先code会被eval

然后target变量new了一个FLAG

FLAG里面有一个

echo $this->free_flag;

这里有一个echo可以输出内容,所以我们将free_flag的值强行赋值为$flag_string,就可以输出真正的falg

payload:

code=$target->free_flag=$flag_string;

执行链如下

code=target
然后target去访问free_flag这个属性
然后再将free_flag的值强行改为$flag_string
再执行$target->get_free_flag();
这个函数有一个echo $this->free_flag;
这才是最终能输出falg的关键
payload的作用只是把free_flag的值给修改了但是并没有输出语句

Level3--对象中值的权限

class FLAG{
   public $public_flag = "HelloCTF{?";
   protected $protected_flag = "?";
   private $private_flag = "?}";

   function get_protected_flag(){
       return $this->protected_flag;
  }

   function get_private_flag(){
       return $this->private_flag;
  }
}

class SubFLAG extends FLAG{
   function show_protected_flag(){
       return $this->protected_flag;
  }

   function show_private_flag(){
       return $this->private_flag;
  }
}

$target = new FLAG();
$sub_target = new SubFLAG();


$code = $_POST['code'];

if(isset($code)){
   eval($code);
} else {
   highlight_file(__FILE__);
   echo "Trying to get FLAG...<br>";
   echo "Public Flag: ".$target->public_flag."<br>";
   echo "Protected Flag:".$target->protected_flag ."<br>";
   echo "Private Flag:".$target->private_flag ."<br>";
}

?>

这一题有一个坑,我一开始想要去调用这个对象class SubFLAG

但是这里有一个问题就是SubFLAG虽然继承了FLAG属性,但是子类 SubFLAG 根本继承不到父类的 private 属性,自然也就 return 不出来。这也是 protected 和 private 在面向对象编程中最大的区别所在。

那问题来了为什么$target->protected_flag 不能直接获取到对应的值呢

因为protected_flag是受保护的属性,外部不可以直接调用,只能内部去调用,FLAG 类里面写了一个公开的方法 get_protected_flag()可以直接调用

$target->public_flag (Public):
这是公开属性。就像摆在马路边的公共自行车,谁都可以直接拿来用。所以在类外部可以直接 -> 访问。

$target->get_protected_flag() (Protected):
protected 是受保护的属性。它只允许类自己内部以及继承它的子类(比如 SubFLAG)访问。你在外部直接写 $target->protected_flag 会报错,但是出题人在 FLAG 类里面写了一个公开的方法 get_protected_flag()。我们调用这个公开的方法,让类自己把内部的属性递出来给我们。

$target->get_private_flag() (Private):
private 是最严格的私有属性。它只能在定义它的类(FLAG)内部访问,连继承它的亲儿子(子类 SubFLAG)都看不到!同样地,我们通过调用 FLAG 类公开的 get_private_flag() 方法顺利拿到最后一段。

所以payload:

code=echo $target->public_flag.$target->get_protected_flag().$target->get_private_flag();

Level4--序列化初体验

class FLAG3{
private $flag3_object_array = array("?","?");
}

class FLAG{
private $flag1_string = "?";
private $flag2_number = '?';
private $flag3_object;

function __construct() {
$this->flag3_object = new FLAG3();
}
}

$flag_is_here = new FLAG();


$code = $_POST['code'];

if(isset($code)){
eval($code);
} else {
highlight_file(__FILE__);
}

阅读代码发现无论是FLAG还是FLAG3都没有输出的语句

code=echo

再观察发现里面的所有对象都是private,所以我们是不可以直接从外部进行读取的

那我们的思路就是从php中找一些在执行时权限极大并且可以无视protect和private权限的函数,让他们进行打印

所以这里的payload就有好几个

code=var_dump($flag_is_here);
code=print_r($flag_is_here);
code=echo serialize($flag_is_here);
此作者没有提供个人介绍。
最后更新于 2026-05-26