php反序列化漏洞
第一周
学习php反序列化漏洞
要求:理解php反序列化原理
了解常用魔术方法的触发条件
能够自己构造反序列链
学习pop链的构造和一些常见的反序列化姿势
最少做三道相关的题目(难度不限),并写出wp
Php是一种运行在服务器端的HTML脚本编程语言。该语言可以让web开发人员快速的书写动态生成的网页。
1. 序列化和反序列化是什么
序列化:变量转换为可保存或传输的字符串的过程;
反序列化:把序列化的字符串再转化成原来的变量使用
作用:可轻松地存储和传输数据,使程序更具维护性、
序列化是为了方便于数据的传输,形象化理解就像物流的过程。你想把一张桌子通过从a–>b,一张桌子肯定不好运输,因此需要把它拆开(这个拆的过程就是序列化);等到达了b需要把他组装起来(装的过程就是反序列化)。
Php进行序列化的目的是保存一个对象,方便以后重用。
2. 为什么会有序列化
序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构
3. 魔术方法
魔术方法是PHP面向对象中特有的特性。它们在特定的情况下被触发,都是以双下划线开头,你可以把它们理解为钩子,利用模式方法可以轻松实现PHP面向对象中重载。魔术方法是一种特殊的方法,像函数但又不是,当对对象执行某些操作时会覆盖 PHP 的默认操作。以‘__’+字符串的一些默认方法,这些方法对后面会讲的序列化与反序列化漏洞起到了非常大的作用
魔术方法的调用是在该类序列化或者反序列化的同时自动完成的,不需要人工干预,这就非常符合我们的想法,因此只要魔术方法中出现了一些我们能利用的函数,我们就能通过反序列化中对其对象属性的操控来实现对这些函数的操控,进而达到我们发动攻击的目的。
1.__construct,__destruct
__constuct构建对象的时被调用;
__destruct明确销毁对象或脚本结束时被调用;
2.__get,__set
__set当给不可访问或不存在属性赋值时被调用
__get读取不可访问或不存在属性时被调用
3.__isset,__unset
__isset对不可访问或不存在的属性调用isset()或empty()时被调用
__unset对不可访问或不存在的属性进行unset时被调用
4.__sleep,__wakeup
__sleep当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
__wakeup当使用unserialize时被调用,可用于做些对象的初始化操作
4. POP 链的介绍
找POP链 这是 整个反序列化漏洞中,最容易让人产生快感的一个部分,像极了高达、拼图、乐高、魔方… 诸如此类
ROP 的全称是面向返回编程(Return-Oriented Programing),ROP 链构造中是寻找当前系统环境中或者 内存环境里已经存在的 、具有固定地址且带有返回操作的指令集,将这些本来无害的片段拼接起来,形成一个连续的层层递进的调用链,最终达到我们的执行 libc 中函数或者是 systemcall 的目的
POP 面向属性编程(Property-Oriented Programing) 常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击者邪恶的目的
说的再具体一点就是 ROP 是通过栈溢出实现控制指令的执行流程,而我们的反序列化是通过控制对象的属性从而实现控制程序的执行流程,进而达成利用本身无害的代码进行有害操作的目的~
练习的题目:
因为刚刚入门,不太会用php语言和phpstorm。对于漏洞的查找也是一知半解。所以我主要练习的是基础的知识,没有实战。
先创建一个php对象
运行结果如下 :
其实这里我不太明白,网上的运行结果是This is a string我这个后面多了个//test.php是版本的原因吗
接下来开始尝试使用magic函数,在类中添加一个magic函数:
<?php class TestClass { //一个变量 public $variable = 'This is a string'; //一个简单的方法 public function PrintVariable() { echo $this->variable.'<br />'; } //Constructor public function __construct() { echo '__construct<br />'; } //Destructor public function __destruct() { echo '__destruct<br />'; } //call public function __toString() { return '__toString<br />'; } } //创建一个对象 //__construct会被调用 $object = new TestClass(); //创建一个方法 //‘This is a string’将会被输出 $object->PrintVariable(); //对象被当作一个字符串 //toString会被调用 echo $object; //php脚本要结束时,__destruct会被调用 ?> //test1.php
运行结果:
几个魔法函数就被依次调用了。
反序列化漏洞测试代码:
我们要传入一个参数flag,并且将传入的值放入反序列化函数中执行,所以我们要传入的应该是一个序列化后的字符串,此时我们应该类vFREE进行序列化
运行结果: