buuctf web [极客大挑战 2019]PHP

文章讲述了使用dirsearch工具扫描网站备份,发现了一个包含PHP代码的页面,通过分析`unserialize`和`serialize`函数,揭示了如何利用构造函数`__wakeup`和析构函数`__destruct`绕过安全限制获取flag的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示有备份,dirsearch扫描网站备份

GitHub - maurosoria/dirsearch: Web path scanner下载.zip格式文件

解压到python目录下

在上图位置cmd打开窗口

输入python setup.py install安装dirsearch

安装好后输入命令使用dirsearch

python dirsearch.py -u http://44296191-973d-448e-9964-d30eab452926.node4.buuoj.cn:81/ -e php

发现了www.zip压缩包

网址输入www.zip,下载zip包

打开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>

这部分代码重点为

意思是:引用class.php页面,用get方法传参,获取变量select,将select进行反序列化,@符号表示忽略可能出现的错误信息。

unserialize() 函数
unserialize() 函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

(反序列:序列转数组)

unserialize ($str )
$str:序列化的字符串(序列化字符串i表示位置,s表是大小)
如果传递的字符串不可解序列化,则返回 FALSE,并抛出异常

serialize() 函数
serialize() 函数用于序列化对象或数组,并返回一个字符串。

serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变.

(序列化:数组转序列)

serialize ($value )
$value: 要序列化的对象或数组。

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的地方

在_destuct()函数下,要求的条件是password==100,username==='admin',具体来看看各个函数

__construct
构造函数(也称为构造器)是类中的一种特殊函数,当使用 new 关键字实例化一个对象时,构造函数将会自动调用。代码中用到了 $this,它表示当前调用的对象,而且 $this 只能在类的方法中使用.

__wakeup()
__wakeup():当类外部使用`unserialize()` 时,会检查是否存在一个 `__wakeup()` 方法。如果存在,则会先调用 `__wakeup` 方法,预先准备对象需要的资源。

题目中的作用:
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
这里的作用就是先将username赋值,使我们传入的username永远为guest。

__destruct():

析构函数/方法,析构函数的作用和构造函数正好相反,析构函数只有在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被自动调用。析构函数允许我们在销毁一个对象之前执行一些特定的操作,例如关闭文件、释放结果集等。

作用:
这里的作用是,在wakeup函数调用完后,进行判断,如果password不为100为真:抛出错误回显,并利用die()函数退出当前脚本
如果为假,也就是password=100,接着强类型比较username是否=== admin 如果为真就打印flag

所以本题主要是,需要绕过wakeup函数强制将username赋值为guest。

因为在反序列化时,当前属性个数大于实际属性个数时,就会跳过__wakeup(),去执行__destruct。

尝试构造payload

"O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";s:3:"100";}"

且因为声明变量时使用的时private(私有变量),所以payload应为:

O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}

ps:补充

public 、public、protected
类中的 公有、私有、受保护成员

public 表示全局,类内部外部子类都可以访问;

private表示私有的,只有本类内部可以使用;

protected表示受保护的,只有本类或子类或父类中可以访问;

不同的访问修饰符对应的序列化也有不同。

各访问修饰符序列化后的区别:

public:属性被序列化的时候属性名还是原来的属性名,没有任何改变

protected:属性被序列化的时候属性名会变成\0*\0字段名

private:属性被序列化的时候属性名会变成\0类名\0字段名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿勉要睡觉(考试版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值