https://www.freebuf.com/articles/web/360757.html
项目说明
https://gitee.com/mingSoft/MCMS
网上看了下这套代码的漏洞比较多,可以用来练练手
技术 | 名称 | 官网 |
---|---|---|
Spring Framework | 容器 | http://projects.spring.io/spring-framework |
Spring Boot | MVC框架 | https://spring.io/projects/spring-boot |
Apache Shiro | 安全框架 | http://shiro.apache.org |
Spring session | 分布式Session管理 | http://projects.spring.io/spring-session |
MyBatis | ORM框架 | http://www.mybatis.org |
Freemarker | 视图框架 | http://freemarker.foofun.cn |
PageHelper | MyBatis分页插件 | http://git.oschina.net/free/Mybatis_PageHelper |
Log4J | 日志组件 | http://logging.apache.org |
Maven | 项目构建 | http://maven.apache.org |
Elasticsearch | 分布式搜索引擎 | https://www.elastic.co |
Redis | 分布式缓存数据库 | https://redis.io |
hutool | 工具类 | http://hutool.mydoc.io |
技术 | 常见安全问题 | 防范措施 |
---|---|---|
Spring Framework | 配置漏洞(如未正确配置 CSRF、CORS),数据暴露风险 | 确保正确配置 CSRF 和 CORS,启用 Spring Security 进行鉴权,避免不必要的 Bean 暴露 |
Spring Boot | 默认配置可能暴露管理端点(如 /actuator ),可能引发信息泄露 |
在 application.properties 中禁用生产环境的管理端点,限制访问权限 |
Apache Shiro | 鉴权绕过(特别是路径拦截不当)、密码加密强度不足 | 确保路径拦截规则严格且测试充分,加密配置中使用高强度散列算法 |
Spring Session | 会话固定攻击(Session Fixation)、会话劫持 | 使用 https 保护传输,加密存储敏感会话信息,定期刷新会话 |
MyBatis | SQL 注入 | 使用 #{} 语法传递参数,避免直接拼接 SQL,定期检查 Mapper 文件 |
Freemarker | 模板注入(Template Injection) | 避免使用用户输入直接作为模板变量,开启输出转义 |
PageHelper | 分页参数未验证,可能导致注入 | 校验分页参数的合法性,设置最大分页限制 |
Log4J | 日志注入,JNDI 注入风险(Log4Shell) | 避免日志记录用户直接输入内容,升级到安全版本(Log4j2 最新版) |
Maven | 使用的依赖库可能包含已知漏洞 | 定期检查依赖库版本,使用 Maven Security Scanner 检测 |
Elasticsearch | 默认配置未认证,可能被未授权访问 | 设置访问控制策略,加密存储,禁用默认的 _cat 等敏感接口 |
Redis | 未授权访问,持久化数据泄露风险 | 禁用不必要的外部网络连接,配置密码和 IP 白名单 |
Hutool | 安全性依赖具体工具函数的实现 | 使用时需验证 Hutool 工具类的输入输出是否合法,避免直接处理用户输入 |
前台XSS
其实感觉也不算是漏洞,只是做给自己看的
主要原因是上面在报错返回时,将恶意代码也添加在了content当中一起返回
这里可以跟进分析下是怎么判断的:
1 | public String clean(String name, String content) { |
在上面的 Jsoup.clean 中就已经清除了,Jsoup.clean 是 Jsoup 库的一部分,Jsoup 是一个开源的 Java 库,专门用于解析、清理和操作 HTML。Jsoup 可以从 HTML 中移除不安全的内容,因此常用于防止 XSS 攻击。
使用Jsoup.clean消除不受信任的HTML (防止XSS攻击)
1 | public static String clean(String bodyHtml, String baseUri, Whitelist whitelist, Document.OutputSettings outputSettings) { |
bodyHtml 字符串解析为一个 Document 对象,称为 dirty(“未清理”文档)。
注意到前面的代码中还有对sql代码的过滤,跟进去看到了规则如下:
1 | private static final Pattern sqlPattern = Pattern.compile("(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|and|or|delete|insert|trancate|char|substr|ascii|declare|chr|mid|exec|count|master|into|drop|execute)\\b)", 2); |
SQL注入
前面已经知道了MCMS使用mybaits作为持久层框架,可以分析相应的映射文件,在其中查找使用$
拼接的参数。除此之外还有种漏洞思路,<include></include>
标签,会将一段复用的SQL代码拼接入当前语句中。
$ 查询分析
在IContentDao.xml
中找到了用到了,这个先暂时放着
<include></include>
分析
三个xml文件中都包含有下面的这个:
1 | <include refid="net.mingsoft.base.dao.IBaseDao.sqlWhere"></include> |
进入到这个类里面看看到底是什么
可以看到其中有大量的$,主要是用到了${item.field}
,分析得到这个是来自于 sqlWhereList ,其中的field变量是可能存在的注入点。
接下来看看这个是否可控,返回去查看方法调用的点,在ICategoryDao.xml,找select id=”query”对应的接口,没有找到,进入到其基类中查找,找到了
1 | public interface IBaseDao<E> extends BaseMapper<E> { |
进一步找query的实现类,有三个,但只有一个接受参数
1 | // net/mingsoft/base/biz/impl/BaseBizImpl.java |
接下来再找找看哪里用了
跟进net/mingsoft/cms/action/CategoryAction.java
1 |
|
存在外部可访问接口,@RequestMapping("/${ms.manager.path}/cms/category")
,${ms.manager.path}
在配置中为ms,找到具体的应用点,传入的参数是 CategoryEntity 类型的:
1 | /** |
跟进 CategoryEntity 分析其结构,进一步找 又跟进到BaseEntity找qlWhereList
和SQLwhere
,SQLwhere是json格式,分析可能存在注入点。
1 | categoryType=1&sqlWhere=%5B%7B%22action%22%3A%22and%22%2C%22field%22%3A%22content_title%22%2C%22el%22%3A%22eq%22%2C%22model%22%3A%22contentTitle%22%2C%22name%22%3A%22%E6%96%87%E7%AB%A0%E6%A0%87%E9%A2%98%22%2C%22type%22%3A%22input%22%2C%22value%22%3A%2212312313%22%7D%5D&pageNo=1&pageSize=10 |
接下来尝试使用报错语句查询:
1 | categoryType=1&sqlWhere=[{"action":"and","field":"updatexml(1,concat(0x7e,(select user()),0x7e),1)","el":"eq","model":"contentTitle","name":"文章标题","type":"input","value":"12312313"}]&pageNo=1&pageSize=10 |
文件上传
模板位置上传
/ms/file/uploadTemplate.do
SSTI:Freemarker模板注入
源码位置net\mingsoft\base\util\FtlUtil.java
FastJson <=1.2.80 反序列化
net/mingsoft/basic/action/web/EditorAction.javaMap<String, Object> map = (Map<String, Object>) JSONObject.parse(jsonConfig); //直接解析了jsonConfig
URL:@RequestMapping(“/static/plugins/ueditor/{version}/jsp”),需要version