序列化原理

序列化是指将对象信息转换为可存储或可传输的过程

序列化之后的对应关系:

布尔:b:value
整数:i:value
字符串:s:length:"value"
数组:a:<length>:{key,value paris}
对象:O:<class_name_length>:
NULL:N

最终格式
<class_name>:<number_of_properties>:{<properties>}

例如下面一个序列化例子

class persion
{
    public $name;
    public $age=19;
    public $sex;
}

serialize()序列化之后:

O:6:"persion":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}
对象:对象名长度:对象名:属性数:{字符串:长度:名字;属性为空;字符串:长度:名字;整数:值;字符串:长度:名字;空;}

利用反序列化漏洞的条件:

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

常见魔术方法:

_construst:对象创建
_destrust:对象销毁
_toString:对象被当做一个字符串使用
_sleep:序列化对象前调用(返回一个数组
_wakeup:反序列化恢复对象前调用
_call:调用对象中不存在的方法时自动调用
_get:从不可访问的属性读取数据

技巧

_wakeup失效: PHP5-5.6.25,PHP7.-7.0.10

当属性的个数不正确的时候,PHP不会调用__wakeup

bypass反序列化正则:使用正则/[oc]:\d+:/i来过滤反序列化字符,可以在O字段的对象长度前面加个+来绕过

Exception绕过:假设某类B,其flag在__desturct中,但因为后面又throw导致__destruct不会执行,这是构造属性为O:1:"B":1{1},解析错误但是类名是对的,所以会调用该类的__desturct

index.php
<?php

class SoFun{
  public $file='index.php';
  
  function __destruct(){
    if(!empty($this->file)){
      if(strchr($this-> file,"\\")===false &&  strchr($this->file, '/')===false){
        echo "<br>";
        show_source(dirname (__FILE__).'/'.$this ->file);}
      else
        die('Wrong filename.');
      }
    }
    
  function __wakeup(){ 
    $this-> file='index.php'; 
    }  
    
  public function __toString(){return '' ;}}
       
  if (!isset($_GET['file'])){
    show_source('index.php');
  } 
  else
  { 
    $file = $_GET['file']; 
    echo unserialize($file); 
  } 
?>  <!--key in flag.php-->



在flag.php里面有flag,但是因为wakeup函数的问题,他在反序列化的时候回把file名自动赋值为index.php,这时利用__wakeup()函数的漏洞,即输入错误的属性数,可以导致其不会运行,从而代入flag.php来获取最后的结果

标签: none

评论已关闭