PHP反序列化漏洞之面向对象基础

news2024/11/27 1:02:03

一、PHP面向对象基础

要谈PHP反序列化,不得不涉及面向对象,因为在反序列化漏洞利用中,大多涉及的都是“对象”的反序列化。所以需要了解面向对象基础。

面向面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个“对象”,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。

1、基本概念

  • 对象
    对象是对事物的抽象表示。 在面向对象的术语中,一切皆是对象,一个对象就代表一个具体的功能操作,我们不需要了解这个对象是如何实现某个操作的,只需要知道该对象可以完成哪些操作即可。

  • 抽象
    抽象(Abstract)就是忽略事物中与当前目标无关的非本质特征 ,更充分地注意与当前目标有关的本质特征,从而找出事物的共性,并把具有共性的事物划为一类,得到一个抽象的概念。

  • 封装
    封装(Encapsulation)是指把对象的属性和行为结合成一个独立的单位,并尽可能隐藏对象的内部细节。

    通常来说封装有两个含义:

    • 把对象的全部属性和行为结合在一起,形成一个不可分割的独立单位,对象的属性值(除了公有的属性值)只能由这个对象的行为来读取和修改;
    • 尽可能隐藏对象的内部细节,对外形成一道屏障,与外部的联系只能通过外部接口实现
  • 继承
    继承(Inheritance)是一种连接类与类的层次模型。 继承性是指特殊类的对象拥有其一般类的属性和行为。 继承意昧着“自动地拥有”,即特殊类中不必重新定义己在一般类中 定义过的属性和行为,而是自动地、隐含地拥有其一般类的属性和行为。 当这个特殊类又被它更下层的特殊类继承时,它继承来的及自己定义的属性和行为又被下一层的特殊类继承下去。因此,继承是传递的,体现了大自然中特殊与一般的关系 。

    父类:一个类被其他类继承,可将该类称为父类,或者基类,超类
    子类:一个集成其他类的类称为子类,也可称为派生类

以上概念对于初学者来说可能比较抽象,晦涩。在面向对象中有许多概念,如类、对象、继承、多态等。面向对象编程思想的培养需要在学习过程中不断积累,对于学习PHP反序列化漏洞知识的学习,先了解基础的“类”、“对象”、“实例化”等基础知识即可,之后随着相关知识的深入,可以深入了面向对象编程。

2、类和对象

类是定义了一件事物的抽象特点,他将数据的形式以及这些数据上的操作封装在一起。类的内部由成员变量(属性)和成员函数(方法)构成,

  • 成员变量:定义在类内部的变量,该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可成为对象的属性
  • 成员函数:定义在类的内部与特定对象相关联的函数。成员函数也称为方法,它用于执行特定的操作,并可以访问和操作类的属性,通过使用关键字function来定义成员函数。
// 定义类的语法格式
class class_name
{
    //类中定义的属性和方法
}
// 定义一个Person类
class Person
{
    //类中定义的属性和方法
    // 属性
    public $name;        // 姓名
    public $age;         // 年龄
    // 成员函数
    public function tell(){
        print($this->name."今年".$this->age."岁!");                        
    } 
}

对象是类实例化后的结果。在PHP中定义好类之后,便可以使用 new 关键字实例化一个类的对象。 其语法格式如下所示:

$object_name = new class_name();
<?php
    class Person
    {
        public $name;        // 姓名
        public $age;         // 年龄
        // 成员函数
        public function tell(){
            print($this->name."今年".$this->age."岁!");                        
        } 
    }
    $p = new Person();		  // 创建 Person 类的实例,即对象,名为$p
    $p -> name = "张三";	  // 给对象的 name 属性赋值
    $p -> age = 18;			  //
    echo $p -> tell();		  // 张三今年18岁!
?>

