浅析PHP反序列化漏洞之PHP常见魔术方法(一)
作为一个学习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 "<br>";
}
}
$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 "<br>";
}
function __destruct() {
echo 'destruct function in test class';
echo "<br>";
}
}
$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 "<br>";
}
function __destruct() {
echo 'destruct function in test class';
echo "<br>";
}
function __set($key, $value) {
echo 'set function in test class';
echo "<br>";
$this->data[$key] = $value;
}
function __get($key) {
echo 'get function in test class';
echo "<br>";
if (array_key_exists($key, $this->data)) {
return $this->data[$key];
} else {
return null;
}
}
function __isset($key) {
echo 'isset function in test class';
echo "<br>";
return isset($this->data[$key]);
}
function __unset($key) {
echo 'unset function in test class';
echo "<br>";
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 "<br>";
}
public static function __callStatic($funcname, $args) {
echo 'static function name is: ' . $funcname. ' args is: ' . implode(', ', $args);
echo "<br>";
}
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 "<br>";
}
function __destruct() {
echo 'destruct function in test class';
echo "<br>";
}
# 反序列化时候触发
function __wakeup() {
// file_put_contents($this->filename, $this->data);
echo 'wakeup function in test class';
echo "<br>";
}
# 一般情况用在序列化操作时候,用于保留数据
function __sleep() {
echo 'sleep function in test class';
echo "<br>";
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 "<br>";
}
function __destruct() {
echo 'destruct function in test class';
echo "<br>";
}
# 当需要输出得到对象名称时候会调用
function __toString() {
return $this->content;
}
}
$a = new test('test.txt', 'data');
echo $a."<br>";
结果:

浅析PHP反序列化漏洞之PHP常见魔术方法(一)的更多相关文章
- PHP中的常见魔术方法功能作用及用法实例
概述 在面向对象编程中,PHP提供了一系列的魔术方法,这些魔术方法为编程提供了很多便利.PHP中的魔术方法通常以__(两个下划线)开始,并且不需要显示的调用而是由某种特定的条件出发. 开始之前 在总结 ...
- PHP几种常见魔术方法与魔术变量解析
原文地址:http://small.aiweimeng.top/index.php/archives/49.html 先不多说,直接上代码,如下: class Demo { private $str ...
- PHP中常见魔术方法解析
<?php class info { private $province; //省 public $city; //城市 private $myname; //姓名 //__construct( ...
- Java反序列化漏洞之殇
ref:https://xz.aliyun.com/t/2043 小结: 3.2.2版本之前的Apache-CommonsCollections存在该漏洞(不只该包)1.漏洞触发场景 在java编写的 ...
- ref:PHP反序列化漏洞成因及漏洞挖掘技巧与案例
ref:https://www.anquanke.com/post/id/84922 PHP反序列化漏洞成因及漏洞挖掘技巧与案例 一.序列化和反序列化 序列化和反序列化的目的是使得程序间传输对象会更加 ...
- Java反序列化漏洞从入门到深入(转载)
前言 学习本系列文章需要的Java基础: 了解Java基础语法及结构(菜鸟教程) 了解Java面向对象编程思想(快速理解请上知乎读故事,深入钻研建议买本<疯狂Java讲义>另外有一个刘意老 ...
- Python 反序列化漏洞学习笔记
参考文章 一篇文章带你理解漏洞之 Python 反序列化漏洞 Python Pickle/CPickle 反序列化漏洞 Python反序列化安全问题 pickle反序列化初探 前言 上面看完,请忽略下 ...
- .NET高级代码审计(第三课)Fastjson反序列化漏洞
0X00 前言 Java中的Fastjson曾经爆出了多个反序列化漏洞和Bypass版本,而在.Net领域也有一个Fastjson的库,作者官宣这是一个读写Json效率最高的的.Net 组件,使用内置 ...
- 魔术方法__sleep 和 __wakeup
感觉序列化和反序列化用得倒是比较少了,而json_encode和json_decode用得相对多,都是转化成串,进行入库.传输等.json更方便,但是序列化和反序列化结合这两个魔术方法使用倒还行< ...
随机推荐
- SceneBuilder 打不开 .fxml文件,只在任务栏显示
mark一下,今天下载官网的SceneBuilder 2.X 最近在使用JavaFX,感觉还是很酷的,可是在正常的编辑关闭SceneBuilder 之后,再次打开却打不开了 可是奇怪的是有些 .fxm ...
- hibernate 多表联合查询
以前用sql实现联合查询 是非常简单的事,只需要写sql语句就可以,第一次遇到hibernate要实现多表联合查询的时候还楞了一下.最后看了下资料,才恍然大悟,hibernate实现多表联合查询跟SQ ...
- mybatis 简单实现 left join
sql -- 表a ta (id,aname,bid) -- 表b tb (id,bname) SELECT T1.*, T2.BNAME FROM TA T1 LEFT JOIN TB T2 ON ...
- WSAStartup函数
函数WSAStartup 一.WSAStartup函数 int WSAStartup ( ...
- Javascript与数据结构系列(二)——队列的实现
队列实现 使用数组来实现队列看起来顺理成章.JavaScript 中的数组具有其他编程语言中没有的优点, 数组的 push() 方法可以在数组末尾加入元素,shift() 方法则可删除数组的第一个元素 ...
- C++ 内敛函数
在主调函数调用函数时,先将现场压入栈以保存现场-转去执行被掉函数-返回主调函数.现场出栈以恢复现场-继续往下执行. 为了减少函数调用的成本,特别是对于小型函数,C++提供了内敛函数(inline).C ...
- Linq扩展最后遗留之SelectMany,Zip,SequenceEqual源码分析
Linq扩展最后遗留之SelectMany,Zip,SequenceEqual源码分析 一: AsParallel [并行化查询] 这个函数的功效就是将计算结果多线程化.[并行计算] =>[多核 ...
- vmware开发包之vSphere Management SDK
vSphere Management SDK关于vmware管理等相关功能的.net和java的代码示例. 在其5.5的解压包中 eam:esx agent management表示esx虚机生产环境 ...
- owin Oauth
原文:http://www.cnblogs.com/richieyang/p/4918819.html 一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前 ...
- Python短路原则
1.括号内逻辑先执行 2.and优先级大于or 3.and一假为假 4.or一真为真 and:如果左边为假,返回左边值.如果左边不为假,返回右边值. or:如果左边为真,返回左边值.如果左边不为真,返 ...