buuctf系列解题思路祥讲--[网鼎杯 2020 青龙组]AreUSerialz1——文件含有漏洞,PHP代码审计,php伪协议,php反序列化

1、解题思路

打开题目是一串代码,好耶是我们最喜欢的代码审计

process();
    }
    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }
    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }
    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }
    private function output($s) {
        echo "[Result]: 
"; echo $s; } function __destruct() { if($this->op === "2") $this->op = "1"; $this->content = ""; $this->process(); } } function is_valid($s) { for($i = 0; $i < strlen($s); $i++) if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125)) return false; return true; } if(isset($_GET{'str'})) { $str = (string)$_GET['str']; if(is_valid($str)) { $obj = unserialize($str); } }

解题流程

分析代码可以得到以下关键信息

1、接收str参数并进行反序列化——提交序列化数据str

2、在提交前对str进行过滤,如果字符中包含ascii值不在该范围的就直接返回false

3、FileHandler类包含三个属性$op;$filename;$content,且有俩个魔术函数其中__destruct是一定会执行的,然后可以看到该函数是对op进行判断了,是否强等于“2”,如果等于就赋值为一然后content置空,然后在执行process()

4、然后看process(),如果op=1就执行write函数,op等于2就执行read()函数(read就是读,write就是写

破题关键

分析一下上述流程那到这里就已经可以知道怎么得到flag了——序列化一个FileHandler对象,然后设置他的

op为2 ——(这里主要是destruct函数是强等于字符串2,而process是弱等于,那就可以让op等于数值2从而绕过destruct函数)

,filename等于flag.php,content随便等于啥都行,这样答案就出来了吗?

随后我们输出序列化字符str=O:11:"FileHandler":3:{s:5:"*op";i:2;s:11:"*filename";s:8:"flag.php";s:10:"*content";s:5:"sssss";}

然后我们会发现并没有得到flag反而是bad hack,为什么呢?

因为is_valid对我们的str进行了过滤,而我们序列化非公有属性时输出的属性前会有一些不可见的字符,所以会被拦截,所以我们把前面的字符删了就行(虽然这里可以直接把属性设为公有的就行,主要是为了引出知识点。。。)然后我们得到str=O:11:"FileHandler":3:{s:5:"op";i:2;s:11:"filename";s:8:"flag.php";s:10:"content";s:5:"sssss";}

随后就可以得到flag,当然这个flag是被隐藏了的,要查看网页源码才能看到

如果想能直接看到flag,可以使用php的filter伪协议就行base64编码

2、涉及关键知识点和疑惑解析

1、PHP序列化

含有private和protected权限的变量时,会在变量名前添加ASCII码为0的不可见字符,这些字符在显示和输出时可能不易察觉,甚至导致数据截断。为了清晰查看,可将序列化后的字符串进行urlencode编码后打印输出

        private私有属性序列化时:\x00类名\x00属性名

        protected受保护属性序列化时:\x00*\x00属性名

2、php魔术方法:

__construct:用于在创建对象时自动调用,主要用于初始化对象。

__destruct:它在对象被销毁时自动调用。这通常发生在对象的所有引用都被删除或者脚本执行结束时。

3、伪协议:filter

phpfilter,关键功能是在读取文件内容时对数据进行预处理(比如编码),这个过程会绕过 PHP 的直接解析执行能直接获取文件的源码

基本格式如下: php  ://filter/[过滤方式]/[过滤器]/resource=[目标文件]

4、强等于弱等于

比较符号名称校验规则核心特点
==弱等于只校验「值是否相等」,不校验「数据类型」会自动转换两边数据类型后比较
===强等于同时校验「值相等」+「数据类型完全一致」不转换类型,直接严格对比

posted @ 2026-01-12 09:47  clnchanpin  阅读(2)  评论(0)    收藏  举报