写点什么

【审计思路】如何快速定位 SQLMS 注入漏洞?

  • 2022-12-18
    湖南
  • 本文字数:3337 字

    阅读完需:约 11 分钟

0x00 前言

MCMS 是政府、教育等其他行业常用的 CMS,应用广泛,但是底层的代码中仍然遗留不少的问题。这篇文章主要针对 SQL 注入进行审计并探讨如何快速定位 SQL 注入漏洞,以及其他工具的应用。


MCMS,是完整开源的 Java CMS!基于 SpringBoot 2 架构,前端基于 vue、element ui。每两个月收集 issues 问题并更新版本,为开发者提供上百套免费模板,同时提供适用的插件(文章、商城、微信、论坛、会员、评论、支付、积分、工作流、任务调度等...),一套简单好用的开源系统、一整套优质的开源生态内容体系。铭飞的使命就是降低开发成本提高开发效率,提供全方位的企业级开发解决方案。

0x01 审计环境

Mingsoft MCMS v5.2.8Mysql 8.0.29Openjdk 19.0.1
复制代码

0x02 审计思路

现代做代码审计的工具市面上已经有很多了,在拿到源码的时候,第一时间当然是先使用工具进行扫描,节省人工时间。尽管有 fortify、奇安信代码卫士这些工具在,但避免不一些纰漏,仍然需要人工经验的判断。

利用自动化代码审计工具

这里我们使用 fortify 工具对源码进行扫描,记录了我遇到的两个问题。该 fortify 工具为收费工具,本文不提供破解版的下载方式。


【一一帮助安全学习,所有资源获取处一一】

①网络安全学习路线

②20 份渗透测试电子书

③安全攻防 357 页笔记

④50 份安全攻防面试指南

⑤安全红队渗透工具包

⑥网络安全必备书籍

⑦100 个漏洞实战案例

⑧安全大厂内部视频资源

⑨历年 CTF 夺旗赛题解析

1.反编译 jar 包

使用 fortify 导入 MCMS 源码进行代码审计,但效果往往不如意。因为这一套源码使用 Maven 作为项目管理工具软件,其中包括依赖管理,MCMS 项目依赖的 jar 包都是远程拉取的。其中 net.mingsoft.ms-base、ms-basic、ms-mdiy 为底层逻辑代码。拉取的时候是以 jar 包的形式存在的,而自动化工具不会对 jar 包进行扫描。



我们可以将 jar 包重命名为 zip,然后解压就能获得 class 文件。但 fortify 同样不会扫描 class 文件,我们需要进一步反编译。这里我们可以使用 jadx 进行反编译。



我们可以直接打开 jar 文件,通过快捷键 Control+S 将反编译后的资源进行保存。



导出之后就是 java 文件,是可以被扫描的文件类型。


2.不扫描 JS 文件

在扫描代码的实践中,我遇到 JS 文件数量过多情况,导致整体的扫描进度大幅度拉长,这不是我想要的。找到 fortify/Core/config 目录下的 fortify-sca.properties



其中 com.fortify.sca.DefaultFileTypes 一项规定了被扫描文件的类型。我们把其中的 ,js删掉就可以了。


人工审计 SQL 注入思路

造成 SQL 注入一般需要满足以下两个条件:(1)输入参数内容用户可控。(2)直接或间接拼入 SQL 语句执行。且在执行 SQL 语句时有不同的方式:(1)直接使用 JDBC 的类方法。针对这种执行 SQL 语句的方式,我们可以全局搜索 SELECT、DELETE、UPDATE 等 SQL 关键词或者搜索 Statement、PreparedStatement 方法名称来定位执行语句的地方。(2)使用 MyBatis 持久化层作 SQL 语句执行代理。MyBatis 持久化层中一般使用 #{} 在底层实现上使用 “?”作为占位符,是预编译的机制。在实践过程中,类似order by等不能使用单引号的地方都不可以使用预编译,转而使用 ${}直接拼接到 SQL 语句中。一般这种情况需要手动增加内容的严格过滤步骤。所以尽管预编译很强大但也有用不上的地方,而这些地方就是我们的突破口。

0x03 审计过程

由上面的描述可以知道使用 ${}的地方往往可能存在 SQL 注入风险,所以我们审计过程中可以直接全局搜索${}

1. 底层映射存在注入漏洞引发多个前台注入

原因

在 SQL 持久化层 IBaseDao.xml 文件中可以看到绑定 id 为 sqlWhere 的 Sql 映射里使用了 ${} 导致存在 SQL 注入的风险。


第一处 GET 类型

IDictDao.xml 中引入 IBaseDao.xml 映射语句。



IDictBiz 这个业务层是继承了 IBaseBiz 从而有 query 确定返回类型为 DictEntity。



在控制层 web/DictAction.class 中可以看到这里请求数据包的数据变成了实体,然后直接传入 dictBiz.query 中。



我们请求这个接口时,所有传入的参数与值会别当作 DictEntity,所以这里直接传 sqlWhere 即可。



sqlWhere的值为 [{"action":"","field":"extractvalue(0x7e,concat(0x7e,(database())))","el":"eq","model":"contentTitle","name":"文章标题","type":"input","value":"a"}]
复制代码

第二处 GET 类型

IDictDao.xml 中引入 IBaseDao.xml 映射语句。id 为 queryExcludeApp



在控制层 web/DictAction.class 中可以看到这里请求数据包的数据变成了实体,然后直接传入 dictBiz.queryExcludeApp中。



同样的这里所有传入的参数与值会别当作 DictEntity,存在同样的问题。


第三处 POST 类型

ICategoryDao.xml 中引入 IBaseDao.xml 映射语句。



在控制层 web/CategoryAction.java 中可以看到这里请求数据包的数据变成了实体,然后直接传入categoryBiz.query 中。



这里的实体类型有了变化,但不妨碍我们传入 sqlWhere导致漏洞的执行。


第四处 POST 类型

IContentDao.xml 中引入 IBaseDao.xml 映射语句。



在控制层 web/ContentAction.java 中可以看到这里请求数据包的数据变成了实体,然后直接传入contentBiz.query 中。



只要引入之后,如果没有过滤都是存在漏洞的。


2. 后台自定义模型任意 SQL 语句执行

在持久化层 IBaseDao.xml 中存在一处绑定了 id 为 excuteSql 的 SQL 操作语句。该地方直接执行了传入 SQL 语句。



持久化层代理 IBaseDao.class 写好了对应 IBaseDao.xml 的接口



IModelDao.class 继承了 IBaseDao 确定了类型为 ModelEntity




业务层 IModelBiz.class 定义了一些接口



业务实现层 ModelBizImpl.class 实现了 IModelBiz.class 接口,通过阅读代码,可以发现实际上在 importModel 函数里面使用了 IModelDao.class 中的 excuteSql 方法。



在控制层 ModelAction.class 中 importJson 函数里调用了 ModelBizImpl.class 的 importModel 函数。



该漏洞产生位置存在后台自定义模型的导入功能处,要使用该功能需要到 https://code.mingsoft.net/ 生成代码。



新建业务表单 ——> 拖动表单组件 ——> 填写字段名和默认值 ——> 生成代码



可以看到生成的自定义模型代码,我们复制出来将 sql 字段的 value 改成我们自定义的即可。



任意都行没有过滤和限制,语句的行是通过 split(';')来分割的。



这个其实是 MCMS 的核心业务,无法避免的使用,所以只要使用 MCMS 拥有自定义模型的导入功能的权限就可以利用 SQL 注入获取数据或者系统权限。

3.校验参数接口前台 SQL 注入

因为使用了 mybatis 框架这里就全局搜使用 $ 进行拼接的,发现在/net/mingsoft/ms-base/2.1.13/ms-base-2.1.13.jar!/net/mingsoft/base/dao/IBaseDao.xml



进一步跟进 queryBySQL



查看对应接口中的实现方法



然后在/net/mingsoft/base/biz/impl/BaseBizImpl.java这里进行了重写 queryBySQL,然后调用getDao().queryBySQL



然后发现在/net/mingsoft/basic/action/BaseAction.class#validated 验证的时候进行调用



继续跟,这时候只要找到前端路由中能调用 validated 就可以了,然后发现在/net/mingsoft/ms-mdiy/2.1.13.1/ms-mdiy-2.1.13.1-sources.jar!/net/mingsoft/mdiy/action/PageAction.java#verify调用了 validated 方法



寻找路由,通过分析我们这个是个 GetMapping 然后参数 fieldName、fieldValue、id、idName 随便构造一下,最开始我们看到的 key 对应的就是前端传进来的 fieldName



http://127.0.0.1:8008/ms/mdiy/page/verify.do?fieldName=1;select/**/if(substring((select/**/database()),1,4)='mcms',sleep(5),1)/**/and/**/1&fieldValue=b&id=c&idName=1fieldName`是传入了 `${key}直接拼接到SQL语句导致SQL注入。
复制代码


0x04 总结

代码审计论证了预编译不是万能的,否则不会出现这么多的 SQL 注入漏洞。在不能使用预编译处理参数值,只能通过拼接进行操作的地方,除了手工写过匹配危险字符滤函数之外还有什么方法吗?我们还可以严格要求传入的参数类型,例如数字的地方将用户输入的内容进行强制转化成 int 不行就报错处理,这种称之为表单过滤层。如果我们的代码体积庞大无法花费大量人力去排查漏洞存在,可以购买安全公司的代码审计服务和 WAF 防火墙产品。

0x05 参考

*   [https://gitee.com/mingSoft/MCMS/issues/I5OWGU](https://gitee.com/mingSoft/MCMS/issues/I5OWGU)*   [https://gitee.com/mingSoft/MCMS/issues/I5X1U2](https://gitee.com/mingSoft/MCMS/issues/I5X1U2)
复制代码


用户头像

我是一名网络安全渗透师 2021-06-18 加入

关注我,后续将会带来更多精选作品,需要资料+wx:mengmengji08

评论

发布
暂无评论
【审计思路】如何快速定位SQLMS注入漏洞?_网络安全_网络安全学海_InfoQ写作社区