3、类的常见修饰符介绍

  • private
    private表示私有的,通过 private 关键字修饰的字段和方法只能在类的内部使用,不能通过类的实例化对象调用,也不能通过类的子类调用。
  • protected
    protected表示受保护的,只能在类本身和子类中使用
  • public
    public关键字修饰的字段或者方法表示它是公共的,即在PHP的任何位置都可以通过对象名来访问该字段和方法。同时,public也是字段和方法的默认修饰符。

4、构造函数与析构函数

构造函数在类的实例化对象时自动执行,在这里可以对成员进行初始化,或者执行一些特殊操作。与它对应的还有一个析构函数,析构函数在实例化对象销毁时自动执行。它通常用于执行一些清理资源的工作,例如释放内存、删除变量和关闭数据库连接等。

1)、构造函数

PHP 中,构造函数的名称被统一命名为__construct()。 也就是说,如果在一个类中声明一个命名为__construct()的函数,那么该函数将被当成是一个构造函数,并且在建立对象实例时被执行。构造函数的语法格式如下所示:

function __construct([参数列表]){
    // 构造函数体
}
<?php
    class Student{
        private $name;
        private $age;
        function __construct()
        {
            $this->name = "zhangsan";
            $this->age = 18;
        }
        public function toString(){
            echo $this->name."今年".$this->age."岁。";
        }
    }
    $s = new Student();		// 实例化对象的时候,自动去调用构造函数__construct,对属性进行初始化
    $s->toString();
?>

2)、析构函数

析构函数也有一个统一的命名,即__destruct()。 析构函数允许在使用一个对象之后执行任意代码来清除内存。默认时仅仅释放对象属性所占用的内存并删除对象相关的资源。与构造函数不同的是,析构函数不接受任何参数。

<?php
    class Counter{
        private static $count = 0;
        function __construct()
        {
            self::$count++;
        } 
        function __destruct()
        {
            self::$count--;
        }
        function getCount()
        {
            return self::$count;
        }
    }
    $num1 = new Counter();				// 实例化对象,触发构造方法,count的值+1,变为1
    echo $num1->getCount()."<br>";		// 1
    $num2 = new Counter();				// 实例化对象,count的值+1,变为2
    echo $num2->getCount()."<br>";      // 2
    $num2 = NULL;                   	// 销毁对象$num2,count的值-1,变为1
    echo $num1->getCount()."<br>";      // 1
?>

二、序列化基础知识

1、序列化的作用

序列化是将对象的状态信息(属性)转换为可以存储或者传输的字符串形式的过程。将对象或者数组转化为可存储/传输的字符串

在php中使用函数serialize()来将对象或者数组进行序列化,并返回一个包含字节流的字符串来表示

2、序列化之后的表达式

// 所有序列化之后的格式第一位都是数据类型的英文字母的简写
<?php
	echo serialize(null);            // N;
	echo serialize(666);             // i:666;
	echo serialize(66.6);            // d:66.599999999999994315658113919198513031005859375;
	echo serialize(true);            // b:1;
	echo serialize(false);           // b:0;
	echo serialize("benben");        // s:6(长度):"benben";(如果字符串中有双引号“"”,序列化之后,被双引号闭合,正因为有前面字符串的长度,所以才可以区分哪个是字符串内容中的双引号)
	echo serialize(array('benben','dazhuang','laoliu'))        //  a:3:{i:0;s:6:"benben";i:1;s:8:"dazhuang";i:2;s:6:"laoliu";}
?>

常见的序列化之后的数据类型:

  • aarray 数组型
  • bboolean 布尔型
  • ddouble 浮点型
  • iinteger 整数型
  • robjec reference 对象引用
  • snon-escaped binary string 非转义的二进制字符串
  • Sescaped binary string 转义的二进制字符串
  • Ccustom object 自定义对象
  • Oclass 对象
  • Nnull
  • Rpointer reference 指针引用
  • Uunicode string Unicode 编码的字符串

