21

Java代码审计-MCMS

 2 years ago
source link: https://timeshu.github.io/2022/01/15/Java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1-MCMS/#%E6%BC%8F%E6%B4%9E%E9%AA%8C%E8%AF%81-5
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Time'Blog

Java代码审计-MCMS

发表于2022-01-15|更新于2022-02-09|代码审计
阅读量:44|评论数:

0X01 环境搭建

项目地址下载:https://gitee.com/mingSoft/MCMS

当前版本:5.2.5 也可下载的releases版本 5.2.4

PS:注意Mysql版本需大于5.6以上

创建一个mcms数据库,并且导入doc/数据库文件

application-dev中修改数据库账户密码

运行MSApplication.java main方法,如下图,环境无问题

管理员:msopen/密码:msopen

外置环境配置

搭建Tomcat环境

注意:环境最好使用1.8版本,作者使用15版本,打包war时一直报错,版本不对,最后将1.8设置默认版本后才成功。

编辑 pox.xml 修改打包方式为 war 包

plaintext
<!-- 打包成war包 -->
<packaging>war</packaging>
plaintext
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

修改启动类 src\main\java\net\mingsoft\MSApplication.java

plaintext
@SpringBootApplication(scanBasePackages = {"net.mingsoft"})
@MapperScan(basePackages={"**.dao","com.baomidou.**.mapper"})
@ServletComponentScan(basePackages = {"net.mingsoft"})
public class MSApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(MSApplication.class);
}

public static void main(String[] args) {
SpringApplication.run(MSApplication.class, args);
}
}

启动类爆红,导入包路径即可。

使用maven打包,点击如下图标,设置

新建 tomcat server ,导入即可

搭建成功,如果登录后提示分页插件出错

原因:参考其他大佬的

MSServletInitializer.java 文件从项目中删除即可,因为该类也继承了SpringBootServletInitializer类,所以导致PageHelper插件被配置了两次

参考链接:https://www.zhihu.com/question/330677156

其中我们主要关注红框的三个目录

  • Action 控制器层
  • biz 业务逻辑层
  • dao 数据库交互层

并且在cms中并未发现全局过滤文件。

作者后端技术框架

0X02 SQL注入漏洞

MyBatis SQL 注入前置知识

根据作者发布的配置文档可知, 后端使用的是 ORM框架 MyBatis

MyBatis 的 SQL 语句可以使用注解方法写在类方法上,也可以使用 xml 的方式,而使用的最多的方式就是将语句写入 xml 文件中。

编写 xml 文件时,MyBatis 支持两种参数符号

  • $ – 拼接 SQL
    • # – 使用预编译

当语句使用 $ 拼接时,则会产生 SQL 注入漏洞。

参考链接:https://www.freebuf.com/vuls/240578.html

我们关注 dao 目录,可以发现作者使用的是 xml 文件方式写入的

右键点击 Find in Path 选中 File mask 在 dao 目录下搜索 xml 文件

$ 搜索,发现有两条 select 语句均使用了 $ 拼接参数 categoryId,跟进

漏洞点:src/main/java/net/mingsoft/cms/dao/IContentDao.xml

可以发现 这条 select 语句是属于 select 标签 id 是 query,说明是 query 方法调用

IContentDao.xml 对应的映射接口类是 net.mingsoft.cms.dao.c,此文件中并未找到 query 方法,此时我们继续跟进到父类 IBaseDao(net.mingsoft.base.dao.IBaseDao)

在父类 IBaseDao 中找到 query 方法,IContentDao 接口类 继承父类 IBaseDao,所以可调用 query 方法

此时,我们需要去寻找 query 方法的对应的实现类。

IContentDao 对应的业务接口是 net.mingsoft.cms.biz.IContentBiz,而实现类是net.mingsoft.cms.biz.impl.ContentBizImpl,同理,跟进 ContentBizImpl 的 父类 BaseBizImpl(net.mingsoft.base.biz.impl.BaseBizImpl)发现父类中实现了 query 方法,调用了 dao 层的 query 方法

现在我们只需要跟进控制器层代码,寻找 categoryId 可控点,即可完成整个调用链。

对应的控制器文件 src/main/java/net/mingsoft/cms/action/ContentAction.java 104行处

@ApiImplicitParam 注解中定义了 categoryId 参数对应的是所属栏目,使用的方法是 query

而 127行 对应的调用处是 list 并且使用 post 方法获取到上述所有需要查询的参数并放到 content 中,通过 query 方法去查询对应的数据

此时我们可以去登录,验证漏洞是否存在

功能大全->文章管理 抓包

在 pageSize 后面添加 categoryId 参数

plaintext
Payload: categoryId=1' and updatexml(1,concat(0x7e,databases(),0x7e),1) and '1

成功,同时可以使用 Mysql 数据库监控程序,查看和数据库交互的语句

注入的语句

