博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅析PHP反序列化漏洞之PHP常见魔术方法(一)
阅读量:5284 次
发布时间:2019-06-14

本文共 5272 字,大约阅读时间需要 17 分钟。

  作为一个学习web安全的菜鸟,前段时间被人问到PHP反序列化相关的问题,以前的博客中是有这样一篇反序列化漏洞的利用文章的。但是好久过去了,好多的东西已经记得不是很清楚。所以这里尽可能写一篇详细点的文章来做一下记录。

  我们来参考这里:

https://secure.php.net/manual/zh/language.oop5.magic.php

 

我们根据官方文档中的解释,一个一个来进行测试。

    __construct() 和 __destruct()

    __construct()被称为构造方法,也就是在创造一个对象时候,首先会去执行的一个方法。

 

我写了这样的一个demo来做测试:

 

class test {    private $flag = '';    public $filename = '';    public $data = '';    function __construct($filename, $data) {        $this->filename = $filename;        $this->data = $data;        echo 'construct function in test class';        echo "
"; }} $a = new test('test.txt', 'data');

 

测试结果:

同样的,我们编写一个类的析构方法,__destruct()

析构函数的作用:

代码如下:

class test {    private $flag = '';    public $filename = '';    public $data = '';    function __construct($filename, $data) {        $this->filename = $filename;        $this->data = $data;        echo 'construct function in test class';        echo "
"; } function __destruct() { echo 'destruct function in test class'; echo "
"; }}$a = new test('test.txt', 'data');

运行结果:

__set()    __get()    __isset()    __unset()    作用如下:

 

 

我们一样是来写一个代码进行验证:

class test {    private $flag = '';        # 用于保存重载的数据     private $data = array();    public $filename = '';    public $content = '';    function __construct($filename, $content) {        $this->filename = $filename;        $this->content = $content;        echo 'construct function in test class';        echo "
"; } function __destruct() { echo 'destruct function in test class'; echo "
"; } function __set($key, $value) { echo 'set function in test class'; echo "
"; $this->data[$key] = $value; } function __get($key) { echo 'get function in test class'; echo "
"; if (array_key_exists($key, $this->data)) { return $this->data[$key]; } else { return null; } } function __isset($key) { echo 'isset function in test class'; echo "
"; return isset($this->data[$key]); } function __unset($key) { echo 'unset function in test class'; echo "
"; unset($this->data[$key]); } public function set_flag($flag) { $this->flag = $flag; } public function get_flag() { return $this->flag; }}$a = new test('test.txt', 'data');# __set() 被调用$a->var = 1;# __get() 被调用echo $a->var;# __isset() 被调用var_dump(isset($a->var));# __unset() 被调用unset($a->var);var_dump(isset($a->var));echo "\n";

运行结果:

我们可以看到调用的顺序为: 构造方法 => set方法(我们此时为类中并没有定义过的一个类属性进行赋值触发了set方法) => get方法 => isset方法 => unset方法 => isset方法 => 析构方法

同时也可以发现,析构方法在所有的代码被执行结束之后进行的。

    __call()    __callStatic()    

官方文档中的解释:

 

类似以上介绍过的__set()和__get(),刚刚是访问不存在或者不可访问属性时候进行的调用。现在是访问不存在或者不可访问的方法时候:

代码如下:

class test {    private $flag = '';        # 用于保存重载的数据     private $data = array();    public $filename = '';    public $content = '';    function __call($funcname, $args) {        echo 'function name is: ' . $funcname. ' args is: ' . implode(', ', $args);        echo "
"; } public static function __callStatic($funcname, $args) { echo 'static function name is: ' . $funcname. ' args is: ' . implode(', ', $args); echo "
"; } public function set_flag($flag) { $this->flag = $flag; } public function get_flag() { return $this->flag; }}$obj = new test;# 调用一个不存在或者无法访问到的方法时候将会调用__call()$obj->run('run args, test');# 调用一个不存在的静态方法,将会去调用__callStatic()$obj::run('static test');

运行结果:

看文档或者注释应该很明白了。

接下来是对于反序列化漏洞利用最重要的一些方法了。

__sleep()    __wakeup()    __toString()

写个代码来进行验证:

class test {    private $flag = '';        # 用于保存重载的数据     private $data = array();    public $filename = '';    public $content = '';    function __construct($filename, $content) {        $this->filename = $filename;        $this->content = $content;        echo 'construct function in test class';        echo "
"; } function __destruct() { echo 'destruct function in test class'; echo "
"; } # 反序列化时候触发 function __wakeup() { // file_put_contents($this->filename, $this->data); echo 'wakeup function in test class'; echo "
"; } # 一般情况用在序列化操作时候,用于保留数据 function __sleep() { echo 'sleep function in test class'; echo "
"; return array('flag', 'filename', 'data'); } # 当需要输出得到对象名称时候会调用 function __toString() { return $this->data; } public function set_flag($flag) { $this->flag = $flag; } public function get_flag() { return $this->flag; }}$key = serialize(new test('test.txt', 'test'));var_dump($key);$b = unserialize($key);

运行结果:

在进行序列化的时候,执行了__sleep()方法,在反序列化的时候执行了__wakeup()方法。

然后是__toString()方法:

class test {    private $flag = '';        # 用于保存重载的数据     private $data = array();    public $filename = '';    public $content = '';    function __construct($filename, $content) {        $this->filename = $filename;        $this->content = $content;        echo 'construct function in test class';        echo "
"; } function __destruct() { echo 'destruct function in test class'; echo "
"; } # 当需要输出得到对象名称时候会调用 function __toString() { return $this->content; }}$a = new test('test.txt', 'data');echo $a."
";

结果:

转载于:https://www.cnblogs.com/magic-zero/p/7360396.html

你可能感兴趣的文章
方维分享系统二次开发, 给评论、主题、回复、活动 加审核的功能
查看>>
Matlab parfor-loop并行运算
查看>>
string与stringbuilder的区别
查看>>
2012-01-12 16:01 hibernate注解以及简单实例
查看>>
iOS8统一的系统提示控件——UIAlertController
查看>>
PAT甲级——1101 Quick Sort (快速排序)
查看>>
python创建进程的两种方式
查看>>
1.2 基础知识——关于猪皮(GP,Generic Practice)
查看>>
迭代器Iterator
查看>>
java易错题----静态方法的调用
查看>>
php建立MySQL数据表
查看>>
最简单的线程同步的例子
查看>>
旅途上看的电影和观后感
查看>>
Ztree异步树加载
查看>>
关于IE和火狐,谷歌,Safari对Html标签Object和Embed的支持问题
查看>>
poj3320 Jessica's Reading Problem(尺取思路+STL)
查看>>
分布式计算开源框架Hadoop介绍
查看>>
安卓平台接口剖析
查看>>
坏的事情不都会带来坏的结果
查看>>
RPC的基础:调研EOS插件http_plugin
查看>>