3、对象序列化

  • 不能序列化“类”,可以序列化“对象”;只序列化成员变量,不序列化成员函数

    <?php
    class test{
        public $pub='benben';
        function jineng(){
            echo $this->pub;
        }
    }
    $a = new test();
    echo serialize($a);        // O:4:"test":1:{s:3:"pub";s:6:"benben";}
    ?>
    

    "对象"序列化之后的解释:

    • OObject
    • 4:类名长度
    • "test":表示类名
    • 1:成员属性数量
    • s:变量名pub的类型为字符串
    • 3:变量名的长度
    • "pub":变量名
    • s:变量值的类型为字符串
    • 6:变量值的长度
    • "benben":变量值
  • private修饰符修饰的私有属性在序列化后,在私有属性名前加“%00类名%00”(这里的%00为空字符(Null)的URL编码,实际是看不到的)。

    <?php
    	class test{
        private $pub='benben';
        function jineng(){
            echo $this->pub;
        }
    	}
    	$a = new test();
    	echo serialize($a);               // O:4:"test":1:{s:9:"testpub";s:6:"benben";}
    	echo urlencode(serialize($a));    // O%3A4%3A%22test%22%3A1%3A%7Bs%3A9%3A%22%00test%00pub%22%3Bs%3A6%3A%22benben%22%3B%7D
    ?>
    

    当属性$pubprivate修饰符修饰时,将“对象”序列化之后,和上一个例子的不同点在于:s:9:"testpub",如果使用URL编码输出后,会看到test前后会有%00,所以成员属性名的长度为9

  • protected修饰符修饰的成员属性在序列化后,会在变量名前加“%00*%00”(这里的%00为空字符(Null)的URL编码,实际是看不到的)。

    <?php
    class test{
        protected $pub='benben';
        function jineng(){
            echo $this->pub;
        }
    }
    $a = new test();
    echo serialize($a);        // O:4:"test":1:{s:6:"*pub";s:6:"benben";}
    ?>
    
  • 当我们序列化一个对象,该对象的成员变量的值为实例化后的另一个对象时,其序列化后,变量的值为另一个对象序列化后的值。

    <?php
    class test1{
        var $pub='benben';
        function jineng(){
            echo $this->pub;
        }
    }
    class test2{
        var $ben;
        function __construct(){
            $this->ben=new test1();
        }
    }
    $a = new test2();
    echo serialize($a);           // O:5:"test2":1:{s:3:"ben";O:5:"test1":1:{s:3:"pub";s:6:"benben";}}
    ?>
    

三、反序列化

1、反序列化的作用

将序列化后的字符串还原成实例化的对象
在这里插入图片描述

2、反序列化的特性

  • 反序列化之后的内容为一个对象

    <?php
    class test {
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
            echo $this->a;
        }
    }
    $d = serialize(new test());
    echo $d;                     // "对象"序列化:O:4:"test":3:{s:1:"a";s:6:"benben";s:4:"*b";i:666;s:7:"testc";b:0;}
    var_dump(unserialize($d));   // object(test)#1 (3) {  ["a"]=>  string(6) "benben"  ["b":protected]=>  int(666)  ["c":"test":private]=>  bool(false)}
    ?>
    
  • 反序列化生成的对象里的值,由反序列化里的值提供;与原有类预定义的值无关

    <?php
    class test {
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
            echo $this->a;
        }
    }
    // 将序列化之后的字符串中变量a的值,改为dazhang,将私有属性c的值改为true
    $d = 'O:4:"test":3:{s:1:"a";s:8:"dazhuang";s:4:"%00*%00b";i:666;s:7:"%00test%00c";b:1;}';
    $d = urldecode($d);
    // 反序列化之后对象的值与原有类中的值无关,而只与反序列化中的值有关
    var_dump(unserialize($d));  // object(test)#1 (3) {  ["a"]=>  string(8) "dazhuang"  ["b":protected]=>  int(666)  ["c":"test":private]=>  bool(true)}
    ?>
    
  • 反序列化不触发类的成员方法(除魔术方法以外);需要调用方法后才能触发(原有类必须存在)

    <?php
    class test {
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
            echo $this->a;
        }
    }
    $d = 'O:4:"test":3:{s:1:"a";s:8:"dazhuang";s:4:"%00*%00b";i:666;s:7:"%00test%00c";b:1;}';
    $e = urldecode($d);
    $f = unserialize($e);
    $f->displayVar();        // 反序列化后,生成对象,调用displayVar(),输出:dazhuang
    ?>
    

