phpcms头像上传漏洞引发的故事
目录
关键代码
第一次防御
第一次绕过
第二次防御
第二次绕过
第三次防御
第三次绕过
如何构造一个出错的压缩包
第四次防御
第四次绕过
本篇文章是参考某位大佬与开发人员对于文件包含漏洞的较量记录下的故事,因为要学习文件包含漏洞,就将大佬的文件作为参考来通过学习+练习的方式复现一下这次较量的全过程
故事还要从phpcms曾经火极一时的头像上传漏洞说起,因为这个漏洞,互联网上大量站点被黑,影响极为恶劣。
简单来说phpcms对头像上传是这么处理:上传上去的zip文件,它先解压好,然后删除非图片文件。
关键代码
前端代码:
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta http-equiv="X-UA-Compatible" content="ie=edge" /><title>文件上传章节练习题</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><style type="text/css">.login-box{margin-top: 100px;height: 500px;border: 1px solid #000;}body{background: white;}.btn1{width: 200px;}.d1{display: block;height: 400px;}</style>
</head>
<body><form method="post" action="upload.php" enctype="multipart/form-data"><input type="file" name="file" value=""/><input type="submit" name="submit" value="upload"/></form>
</body>
</html>
后端代码:
<?php
header("Content-Type:text/html; charset=utf-8");
require_once('pclzip.lib.php');$file = $_FILES['file'];
if ($file['size'] == 0) {exit("请勿上传空文件");
}
$name = $file['name'];
$dir = 'uploads/';
$ext = strtolower(substr(strrchr($name, '.'), 1));function check_dir($dir)
{$handle = opendir($dir);while (($f = readdir($handle)) !== false) {if (!in_array($f, array('.', '..'))) {$ext = strtolower(substr(strrchr($f, '.'), 1));if (!in_array($ext, array('jpg', 'gif', 'png'))) {unlink($dir . $f);}}}}if (!is_dir($dir)) {mkdir($dir);
}$temp_dir = $dir . 'member/1/';
if (!is_dir($temp_dir)) {mkdir($temp_dir);
}if (in_array($ext, array('zip', 'jpg', 'gif', 'png'))) {if ($ext == 'zip') {// $zip = new ZipArchive;// if(!$zip->open($file['tmp_name'])) {// echo "fail";// return false;// }// if(!$zip->extractTo($temp_dir)) {// // check_dir($temp_dir);// exit('fail to zip');// }$archive = new PclZip($file['tmp_name']);if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {exit("解压失败");}check_dir($temp_dir);exit('上传成功!');} else {move_uploaded_file($file['tmp_name'], $temp_dir . '/' . $file['name']);check_dir($temp_dir);exit('上传成功!');}
} else {exit('仅允许上传zip、jpg、gif、png文件!');
}
第一次防御
访问前端页面发现我们是可以上传一个文件的,因此这样就可以创建一个phpinfo.php文件和一个1.jpg文件,然后放在php文件夹中,然后将该文件夹压缩上传:

然后尝试进行上传该压缩包:
上传完成后可以看到上传成功了

然后我们可以在那个对应的目录中进行查看上传后的文件内容:

可以看到上传后的文件只剩下了一个1.jpg文件,和它一起在压缩包中的phpinfo.php文件被删除了
第一次绕过
这里那就无法上传php文件了,那么我们就真的就没有办法了吗?大佬告诉了我们解决方案:
通过代码审计,可以看到,它删除的时候没有递归删除,也没有删除文件夹。
这样,只要我们的webshell放在压缩包的文件夹中,就可避免被删除了。
因此这样就可以创建一个phpinfo文件夹里面再放入一个phpinfo.php文件一个单独的1.jpg文件,然后放在php2文件夹中,然后将该文件夹压缩上传:

上传完成后可以再去uploads文件夹中查看就会发现已经成功的上传了php文件了

可以看到,现在就成功的上传了phpinfo文件并且里面的phpinfo.php文件保留了下来,并且1.jpg也上传了,这样就成功的绕过了限制
第二次防御
后面网页管理员对网页进行了一些安全加固,将后端的检查文件代码修改为下列的形式:
function check_dir($dir)
{$handle = opendir($dir);while (($f = readdir($handle)) !== false) {if (!in_array($f, array('.', '..'))) {if (is_dir($dir . $f)) {check_dir($dir . $f . '/');} else {$ext = strtolower(substr(strrchr($f, '.'), 1));if (!in_array($ext, array('jpg', 'gif', 'png'))) {unlink($dir . $f);}}}}
}
第一次绕过的方法的根本原因是因为没有考虑文件在文件夹中的情况,只删除了压缩包根目录下的非法文件,而没有删除其文件夹中的非法文件。
所以补丁就采用了递归删除的方式,将压缩包中所有非法文件删除。
但是采用了递归的方式就真的可以防御好了吗?并不是的
第二次绕过
因为通过分析代码后发现,删除的方式是先上传后删除,那么就可以尝试利用上传成功和删除的时间差来尝试访问该文件
因此这里使用Burpsuite来进行不断的上传,然后手动的访问一下上传后的文件看看会不会成功呢
首先使用Burpsuite对上传页面进行抓包,然后发送到intruder页面,添加payload:

然后设置发送1000个包,然后开始

下面就是尝试快速的不断的访问一下上传后的php文件:
可以看到通过上传后与删除的时间差是可以访问到php文件的,因此这种防御方法也是可以绕过的
第三次防御
上面的绕过方法出现后,后端人员也是快速的修改了,增加了一下代码:
$temp = FCPATH.'cache/attach/'.md5(uniqid().rand(0, 9999)).'/';
就是将压缩包放在一个随机命名的文件夹中再解压缩,这样你猜不到访问地址也就没法去暴力getshell了。
第三次绕过
通过对后端代码的审计后,发现当解压发生失败时,就退出解压缩过程。
这也是一个很平常的思路,失败了肯定要报错并退出,因为后面的代码没法运行了。
但是,程序员不会想到,有些压缩包能在解压到一半的时候出错。
什么意思,也就说我可以构造一个“出错”的压缩包,它可以解压出部分文件,但绝对会在解压未完成时出错。这是造成了一个状况:我上传的压缩包被解压了一半,webshell被解压出来了,但因为解压失败这里exit($this->pclzip->zip(true));退出了程序执行,后面一切的删除操作都没有了作用。
如何构造一个出错的压缩包
因为这里我们首先构造一个解压会出错的压缩包,这里龙哥给我们交了几种好用的方法:
我这里就以两个解压的程序作为例子:
-
Windows下的7zip
-
PHP自带的ZipArchive库
7zip的容忍度很低,只要压缩包中某一个文件的CRC校验码出错,就会报错退出。
如何修改压缩包里文件的CRC校验码呢?可以使用010editor。
我们先准备两个文件,一个PHP文件1.php,一个文本文件2.txt,其中1.php是webshell。
然后将这两个文件压缩成shell.zip。
然后我们用010editor打开shell.zip,可以看到右下角有这个文件的格式信息,它被分成5部分


我们打开第4部分,其中有个deCrc,我们随便把值改成其他的值,然后保存。

此时用7zip解压就会出错,解压出的1.php是完好的,2.txt是一个空文件。

我们再用PHP自带的ZipArchive库,测试这个zip,发现解压并没有出错,这也说明ZipArchive的容忍度比较高。
那么我们又如何让ZipArchive出错呢?最简单的方法,我们可以在文件名上下功夫。
比如,Windows下不允许文件名中包含冒号(:)
我们就可以在010editor中将2.txt的deFileName属性的值改成“2.tx:”。

此时解压就会出错,但1.php被保留了下来。
注:在Linux下也有类似的方法,我们可以将文件名改成5个斜杠(/)。
因此这里我们第三次绕过的思路有出来了,使用一个会报错的zip文件,上传后会将php文件解压问成功,进行报错了,因此php文件会被保留
第四次防御
这里的漏洞也是被后端人员发现后修复了,因此将代码修改为下面的形式:
if(!$zip->extractTo($temp_dir)) {check_dir($temp_dir);exit('fail to zip');}
可以看到,它会对解压失败的文件也进行一次检查,将里面非图片的文件删除
第四次绕过
但是这样真的就安全了吗?答案是不安全的
压缩包中通常是不含有诸如“../”、“..”这种文件名的,但通常不含有不代表不能含有。
如果把压缩包中某文件名改成../../../../../index.php,是不是就能直接把你首页变成我的webshell呀?
这就是因为抄袭者并没有真正领悟zip这个类的使用方法,导致了这个安全问题。
先把自己的shell改名字成aaaaaaaaaaaaaaaaaaaa.php
之所以起这个名字,就是预留一些空间,方便我之后将文件名改成../../../aaaaaaaaaaa.php而不用怕字符串长度不对。
把文件直接打包成zip,用010editor打开:
将画框的俩文件名的前9个字符改成../../../

然后再上传就可以成功上传了
总结一下:
1、没有对上传的文件进行递归删除,导致文件夹中的目录可以上传
2、先上传,后删除,可以利用时间竞争来访问上传后的文件
3、对上传后的文件进行一个重命名,随机名称,可以利用解压报错绕过
4、对解压后的文件进行检查,可以利用../../路径穿越进行绕过
到此这个黑客大佬与后端开发人员的对抗就结束了,但是还有很多web页面存储漏洞仍然存在着漏洞等着我们去发现
相关文章:
phpcms头像上传漏洞引发的故事
目录 关键代码 第一次防御 第一次绕过 第二次防御 第二次绕过 第三次防御 第三次绕过 如何构造一个出错的压缩包 第四次防御 第四次绕过 本篇文章是参考某位大佬与开发人员对于文件包含漏洞的较量记录下的故事,因为要学习文件包含漏洞,就将大佬…...
二叉树|二叉树理论基础、二叉树的递归遍历
代码随想录 (programmercarl.com) 树和二叉树 1.树的基本概念 1.1树的定义 1.2树的逻辑表示方法 1.3树的基本术语 1.4树的性质 1.5树的基本运算 1.6树的存储结构 2.二叉树的概念和性质 2.1二叉树的定义 2.2二叉树的性质 2.3二叉树与树、森林之间的转换 3.二叉树的…...
JavaScript 语法-对象
对象 JavaScript 中的对象是一组键值对的集合,其中每个键都是字符串,每个值可以是任意类型。 对象是由一些属性和方法组成的集合,属性可以用来存储数据,方法可以用来操作数据。 属性和方法使用“.”来访问 // 创建一个对象 let …...
代码随想录阅读笔记-哈希表【四数之和】
题目 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a b c d 的值与 target 相等?找出所有满足条件且不重复的四元组。 注意:答案中不可以包…...
JVM学习——双亲委派机制
简而言之就是为了防止与Java固有全类名重复,而导致系统崩坏所设立的机制。 当类加载器接收到加载类的任务时,首先会向上请求,一直请求到引导类加载器,如果引导类加载器无法加载,就会逐层返回让类加载器自己执行&#…...
【Paper Reading】6.RLHF-V 提出用RLHF的1.4k的数据微调显著降低MLLM的虚幻问题
分类 内容 论文题目 RLHF-V: Towards Trustworthy MLLMs via Behavior Alignment from Fine-grained Correctional Human Feedback 作者 作者团队:由来自清华大学和新加坡国立大学的研究者组成,包括Tianyu Yu, Yuan Yao, Haoye Zhang, Taiwen He, Y…...
Aloudata 倾力打造,《Data Fabric 白皮书 2.0》正式发布
数字经济时代,越来越多企业开始寻求全新的数据管理范式,以更有效地管理、利用不断增长的数据资产。在此背景下,Data Fabric 的概念应运而生,被视为面向未来的数据管理解决方案。 距离第一版白皮书问世已经过去一年多时间ÿ…...
docker内部无法使用ping等网络工具解决方案
通常docker内部没有网络,所以我们先离线安装需要的依赖包,然后再使用sh脚本容器内部访问宿主机同网络端其他服务器ip,实现监测远程ip telnet包依赖于netbase包,但是netbase包没有安装。你需要先安装netbase包,然后再尝试安装teln…...
后端工程师快速使用vue和Element
文章目录 Vue1 Vue概述2 快速入门3 Vue指令3.1 v-bind和v-model3.2 v-on3.3 v-if和v-show3.4 v-for3.5 案例 4 生命周期 Element快速使用1 Element介绍2 快速入门3 当前页面中嵌套另一个页面案例代码案例截图 Vue 1 Vue概述 通过我们学习的htmlcssjs已经能够开发美观的页面了…...
自学rabbitmq入门到精通
交换机的fault (发布与订阅模式) 因为消息是由生产者发送给excahnge,exchange发送给队列, 然后由队列发送给消费者的。 展示使用图形化界面使用fanout模式。 创建交换机 然后创建三个队列,绑定对应的交换机ÿ…...
由浅到深认识C语言(13):共用体
该文章Github地址:https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn…...
python爬虫(9)之requests模块
1、获取动态加载的数据 1、在开发者工具中查看动态数据 找到csdn的门户的开发者工具后到这一页面。 2、加载代码 import requests headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36…...
phpstudy自定义安装mysql8.3并启动
phpstudy自定义安装mysql8.3并启动 先去官网:https://dev.mysql.com/downloads/下载压缩包文件 然后按下面的图片一步一步操作 选择版本,选择第一个压缩包文件,下载 下载完成后,解压到phpstudy环境目录下,如下图 然后进入mysq…...
Netty 学习资料
Netty 学习资料 搜集了一下Java网络库Netty的学习资料,整理如下,有空花时间研究一下。 1、Netty学习手册 《尚硅谷 Netty 核心技术及源码剖析》课程学习手册 本课程不适合零基础的学员,需要掌握常用的设计模式和数据结构 掌握 Java 的面向对…...
【概率论中的两种重要公式:全概率和贝叶斯】
贝叶斯公式(Bayes’ Theorem)是概率论中的一条重要定理,用于计算条件概率。它描述了在已知某一事件发生的条件下,另一事件发生的概率。贝叶斯公式如下所示: P ( A ∣ B ) P ( B ∣ A ) ⋅ P ( A ) P ( B ) P(A|B) \…...
python中的闭包
一、闭包 1、作用域 在Python代码中,作用域分为两种情况:全局作用域 与 局部作用域 2、变量的作用域 在全局定义的变量 > 全局变量 在局部定义的变量 > 局部变量 3、全局变量与局部变量的访问范围 ① 在全局作用域中可以访问全局变量&#…...
成功解决RuntimeError: OpenSSL 3.0‘s legacy provider failed to load
报错 RuntimeError: OpenSSL 3.0s legacy provider failed to load. This is a fatal error by default, but cryptography supports running without legacy algorithms by setting the environment variable CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this er…...
【 React 】React 组件之间如何通信?
相关文章: React Context的使用方法 react Provider Consumer 使用方法 1. 是什么 我们将组件间通信可以拆分为两个词: 组件通信 组件是vue中最强大的功能之一,同样组件化是React的核心思想 相比vue,React的组件更加灵活和多样…...
汇总全网免费API,持续更新(新闻api、每日一言api、音乐。。。)
Public&FreeAPI 网址:apis.whyta.cn (推荐) UomgAPI 网址:https://api.uomg.com 教书先生 网址:https://api.oioweb.cn/ 山海API https://api.shserve.cn/ 云析API铺 https://api.a20safe.com/ 韩小韩…...
Android SystemServer进程解析
SystemServer进程在android系统中占了举足轻重的地位,系统的所有服务和SystemUI都是由它启动。 一、SystemServer进程主函数流程 1、主函数三部曲 //frameworks/base/services/java/com/android/server/SystemServer.java /** * The main entry point from zy…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
