WEB漏洞——反序列化

序列化

首先说说什么是序列化

序列化是将某个对象转换为以后可以恢复的数据格式的过程。 人们经常序列化对象以将它们保存到存储中,或作为通信的一部分发送。 反序列化与从某种格式获取结构化数据并将其重建为对象的过程相反。 今天,用于序列化数据的最流行的数据格式是JSON。在此之前,它是 XML。

a:4:{i:0;i:132;i:1;s:7:"Mallory";i:2;s:4:"用户"; i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}

 

许多编程语言提供了用于序列化对象的本机功能。 这些原生格式通常提供比 JSON 或 XML 更多的功能,包括序列化过程的可定制性。 不幸的是,在对不受信任的数据进行操作时,这些原生反序列化机制的功能可能会被重新用于恶意影响。 已经发现对解串器的攻击允许拒绝服务、访问控制和远程代码执行攻击。
已知受影响的编程语言PHP、Python、Ruby、JAVA、C、C++

 

只有数据被序列化。 代码本身没有序列化。 反序列化创建一个新对象并从字节流中复制所有数据,以获得与序列化的对象相同的对象。

 

 

在PHP,通过反序列化在特定条件下可以重建php对象并执行php对象中某些magic函数。

在PHP应用中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。

举一个简单的例子

<?php
class people{
 public $name;
 public $age;
 public $sex;
 
 function __construct($name,$age,$sex){   //_construct:创建对象时初始化
  $this->name = $name;
  $this->age = $age;
  $this->sex = $sex;
 }
}
$people=new people("hhy",20,"boy");
echo serialize($people);
?>

输出结果:O:6:"people":3:{s:4:"name";s:3:"hhy";s:3:"age";i:20;s:3:"sex";s:3:"boy";}

“O”表示对象,6表示对象名长度为6

“people”为对象名,3表示有3个参数

“s”表示string对象

“i”表示int对象

 

反序列化输出

$unpeople='O:6:"people":3:{s:4:"name";s:3:"hhy";s:3:"age";i:20;s:3:"sex";s:3:"boy";}';
var_dump(unserialize($unpeople)); //输出用var_dump函数

或者 $u=unserialize('O:6:"people":3:{s:4:"name";s:3:"hhy";s:3:"age";i:20;s:3:"sex";s:3:"boy";}'); echo $u->name,$u->age,$u->sex;

输出结果:object(people)#2 (3) { ["name"]=> string(3) "hhy" ["age"]=> int(20) ["sex"]=> string(3) "boy" }

输出结果:hhy20boy

 

在JAVA中由ObjectOutputStream类中的writeObject()函数和ObjectInputStream类中的readObject()函数实现

 

PHP反序列化漏洞

原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码 执行,SQL 注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法。当进行 反序列化的时候就有可能会触发对象中的一些魔术方法

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题 

  1. unserialize()函数的参数可控
  2. php中有可以利用的类并且类中有魔术方法

常见的魔术方法

__construct(): 在创建对象时候初始化对象,一般用于对变量赋初值。

__destruct(): 和构造函数相反,当对象所在函数调用完毕后执行。

__toString():当对象被当做一个字符串使用时调用。

__sleep():序列化对象之前就调用此方法(其返回需要一个数组)

__wakeup():反序列化恢复对象之前调用该方法

__call():当调用对象中不存在的方法会自动调用该方法。

__get():在调用私有属性的时候会自动执行

__isset()在不可访问的属性上调用isset()或empty()触发

__unset()在不可访问的属性上使用unset()时触发

<head>
<meta charset="UTF-8">
</head>
<?php 
class T{
    public $test=1;
    function __construct(){
        echo '调用了_construct<br>';
    }
    function __destruct(){
        echo '调用了_destruct<br>';
    }
    //function __sleep(){
    //    echo '调用了_sleep<br>'
    //}
    function __wakeup(){
        echo '调用了_wakeup<br>';
    }
}
$t=new T();
echo $t->test;
echo "<br/>";
$t1=serialize($t);
echo $t1;
echo "<br/>";
$t2=unserialize($t1);
echo $t->test;
echo "<br/>";

 

当程序执行前,serialize() 函数会首先检查是否存在一个魔术方法__sleep.如果存在,__sleep()方法会先被调用,然后才执行序列化操作。这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则NULL被序列化,导致一个E_NOTICE错误。

unserialize()会检查是否存在一个__wakeup方法。如果存在,则会先调用 __wakeup方法,预先准备对象数据。

 

漏洞举例       


   class S{
            var $test = "pikachu";
            function __destruct(){
                echo $this->test;
            }
        }
        $s = $_GET['test'];
        @$unser = unserialize($a);

        payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
 

JAVA反序列化

WebGoat靶场

Releases · WebGoat/WebGoat (github.com)

分析一下源码

 

 大概的内容就是,用户输入了数据,对数据进行对象的还原,接着进行命令执行

 

防御

反序列化的问题是用户参数的控制问题引起的,所以好的预防措施就是不要把用户的输入或者是用户可控的参数直接放进反序列化的操作中去。

 

 

posted @ 2021-09-13 10:51  1_Ry  阅读(215)  评论(0编辑  收藏  举报