以上知识总结来自橙子科技php反序列化漏洞学习,并结合自己的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WORD模板如何自定义并使用?

文章目录 0.引言1.新建WORD2.WORD另存为模板3.使用模板 0.引言 使用Word模板可以提高文档处理的一致性、效率和专业性&#xff0c;同时也方便了更新和维护。对于需要频繁创建或修改文档的组织或个人来说&#xff0c;使用Word模板是一个非常实用的工具。本文总结Word模板自定义并…

Docker数据管理和镜像创建

Docker数据管理和镜像创建 一、Docker的数据管理1、数据卷2、数据卷容器3、端口映射4、容器互联&#xff08;使用centos镜像&#xff09; 二、Docker 镜像的创建1、基于现有镜像创建2、基于本地模板创建3、基于Dockerfile创建3.1 联合文件系统&#xff08;UnionFS&#xff09;3…

Docker 的前世今生

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

19 数组静态初始化练习

语法&#xff1a; 数据类型[ ] 数组名称 {元素1&#xff0c;元素2&#xff0c;元素3}; public class Demo1 {public static void main(String[] args) {int[] arr {0,1,2,3};System.out.println(arr);System.out.println(arr[0]);System.out.println(arr[1]);System.out.pri…

线性链表的实现

线性链表简介 线性表的链式存储结构称为线性链表&#xff0c;如图1所示&#xff0c;线性链表将存储空间划分成若干的小块&#xff0c;每块占用若干个字节&#xff0c;这些小块称为存储结点。将其中的存储结点分为两个部分&#xff0c;一部分用于存储数据元素的值&#xff0c;称…

vue中如何通过webpack-bundle-analyzer打包分析工具进行配置优化

vue中随着项目的不断功能迭代和开发&#xff0c;项目文件越来越多&#xff0c;项目的打包文件也越来越大。如何对打包文件进行分析优化&#xff0c;减小打包文件大小呢&#xff1f;可以通过webpack-bundle-analyzer 这个打包分析工具进行解决。 1、webpack-bundle-analyzer的安…

传输层协议 TCP与UDP

目录 传输层端口号端口号范围划分 0-65535认识知名端口号(Well-Know Port Number)netstatpidofxargs UDP协议UDP协议段格式UDP的特点面向数据报UDP的缓冲区基于UDP的应用层协议 TCP协议TCP协议段格式确认应答(ACK)机制超时重传机制连接管理机制&#xff1a;tcp的三次握手和四次…

自然语言处理基础详解入门

1、自然语言的概念 自然语言是指人类社会约定俗成的&#xff0c;并且区别于人工语言&#xff08;如计算机程序&#xff09;的语言&#xff0c;&#xff0c;是自然而然的随着人类社会发展演变而来的语言&#xff0c;它是人类学习生活的重要工具。 2、自然语言处理概述 自然语言…

Kubernetes对象深入学习之四:对象属性编码实战

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《Kubernetes对象深入学习》系列的第四篇&#xff0c;前面咱们读源码和文档&#xff0c;从理论上学习了kubernetes的对象相关的知识&#xff…

【算法基础:搜索与图论】3.6 二分图(染色法判定二分图匈牙利算法)

文章目录 二分图介绍染色法判定二分图例题&#xff1a;860. 染色法判定二分图 匈牙利匹配二分图最大匹配匈牙利匹配算法思想例题&#xff1a;861. 二分图的最大匹配 二分图介绍 https://oi-wiki.org/graph/bi-graph/ 二分图是图论中的一个概念&#xff0c;它的所有节点可以被…

群组变量选择、组惩罚group lasso套索模型预测新生儿出生体重风险因素数据和交叉验证、可视化...