plaintext
select count(0) from ( select ct.* from ( select ct.*,cc.category_path from cms_content ct join cms_category cc on ct.category_id=cc.id WHERE ct.del=0 and (ct.category_id='1'' and updatexml(1,concat(0x7e,user(),0x7e),1) and ''1' or ct.category_id in (select id FROM cms_category where find_in_set('1' and updatexml(1,concat(0x7e,user(),0x7e),1) and '1',CATEGORY_PARENT_IDS)>0)) )ct ORDER BY ct.content_datetime desc,content_sort desc ) tmp_count

抓包时,还发现了华点。。

plaintext
rememberMe=rWugSNNLZQzRFHaq7ak+mgedIxoeZBy4qAquhNineUSo8u1NL/L4YCkX4vhDD9i1d/Hm2oBNc4ou74W/ALQNI5GYQH/tGQcYkffbwtjd4VZuoXD4D73yWZ3IGNIbVxXLJgk5WCc0VkOIizpA529fHxCurk4RLpC5K6EeX+J/TK8uGYnNtZyDz50BnbtF0UgntjTpRx++tnbB1XEpiUm4T/+AR1jH3U3RI/BCRXpAwg08lsFEBTYloTj+CqAHKMFCXOBIAdS4F/2pnHJfba7KU2JKNap0xu8maiRCs3+qYPncV3dpwzA8KyVOvnUIaNxOBSMEclpiQi1ykpwd32e4eqcC4Zey9lTJIp+znimCIszR5Qrn3SGewegH7BOrzdSkyHpDJxPWwejq9UYJ6ZkthidmrM8YVRHD8+kJGpkt/po42qP4JmGW6JP4Wt4StgsJZEO+bS/HjFwOpbDkJ3nnqZGaZzoAUmI+TaF8yPE9fmHNg01HtbiJsR8Ml6YcDXJdTOZ0xzPaGnUanggXwlL2x3DEndd0DKHfMHe8NNEe0KTMPoI+/ScWkF+Ogjomuo2mRqVMVWdYMsimMB73MFfW+9U/ugVVREqzSuH7Ym1KdwvtsCrQBMjLBz7P6d10Uvi2zL8g86u8wKhKoBg5gu8jmO8tQJkdb53VMpYNpyc8SnujThz/CQgyRjPRJ6v9lINR7rRQ0SjTU2wHIJfToaIOerDgxj2wTcw2tcLJKj8fj0DamOAdXrNhayx1xHYS16bU9PO3TteshfPCPOBrC31SKKY1RxTMBcMFrDTApI0n9eSOhDttMHp879iibCXXgH17TfrXIsymd+5iSCpkKJCruhwZJyi8TtvShgotzE0OumKObevO2p1/D2lWX1yuZ2zL2wSMtKReGo5g8ONab5bOQsp+B++LjFhLUsBLqWiBT1L8wNwJl5yTy1jgdpC2tmkz0judbdp/h9E6J9pDEhUsUllYeVyzadnCYugRDMrNbcDFusdUKOUZrz8yBLTuHcPopP1hmDJnotSnvKuAdg36mUzuipolOMGHz49OkAzQE9y8aV1S33hBMs8dCF+1bL+VZYKlpPriP5LWrEiKzf3v/L9sojsDrLzbhZjbBaZ2zkUdh9O/dyWyw4hBSNVUYmO3pjTjIWBbhiBFKjc12S6jcTP/QPkY1i9deoMhMhHuP0gYlNiL4YLpsnXnAwaElaTutHWPbQcHQhXQounbYJRIVGiXCj3aLNQ4wgOlZdLMAvcAoyRljrIrjQJcfInuQNCKMYf5d9ZbtCfB3NJyZ3H3ff56pS+ipZfJ6RMIijqMFHs448CGn0lqJjpFD/bH+CTQIEvwF7tHJw==

网站还使用 shiro 框架,后续可以跟踪一下此漏洞。

0X03 shiro反序列化

shiro配置文件:

plaintext
repository/net/mingsoft/ms-basic/2.1.10/ms-basic2.1.10.jar!/net/mingsoft/config/ShiroConfig.class

mcms作者将核心一些配置文件封装成 ms-basic2.1.10.jar

打个断点到 ShiroConfig 的 rememberMeManager

可以看见获取到默认 key 值 4AvVhmFLUs0KTA3Kprsdag==

这里获取的 MCMS-master/src/main/resources/application.yml 配置文件中的值

之前我们跟过 shiro 反序列化漏洞,知道触发点在

org/apache/shiro/shiro-all/1.8.0/shiro-all-1.8.0.jar!/org/apache/shiro/mgt/AbstractRememberMeManager.class

跟进 getRemeberedPrincipals , this.getCookie().readValue 获取cookie值

再对比 cookie 值是否为 deleteME ,不匹配,走到 decoded = Base64.decode(base64) 解密 base64

