【反序列化漏洞02】PHP反序列化漏洞原理测试及魔术方法总结

1 简介

  1. PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。
  2. 漏洞形成的根本原因是程序没有对用户输入的反序列化字节流进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、GetShell等一系列不可控的后果。(在反序列化过程中,会触发代码执行。)
  3. 反序列化漏洞并非是PHP所特有的,也存在与java、Python等语言中,原理基本相同。

2 PHP反序列化漏洞

2.1 测试环境

  1. 服务器:在虚拟机中安装win2008及phpstudy,参考《win2008R2SP1+WAMP环境部署》。
  2. 客户端:真实机浏览器。

2.2 测试过程

  1. 在服务器根目录下,新建txt文件,输入以下内容,并另存为test.php。
<?php
class test{
	public $str='libai;';
	function __destruct(){
		echo "This is function __destruct()";
		@eval($this->str);
	}
}
$test1 = new test();
echo serialize($test1);
echo "<hr>";
$t = $_GET['obj'];
var_dump(unserialize($t));
?>
  1. 浏览器访问该网页,攻击者构造输入参数?obj=O:7:"payload":1:{s:4:"name";s:10:"phpinfo();";},网页显示如下,可以看到phpinfo()函数被成功执行。
    在这里插入图片描述
  2. 将test.php文件修改如下,将新建test类对象的语句注释掉,再次实验。
<?php
class test{
	public $str='libai;';
	function __destruct(){
		echo "This is function __destruct()";
		@eval($this->str);
	}
}
//$test1 = new test();
//echo serialize($test1);
//echo "<hr>";
$t = $_GET['obj'];
var_dump(unserialize($t));
?>
  1. 同样的参数访问,网页显示如下,可以看到同样能执行phpinfo()函数,因此可以判断输入对象成功反序列化为test类对象,并自动执行了__destruct()函数。
    在这里插入图片描述
  2. 将test.php文件修改如下,将最后一行语句修改如下,再次实验。
<?php
class test{
	public $str='libai;';
	function __destruct(){
		echo "This is function __construct()";
		@eval($this->str);
	}
}
//$test1 = new test();
//echo serialize($test1);
//echo "<hr>";
$t = $_GET['obj'];
$t = unserialize($t);
?>
  1. 同样的参数访问,网页显示如下,可以看到同样能执行phpinfo()函数,因此可以判断输入对象成功反序列化为test类对象,并自动执行了__destruct()函数。
    在这里插入图片描述
  2. 我们发现,当销毁实例化类的时候,__destruct()函数会被自动调用,并输出字符串This is function __destruct()。
  3. 默认情况下,PHP仅仅释放对象属性所占用的内存并销毁对象相关的资源.,__destruct()允许你在使用一个对象之后执行任意代码来清除内存,当PHP决定你的脚本不再与对象相关时,__destruct()将被调用.,在一个函数的命名空间内,这会发生在函数return的时候,对于全局变量,这发生于脚本结束的时候,如果你想明确地销毁一个对象,你可以给指向该对象的变量分配任何其它值,通常将变量赋值勤为NULL或者调用unset。

3 PHP魔术方法归纳

  1. 以 __ 开头的的方法,是PHP中的魔术方法,在特定情况下会被自动调用。主要魔术方法如下:
魔术方法触发条件
__construct()构造方法,当一个对象被创建时调用此方法.
__destruct()析构方法,PHP将在对象被销毁前(即从内存中清除前)调用这个方法
__autoload()使用尚未被定义的类时自动调用。通过此函数,
脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
__call( $method, $arg_array )在对象中调用一个不可访问方法时
__callStatic()在静态上下文中调用一个不可访问的方法时使用
__clone()使用clone方法复制一个对象时
__invoke()当尝试调用函数的方式调用一个对象时
__get( $property )从不可访问的属性中读取数据
__set( $property, $value )给一个未定义的属性赋值时调用
__isset( $property )当在一个未定义的属性上调用isset()函数时调用此方法
__unset( $property )当在一个未定义的属性上调用unset()函数时调用此方法
__toString()在将一个对象转化成字符串时自动调用
__sleep()序列化对象前调用(其返回需要是一个数组),详见补充说明
__wakeup()反序列化恢复对象前调用,详见补充说明
__set_state()当调用var_export()时,这个静态方法会被调用
__invoke()当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用
  1. __sleep()和__wakeup()的补充说明
    1. serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
    2. 使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
    3. 相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。
    4. 使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

4 总结

  1. 理解PHP反序列化漏洞的触发原理;
  2. 了解PHP相关的魔术方法及调用情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值