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文件夹中,然后将该文件夹压缩上传:

d778b2561c36425da6dcd7fdddd9eae9.png

然后尝试进行上传该压缩包:

上传完成后可以看到上传成功了

b0182a870abe46ffb50f0c5342d26aa6.png

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

6e86e784bc294075bba4a32ce9ecc5bc.png

可以看到上传后的文件只剩下了一个1.jpg文件,和它一起在压缩包中的phpinfo.php文件被删除了

第一次绕过

这里那就无法上传php文件了,那么我们就真的就没有办法了吗?大佬告诉了我们解决方案:

通过代码审计,可以看到,它删除的时候没有递归删除也没有删除文件夹

这样,只要我们的webshell放在压缩包的文件夹中,就可避免被删除了。

因此这样就可以创建一个phpinfo文件夹里面再放入一个phpinfo.php文件一个单独的1.jpg文件,然后放在php2文件夹中,然后将该文件夹压缩上传:

8e38a5b9bcd3490c97e13dccd785633b.png

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

82b8291ca7764749b52a77b6345f9742.png

可以看到,现在就成功的上传了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:

07fe8d37aac241529b9541e37209a2bd.png

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

b6b098e4a9c841c9ab0210182659190d.png

下面就是尝试快速的不断的访问一下上传后的php文件:
d3f7e8fde29748fabcdb9cf7e8a4eccf.png

可以看到通过上传后与删除的时间差是可以访问到php文件的,因此这种防御方法也是可以绕过的

第三次防御

上面的绕过方法出现后,后端人员也是快速的修改了,增加了一下代码:

$temp = FCPATH.'cache/attach/'.md5(uniqid().rand(0, 9999)).'/';

就是将压缩包放在一个随机命名的文件夹中再解压缩,这样你猜不到访问地址也就没法去暴力getshell了。

第三次绕过

通过对后端代码的审计后,发现当解压发生失败时,就退出解压缩过程。

这也是一个很平常的思路,失败了肯定要报错并退出,因为后面的代码没法运行了。

但是,程序员不会想到,有些压缩包能在解压到一半的时候出错。

什么意思,也就说我可以构造一个“出错”的压缩包,它可以解压出部分文件,但绝对会在解压未完成时出错。这是造成了一个状况:我上传的压缩包被解压了一半,webshell被解压出来了,但因为解压失败这里exit($this->pclzip->zip(true));退出了程序执行,后面一切的删除操作都没有了作用。

如何构造一个出错的压缩包

因为这里我们首先构造一个解压会出错的压缩包,这里龙哥给我们交了几种好用的方法:

我这里就以两个解压的程序作为例子:

  1. Windows下的7zip

  2. PHP自带的ZipArchive库

7zip的容忍度很低,只要压缩包中某一个文件的CRC校验码出错,就会报错退出。

如何修改压缩包里文件的CRC校验码呢?可以使用010editor。

我们先准备两个文件,一个PHP文件1.php,一个文本文件2.txt,其中1.php是webshell。

然后将这两个文件压缩成shell.zip。

然后我们用010editor打开shell.zip,可以看到右下角有这个文件的格式信息,它被分成5部分

ba5bc0681f4d4bd19f637a428c89cdbe.png

c4d9256f7c224229ac5a3d45943bf6a1.png

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

cc6235d8fd7f43fbb19fa06254014e58.png

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

6ae51932c36848389f856d96d2bb8c07.png

我们再用PHP自带的ZipArchive库,测试这个zip,发现解压并没有出错,这也说明ZipArchive的容忍度比较高。

那么我们又如何让ZipArchive出错呢?最简单的方法,我们可以在文件名上下功夫。

比如,Windows下不允许文件名中包含冒号(:)

我们就可以在010editor中将2.txt的deFileName属性的值改成“2.tx:”。

1ac6ddd74ee24213a87bd1f50ef03461.png

此时解压就会出错,但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个字符改成../../../

a3eea48173024483b5f80bdf26f98df8.png

然后再上传就可以成功上传了

总结一下:

1、没有对上传的文件进行递归删除,导致文件夹中的目录可以上传

2、先上传,后删除,可以利用时间竞争来访问上传后的文件

3、对上传后的文件进行一个重命名,随机名称,可以利用解压报错绕过

4、对解压后的文件进行检查,可以利用../../路径穿越进行绕过