返回一串 AES 加密的 bytes 值,走完后,会跳回到 getRemeberedPrincipals 执行下一个方法

convertBytesToPrincipals 这个方法是解密并进行反序列化

跟进 decrypt , getCipherService AES加密类,说明当前使用的加密是 AES/GCM/NoPadding 分组加密不填充模式

cipherService.decrypt(encrypted, this.getDecryptionCipherKey()) 解密,getDecryptionCipherKey 获取密钥,密钥是在配置文件中获取的

通过 setCipherKey 设置密钥,rememberMeManager 返回的是 CookieRememberMeManager 对象,而 CookieRememberMeManager 继承 AbstractRememberMeManager

所以 AbstractRememberMeManager 构造方法接收到了密钥 4AvVhmFLUs0KTA3Kprsdag==

解密后,返回一串 序列化值

调用 deserialize 反序列化

反序列化出来的内容,就是我们当前用户的信息。

打个 payload 看看反序列的内容是不是命令执行。

payload 成功反序列化出来

0X04 文件上传漏洞

文件上传接口

repository/net/mingsoft/ms-basic/2.1.10/ms-basic-2.1.10.jar!/net/mingsoft/basic/action/ManageFileAction.class

当我们上传文件时,upload 获取上传的文件信息

this.upload 处理上传操作,跟进

MCMS-master/src/main/resources/application.yml 配置文件内容

uploadFileDenied 获取配置文件的中后缀名赋给 errType 是黑名单 ,而这里只获取了 .exe.jsp , 继续跟代码,查看是否有做二次验证。

后续并没有进行二次验证,在 40 行截取上传文件后缀名,在 59 行,System.currentTimeMillis() 生成一段14位的随机数和后缀名拼接组成新的文件名 ,并在 66 行循环对比后缀名是否和黑名单中相匹配。

后缀名不在黑名单后,就会执行保存操作,这段验证操作比较简单,主要是对比黑名单,而作者的黑名单后缀名过滤不够完整,用 jspx 即可绕过。

栏目管理 -> 上传缩略图

文件管理 -> 上传缩略图

系统设置 -> 网站LOGO

均调用 upload 代码,只是上传目录不同。

上传 jspx 文件,跟踪调用链

可以看见 jspx 成功上传

0X05 ZIP自解压(上传webshell)

ZIP文件上传点

net/mingsoft/ms-basic/2.1.10/ms-basic-2.1.10.jar!/net/mingsoft/basic/action/ManageFileAction.class

整个ZIP文件上传流程和前面分析的流程一致。

repository/net/mingsoft/ms-basic/2.1.10/ms-basic-2.1.10.jar!/net/mingsoft/basic/action/TemplateAction.class

上传一个zip,然后抓包,上传成功后,会返回一个zip包上传路径

随即会自动调用 unzip 解压文件,fileUrl 是我们上次的zip文件地址

断点打在 unzip ,也没什么复杂的处理,得到文件路径,判断路径中是否有 ../..\\ zip文件,再根据路径获取 zip 文件。

unzip 解压 , 跟进,可以发现是遍历 zip 文件中的所有文件

返回解压后的所有文件,del 判断是否解压,解压完成后,删除压缩包文件。

中间也没有做任何的文件过滤,判断啥的,后缀名也是使用的黑名单,使用burp可以修改后缀名上传webshell。

生成一个哥斯拉 webshell , 将webshell放到 zip 压缩包中

上传压缩包

http://localhost:8081/ms_mcms_war/template/1//default/2.jsp

哥斯拉连接

绕过后缀名

0X06 模板注入

该CMS使用的模版引擎是freemarker,该模版引擎是存在模版注入的

登录管理后台,在后台模板管理界面,是可以修改模板文件内容的

编辑模块调用的是

/net/mingsoft/ms-basic/2.1.10/ms-basic-2.1.10.jar!/net/mingsoft/basic/action/TemplateAction.class writeFileContent

可以看见这段代码中也没有对内容进行过滤,只是获取了内容,名字,然后将编辑后的内容和原内容对比,然后修改成功。

MCMS-master/src/main/java/net/mingsoft/cms/action/GeneraterAction.java

跟进 generate 方法

rendering 解析模板文件

正常解析模板文件,当注入恶意代码时,漏洞被成功触发。

修改模板文件

plaintext
payload:  
<#assign ex="freemarker.template.utility.Execute"?new()>
${ ex("wget http://localhost:8084") }

保存,点击内容管理 -> 静态化

模板选择对应修改的文件,生成主页

触发成功。

OXO7 任意文件删除

net/mingsoft/ms-basic/2.1.10/ms-basic-2.1.10.jar!/net/mingsoft/basic/action/TemplateAction.class

代码无任何过滤,获取要删除的文件名,deleteDirectory 执行删除

修改为 ../1 , 成功删除


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK