文章目录
- 几种常用的魔术方法
- 1、__destruct()
- 2、__tostring()
- 3、__call()
- 4、__get()
- 5、__set()
- 6、__sleep()
- 7、__wakeup()
- 8、__isset()
- 9、__unset()
- 9、__invoke()
- 三种变量属性
- 极客2019 PHP
- php原生类
几种常用的魔术方法
1、__destruct()
当删除一个对象或对象操作终止时被调用,其最主要的作用是拿来做垃圾回收机制。当对象销毁时会调用此方法,对象销毁:1.用户主动销毁对象,使用unset()
函数;2.当程序结束时由引擎自动销毁。
2、__tostring()
在对象当作字符串的时候会被调用。但是需要注意的是,执行完__toString()
之后,会有返回值。
3、__call()
调用某个方法,若方法存在,则直接调用;若不存在,则会调用__call()
方法。
4、__get()
读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get()
魔术方法。
5、__set()
设置一个对象的属性时,若属性存在,则直接赋值;若属性不存在或者无法访问(私有)的属性时,则会调用__set()
函数。
__set($name, $value)
- 用来为私有成员属性设置属性值;
- 第一个参数为需要设置值多的属性名,第二个参数为需要设置的属性值,
__set
方法没有返回值。
6、__sleep()
serialize()
之前被调用,可以指定要序列化的对象属性。
7、__wakeup()
反序列化恢复对象之前调用该方法,也就是使用unserialize()
之前会先调用__wakeup()
。
var_dump
会输出反序列化内容。
8、__isset()
检测对象的某个属性是否存在时执行该函数,当对不可访问属性调用isset()
或empty()
时,触发__isset()
。
9、__unset()
在不可访问的属性上使用unset()
时触发, 或销毁对象的某个属性时执行此函数。
unset()
函数不仅触发__unset()
,而且会触发__destruct()
。- 三种对象变量属性:
public
:在本类内部、外部类、子类中都可以访问;protected
:只在本类或子类或父类中可以访问;private
:在本类内部可以访问。- 序列化数据显示:
private
属性序列的时候格式是%00类名%00成员名
protected
属性序列的时候格式是%00*%00成员名
- 使用
new
是创建外部类(测试类),子类是通过继承extends
父类得到的。
9、__invoke()
当调用函数的方式调用一个对象时触发。
三种变量属性
- 三种对象变量属性:
public
:在本类内部、外部类、子类中都可以访问;protected
:只在本类或子类或父类中可以访问;private
:在本类内部可以访问。
- 序列化数据显示:
private
属性序列的时候格式是%00类名%00成员名
protected
属性序列的时候格式是%00*%00成员名
极客2019 PHP
反序列化利用大概分为三类:
- 魔术方法的调用逻辑,如触发条件;
- 语言原生类的调用逻辑,如
SoapClient
; - 语言自身的安全缺陷,如
CVE-2016-7124
.
首先,通过目录扫描可以发现网站源码保存在www.zip
中(这里就不作叙述);
index.php
中包含flag.php
,并且接收select
传参,并且对传参内容进行反序列化。
在flag.php
中存在一个className
,而且flag在__destruct()
魔术方法中,有两种方式触发__destruct()
魔术方法:1.用户主动销毁对象,使用unset()
函数;2.当程序结束时由引擎自动销毁。也就是说,当程序执行完,必定会触发__destruct()
魔术方法。因此,我们只需要满足__destruct()
魔术方法中的两个条件:username=admin&password=100
。由于__wakeup()
的存在,使得index.php中的unserialize
执行之前,就会自动触发__wakeup()
。
故获取flag的关键在于:绕过__wakeup()
。这里可以使用CVE-2016-7124进行绕过__wakeup()
。CVE-2016-7124:对象中的属性个数超过实际属性个数会绕过__wakeup()
。
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
将2
改为3
,即可获取flag。
php原生类
php原生类
-
PHP有哪些原生类
//查找PHP所有原生类 <?php $classes = get_declared_classes(); foreach ($classes as $class) { $methods = get_class_methods($class); foreach ($methods as $method) { if (in_array($method, array( '__destruct', '__toString', '__wakeup', '__call', '__callStatic', '__get', '__set', '__isset', '__unset', '__invoke', '__set_state' ))) { print $class . '::' . $method . "\n"; } } }
-
常见使用的原生类
浅析PHP原生类 -
配合官方文档利用php原生类
-
反序列化字符逃逸
[安恒月赛]反序列化字符逃逸