到此这个黑客大佬与后端开发人员的对抗就结束了,但是还有很多web页面存储漏洞仍然存在着漏洞等着我们去发现

 

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

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

相关文章

Dense Distinct Query for End-to-End Object Detection

摘要 对象检测中的一对一标签分配成功地消除了作为后处理的非极大值抑制&#xff08; NMS &#xff09;的需要&#xff0c;并使流水线端到端。然而&#xff0c;这引发了一个新的困境&#xff0c;因为广泛使用的稀疏查询无法保证高召回率&#xff0c;而密集查询不可避免地带来更…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:ListItemGroup)

该组件用来展示列表item分组&#xff0c;宽度默认充满List组件&#xff0c;必须配合List组件来使用。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。该组件的父组件只能是List。 使用说明 当List…

uni app 钓鱼小游戏

最近姑娘喜欢玩那个餐厅游戏里的钓鱼 &#xff0c;经常让看广告&#xff0c;然后就点点点... 自己写个吧。小鱼的图片自己搞。 有问题自己改&#xff0c;不要私信我 <template><view class"page_main"><view class"top_linear"><v…

1.2 课程架构介绍:STM32H5 芯片生命周期管理与安全调试

1.2 课程架构介绍&#xff1a;STM32H5 芯片生命周期管理与安全调试 下面开始学习课程的第二节&#xff0c;简单介绍下STM32H5芯片的生命周期和安全调试&#xff0c;具体课程大家可以观看STM32官方录制的课程&#xff0c;链接&#xff1a;1.2. 课程架构介绍&#xff1a;STM32H5…

使用IDEA2023创建传统的JavaWeb项目并运行与调试

日期:2024-0312 作者:dusuanyun 文档环境说明: OS:Deepin 20.9(Linux) JDK: OpenJDK21 Tomcat:10.1.19 IDEA: 2023.3.4 (Ultimate Edition) 本文档默认已经安装JDK及环境变量的配置。 关键词…

PytorchAPI的使用及在GPU的使用和优化

API 调用API&#xff1a;和手动实现的思路是一样的。#1&#xff0c;#2这两个步骤是通用的步骤&#xff0c;相当于建立一个模型&#xff0c;之后你具体的数据直接丢进去就行了。只需要按着这样的样式打代码就行&#xff0c;死的东西&#xff0c;不需要你自己创造。 import torc…

一款Jenkins的综合漏洞利用工具-JenkinsExploit-GUI

一、使用 jdk版本 在windows或linux使用jdk8的哪一个版本应该都可以,在macOS里需要jdk8u较高的版本,比如jdk8u321 二、外置payload 从release下载windows_tools,linux_tools或macOS_tools并放在与JenkinsExploit-GUI-*-SNAPSHOT.jar相同的目录,或者可以自行打包tools_source…

fs模块 之 文件读取

fs 文件读取&#xff1a; 利用文件读取而不是直接打开文本查看的目的是为了实现自动化 读取文件的应用场景:电脑开机/程序运行/播放视频音乐/上传文件... 一、异步读取 &#xff08;1&#xff09;语法&#xff1a;fs.readFile(path,[options],callback); 以之前写的文件写…

idea maven 项目融合

背景 &#xff1a;项目A 和项目B 是两个独立的多模块项目&#xff0c;项目A 和项目B &#xff0c;均为独立的数据源 。其中项目B 有两个数据原。 需要将项目B 以多模块的方式融合进项目A。 解决版本。建立项目C&#xff0c;只含有pom的&#xff0c;空项目&#xff0c;项目A和项…

C++_学习String

1.标准库中的string类 1. 字符串是表示字符序列的类 2. 标准的字符串类提供了对此类对象的支持&#xff0c;其接口类似于标准字符容器的接口&#xff0c;但添加了专门用于操作单字节字符字符串的设计特性 3. string 类是使用 char( 即作为它的字符类型&#xff0c;使用它的默…

MySQL—redo log、undo log以及MVCC

MySQL—redo log、undo log以及MVCC 首先回忆一下MySQL事务的四大特性&#xff1a;ACID&#xff0c;即原子性、一致性、隔离性和持久性。其中原子性、一致性、持久性实际上是由InnoDB中的两份日志保证的&#xff0c;一份是redo log日志&#xff0c;一份是undo log日志&#xff…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:List)

列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据&#xff0c;例如图片和文本。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。该组件内容区小于一屏时&#xff0c;默认没有回弹效果。…