🎼个人主页:金灰
😎作者简介:一名简单的大一学生;易编橙·终身成长社群的嘉宾.✨
专注网络空间安全服务,期待与您的交流分享~
感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️
🍊易编橙·终身成长社群🍊 : http://t.csdnimg.cn/iSLaP 期待您的加入~
免责声明:本文仅做分享...
目录
php手册
在线php运行
php在线运行,在线工具,在线编译IDE_w3cschool
序列化与反序列化
序列化是 将 一个对象 变为一个可以传输的字符串. serialize(对象) 返回 序列化后的字符串.
反序列化 就是将 一个可以传输的字符串 变为一个 可以调用的对象. unserialize(反序列化后的字符串) 返回 对象.
O:10:"normalUser":4:{s:5:"score";N;s:8:"username";s:5:"admin";s:14:"userpassword";s:8:"admin666";s:11:"*userType";N;}
url编码->
O%3A10%3A%22normalUser%22%3A4%3A%7Bs%3A5%3A%22score%22%3BN%3Bs%3A8%3A%22username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00user%00password%22%3Bs%3A8%3A%22admin666%22%3Bs%3A11%3A%22%00%2A%00userType%22%3BN%3B%7D
注意:
如果属性权限为private,那么序列化后,存储的属性名字为 %00+类名+%00+属性名
如果属性权限为protected,那么序列化后,存储的属性名字为 %00+*+%00+属性名
<?php
class Animal{
public $name;
function eat(){
echo "i can eat";
}
function sleep(){
echo "i can sleep";
}
}
$a = new Animal();
echo serialize($a);
//可将php.exe的目录添加到全局变量里面实现快速利用.
// 对象-> 字符串
O:6:"Animal":1:{s:4:"name";N;}
//O:6:" ":1:{s:4:"name";N;}
解释(翻译)---------------->
// O 有一个对象
// : 下一句
// 6 名字是6个字符
// : 下一句
//"Animal" 内容是Animal
// : 下一句
// 1 对象有一个属性
// : 下一句
// { 对象属性描述开始
// s 属性是一个字符串 string
// : 下一句
// 4 属性名字是4个字符
// : 下一句
// "name" 属性名字是name
// ; 属性名字描述完了
// N 没有值,值为null
// ; 属性值描述完了
// } 对象属性描述完了
将次字符串进行描述----------->
class Animal{
public $name;
}
结论:
反序列化和类的方法无关,不能把类方法序列化.
反序列化时,php-->
// 1 找到反序列化字符串规定的类名字
// 2 实例化这个类,但是不是调用构造方法
// 3 有了实例化的类对象,对它的属性进行赋值
// 4 执行魔术方法
// 5 返回构造好的对象
问题
1 接口是否可以序列化? no
//接口类是不含属性的,不参与反序列化.
2 匿名类是否可以序列化? no
//匿名类没有名字(类名)呀,构造不了,,,
3 trait 是否可以序列化? no
魔术方法总结:
1 魔术方法是一类 类的方法.
2 会在序列化和反序列化及其他特殊情况下,自动执行.
分类:
1 __construct
在实例化一个对象(new)时,会被自动调用.
传参时至少要保持参数的个数相同.
不允许重复声明(一个类只能用一个构造方法)
可以作为非public权限属性的初始化
2 __sleep 和 __wakeup方法
序列化时自动调用__sleep方法
返回数组中有属性名才进行反序列化 __sleep
3 __destruct方法 析构方法
类对象将要销毁,也就是脚本执行完毕后执行清理工作时自动执行
绕过:
强制将系统的进程kill
(终端 浏览器 调用的进程不一样)
4 __call 和__callstatic
对象执行类不存在的方法时候,会自动调用__call方法
直接执行类的不存在的静态方法时,会自动调用__callstatic方法
5 __get __set 和 __isset __unset魔术方法
__get 对不可访问属性或不存在属性 进行访问引用时自动调用
__set 对不可访问属性或不存在属性 进行写入时自动调用
isset($obj->zhi);
unset($obj->zhi);
6 __tostring 方法
类的实例和字符串 进行拼接或者作为字符串引用时,会自动调用__tostring方法
7 __invoke方法
当类的实例被作为函数名字执行的时候,会自动调用__invoke方法
(将一个对象直接作为函数调用)
8 __set_state 方法
文档中说 执行 var_export 时自动调用
var_export($obj);
https://www.php.net/manual/zh/language.oop5.magic.php
9 __debugInfo 方法的属性修饰符
执行var_dump时自动调用
10 __clone方法
当使用clone关键字 ,clone一个对象时,会自动调用.
php的反序列化漏洞:
1 有反序列化提交的入口
2 被反序列化的类的魔术方法,有可能被利用
1 绕过__wakeup方法
条件:
1 php5至php5.6.25 之间的版本可以绕过
2 php7到php7.0.10 之间的版本可以绕过
绕过方法:
反序列化字符串中表示属性数量的值 大于 大括号内实际属性的数量时 ,wakeup方法会被绕过.
(将属性的个数改大,大大大)
2 绕过 +号正则匹配
参数有过滤,不让输入 O:数字 的形式,试图防止反序列化某个对象
-->
O:数字 改为 O:+数字 就可以绕过上面的O:数字 过滤
O:+数字
O:+数字
例:
将环境移到本地,进行赋值,得payload,然后POST提交值.
+ = %2b
详情见--php源码 var.c 里面.
3 引用绕过相等
使用&符号表示两个变量指向相同的内存引用地址.(原理和内存地址有关)
$this->password = &$this->secrect;
// 永远指向右边变量.
4 16进制绕过
反序列化后的字符串 不能出现某个关键单词时,可以使用大S绕过
O:8:"backdoor":1:{s:4:"name";s:10:"phpinfo();";}
O:8:"backdoor":1:{S:4:"n\97me";s:10:"phpinfo();";}
//ASCII
$data='O:8:"backdoor":1:{S:4:"n\97me";s:15:"system(\'calc\');";}';
5 exception 绕过
不影响析构方法执行.
0属性-->
data='O:8:"backdoor":0:{};
6 php反序列化字符逃逸
1 可以控制某个类中的属性值
2 间接控制了某个类的反序列化字符串
3 由于存在无脑过滤,字符增减,造成 描述中字符串的长度 和实际的不一致
4 从而能够逃逸出若干个字符,实现字符可控,从而闭合前面的双引号
5 实现反序列化字符串的完全可控
例:
<?php
class backdoor{
public $m;
public $c;
}
$b = new backdoor();
$b->m = 'system";s:1:"c";s:7:"notepad";}';
$b->c = 'calc';
echo serialize($b);
//O:8:"backdoor":2:{s:1:"m";s:6:"system";s:1:"c";s:4:"calc";}
//O:8:"backdoor":2:{s:1:"m";s:6:"system";s:1:"c";s:7:"notepad";}";s:1:"c";s:4:"calc";}
//";s:1:"c";s:7:"notepad";}
//";s:1:"c";s:4:"calc";}
//-->
//O:8:"backdoor":2:{s:1:"m";s:31:"system";s:1:"c";s:7:"notepad";}";s:1:"c";s:4:"calc";}
// system";s:1:"c";s:7:"notepad";}
//如果代码对提交的反序列化的字符串进行了过滤,将里面的内容进行了替换
//比如 fuck -> loveu (每多一个字符,就相当于加到后面一个字符可控)
//未修正字符长度时,再进行反序列化,就会出现逃逸情况.