原文链接&#xff1a;http://tecdat.cn/?p25158 本文介绍具有分组惩罚的线性回归、GLM和Cox回归模型的正则化路径。这包括组选择方法&#xff0c;如组lasso套索、组MCP和组SCAD&#xff0c;以及双级选择方法&#xff0c;如组指数lasso、组MCP&#xff08;点击文末“阅读原文”…

htmlCSS-----背景样式

目录 前言&#xff1a; 背景样式 1.背景颜色 background-color 2.背景图片 background-image 背景的权重比较 代码示例&#xff1a; 前言&#xff1a; 很久没写文章了&#xff0c;会不会想我呢&#xff01;今天我们开始学习html和CSS的背景样式以及文字样式&#xff…

井川里予是谁呢?是中国人,还是日本人?

井川里予是抖音上的一个网红&#xff0c;名字叫庞欣然。 井川里予不是日本人&#xff0c;她是地地道道的中国人。 井川里予2001年6月出生于浙江省杭州市&#xff0c;现在在广东湛江发展。她毕业于浙江经济职业技术学院&#xff0c;抖音女网红&#xff0c;粉丝高达一千多万&…

Day 64:集成学习之 AdaBoosting (2. 树桩分类器)

做了一个超类, 用于支持不同的基础分类器. 这里为了减少代码量, 只实现了树桩分类器.树桩分类器每次只将数据分成两堆, 与决策树相比, 简单至极. 当然, 这里处理的是实型数据, 而 ID3 处理的是符号型数据. 抽象分类器代码&#xff1a; package dl;import java.util.Random;im…

图像处理之LoG算子(高斯拉普拉斯)

LoG算子&#xff08;高斯拉普拉斯算子&#xff09; LoG算子是由拉普拉斯算子改进而来。拉普拉斯算子是二阶导数算子&#xff0c;是一个标量&#xff0c;具有线性、位移不变性&#xff0c;其传函在频域空间的原点为0。所有经过拉普拉斯算子滤波的图像具有零平均灰度。但是该算子…

栈OJ(C++)

文章目录 1.最小栈2.栈的压入、弹出序列3.逆波兰表达式&#xff08;后缀表达式&#xff09;求值3.1后缀表达式求值3.2中缀表达式转后缀表达式3.3带有括号的中缀表达式转后缀表达式 1.最小栈 class MinStack { public:MinStack(){}void push(int val){_st.push(val);//empty放在…

MQTT网关 5G物联网网关 PLC控制工业网关

MQTT网关&#xff0c;两个以上的节点之间通信的新型网关&#xff0c;网络节点之间通过互连来实现双向通信。支持PLC协议转MQTT&#xff0c;实现plc数据采集上云&#xff0c;物联网云平台对接&#xff0c;广泛应用于工业自动化plc远程监测控制。 计讯物联5G MQTT物联网网关TG463…

设计模式-单例模式进阶

在前面的文章(设计模式-单例模式)中&#xff0c;我们分别介绍了四种单例设计模式&#xff0c;包括普通恶汉式单例、双重检查锁单例(DCL)、静态内部类单例以及枚举单例。但是&#xff0c;这四种模式还有一些问题我们没有仔细分析&#xff0c;以至于我们无法深入分析他们的优点以…

【面试题】万字总结MYSQL面试题

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 1、三大范式 2、DML 语句和 DDL 语句区别 3、主键和外键的区别 4、drop、delete、truncate 区别 5、基础架构 6、MyISAM 和 InnoDB 有什么区别&#xff1f; 7、推荐自增id作为…

【mac系统】mac系统调整妙控鼠标速度

当下环境&#xff1a; mac系统版本&#xff0c;其他系统应该也可以&#xff0c;大家可以自行试下&#xff1a; 鼠标 mac妙控鼠标&#xff0c;型号A1657 问题描述&#xff1a; 通过mac系统自带的鼠标速度调节按钮&#xff0c;调到最大后还是感觉移动速度哦过慢 问题解决&…