一个挺不错的链接:https://www.cnblogs.com/Mrsm1th/p/6835592.html
0x01 原理
序列化与反序列化简介
序列化:把复杂的数据类型压缩到一个字符串中 数据类型可以是数组,字符串,对象等 函数 : serialize()
反序列化:恢复原先被序列化的变量 函数: unserialize()
例子
在本地搭建PHP环境,测试序列化和反序列化这两个函数的原理1
2
3
4
5
6
7
8
9
10<?php
$a = "hello world";
$b = array("hello","world");
$c = 12345678;
echo serialize($a);
echo "<br>";
echo serialize($b);
echo "<br>";
echo serialize($c);
?>
输出为:1
2
3s:11:"hello world"; // 序列化字符串
a:2:{i:0;s:5:"hello";i:1;s:5:"world";} 序列化数组
i:12345678;
1 | <?php |
输出为:1
O:5:"hello":1:{s:1:"d";s:11:"hello,world";}//序列化对象 首字母代表参数类型 O->Objext S->String...
PHP 对不同类型的数据用不同的字母进行标示,Yahoo 开发网站提供的Using Serialized PHP with
Yahoo! Web Services 一文中给出所有的字母标示及其含义:1
2
3
4
5
6
7
8
9
10
11
12a - array 数组
b - boolean 布尔
d - double
i - integer 整数
o - common object 对象
r - reference
s - string 字符串
C - custom object 自定义对象
O - class 类
N - null
R - pointer reference
U - unicode string
具体讲解见如链接 https://blog.csdn.net/iamduoluo/article/details/8491746
魔术方法
construct(), destruct(), call(), callStatic(), get(), set(), isset(), unset(),
sleep(), wakeup(), toString(), invoke(), set_state(), clone() 和 __debugInfo() 等方法在 PHP 中被称为”魔术方法”(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。1
PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
序列化public private protect参数产生不同结果
1 | <?php |
test类定义了三个不同类型(私有,公有,保护)但是值相同的字符串,序列化输出的值不相同 O:4:”test”:3:{s:11:” test test1”;s:5:”hello”;s:5:”test2”;s:5:”hello”;s:8:” * test3”;s:5:”hello”;}
通过对网页抓取输出是这样的 O:4:”test”:3:{s:11:”\00test\00test1”;s:5:”hello”;s:5:”test2”;s:5:”hello”;s:8:”\00*\00test3”;s:5:”hello”;}
private的参数被反序列化后变成 \00test\00test1 public的参数变成 test2 protected的参数变成 \00*\00test3
CTF比赛题目分析
1 | <?php |
大致思路 首先是一个类sercet 接受$cmd,绕过正则 ,反序列化。覆盖$file的值,绕过 __wakeup,显示the_next.php的源码
1 | <?php |
绕过正则可以用+号 问题是如何绕过__weakup 百度一下 发现这是一个CVE漏洞 ==》当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)
O:6:”sercet”:1: 也就是输入比1大的值就行 如O:6:”sercet”:2:
1
O:+6:"sercet":1:{s:12:" sercet file";s:12:"the_next.php";}