jspxcms代码审计

Jspxcms 是灵活的、易扩展的开源网站内容管理系统,具有可独立管理的站群、 自定义模型、自定义工作流、控制浏览权限、支持全文检索、多种内容形式、支持 文库功能、支持手机站、支持微信群发、可查询字段、文章多栏目、文章多属性、 内容采集、附件管理、全站静态化等功能特点,是在 gitee 开源平台获得推荐标志的 优秀 Java 项目。

Jspxcms 的前端技术主要运用了 HTML 5、CSS、JavaScript、jQuery、jQuery Validate (验证框架)、jQuery UI、AdminLTE、Bootstrap(响应式 CSS 框架)、UEditor(Web 编辑器)、Editor.md(Markdown 编辑器)、SWFUpload(上传组件)、My97 DatePicker (日期控件)、zTree(树控件)等,后端技术主要运用了 Spring Boot、Spring、Spring MVC、JPA(Java 持久层 API)、Hibernate(JPA 实现)、Spring-Data-JPA、QueryDSL、Shiro(安全框架)、Ehcache(缓存框架)、Lucene(全文检索引擎)、IKAnalyzer(中 文分词组件)、Quartz(定时任务组件)、Tomcat JDBC(连接池)、Logback(日志组 件)、JCaptcha(验证码组件)、JSP、JSTL(JSP 标准标签库)、FreeMarker(模板引擎)、Maven 等。

环境搭建

Jspxcms v9.0.0

MySQL 5.5.53

jspxcms源码包

image-20240108182626167

在主目录中,src 目录为存放源码的目录,database 为存储 SQL 文件目录

创建名为 jspxcms_test 的数据库,并导入SQL 文件

create database jspxcms_test;
use jspxcms_test;
source mysql.sql;

image-20240108183219269

接着打开 IDEA,选择 Open or Import,导入 Jspxcms 项目

image-20240108183449142

再打开/src/main/resources/application.propertis 文件,修改 url、username、password 的值,其余保持默认即可

image-20240108183550512

配置文件修改好后,继续修改 pom.xml 文件,将部分中间件版本修改成我们本机环境所安装的版本。

如我这里的 MySQL 版本是 5.5.53,但是在maven仓库中没有5.5.53版本的依赖,报错:

Could not find artifact mysql:mysql-connector-java:pom:5.5.53 in central

不过我们可以选择与5.5.53相兼容的版本

image-20240109111913927

因此将 pom.xml 文件中 的 MySQL 版本修改成 5.1.x 即可:

image-20240109111947078

修改好后保存文件,点击重新加载maven

image-20240108184358807

完成之后,在 Environment 选项中选择相应的 JDK 版

image-20240108191431272

运行项目

image-20240108191551757

访问http://127.0.0.1:8080/ ,即可看到该项目的主界面

image-20240109111631864

访问 http://localhost:8080/cmscp/index.do,即可看到该项目管理界面的主界面

image-20240123145528587

输入用户名为 admin,密码为空,单击登录按钮即可访问后台主界面

image-20240123145611776

至此,Jspxcms 项目安装完成。

目录结构

Jspxcms 的目录结构分为 3 个主文件夹,分别为 java、resource 和 webapp。java 文件夹中主要存放 Java 源码,resource 文件夹主要存放配置文件,webapp 文件主要存放 JSP 文件以及静态资源文件。

Java文件夹:

  • com.jspxcms.common:主要存放公用组件代码

  • com.jspxcms.core:主要存放站点功能的核心模块代码

resources文件夹:

  • conf:主要存放各种类型的配置文件

  • application.properties:Spring Boot 的配置文件

webapp 文件夹:

  • jsp:主要存放单独的 JSP 页面文件

  • static:主要存放静态资源文件

  • template:主要存放前台 FreeMarker 的模板文件

  • uploads:主要存放上传的文件

  • views:主要存放后台的 JSP 页面

  • crossdomain.xml:跨域策略的配置文件

看完目录结构,可以浏览一下网站的功能点,前台、后台能交互的地方都挨个点点看看

image-20240123161939050

image-20240123161858783

可以在功能列表中寻找可能出现的漏洞点,如 XSS 漏洞,那么可能出现该漏洞点的功能一般是文章发表功能、评论功能、友情链接申请功能、名称修改功能、个性签名修改功能等。如果找到功能点对应的逻辑代码,那么我们审计起来的时候就能事半功倍。

第三方组件漏洞审计

对于早期的 Java Web 项目,如果使用了其他官方或组织提供的 Jar 包,那么我们需要手动将对应的 Jar 包复制到对应的 lib 目录并配置对应信息。如果一个项目使用了大量的中间件,则会增加维护成本,但是也利于其他用户部署该项目。Apache 为了解决这个问题编写了 Maven,它是一款基于 Java 平台,可用于项目构建、依赖管理和项目信息管理的工具,使用该功能能够大大减少维护成本,并且 Maven 规范了团队以相同的方式进行项目管理,无形中提升了团队的工作效率。

Maven 的核心文件是 pom.xml,该文件主要用于管理源代码、配置文件、开发者的信息和角色、问题追踪、组织信息、项目授权、项目的 url、项目的依赖关系等。

因此对于审计者来说,在审计第三方组件的漏洞时,首先需要翻阅 pom.xml 文 件,该文件中记录着这个项目使用的第三方组件及其版本号。

Jspxcms 使用的第三方组件及其版本号如下:

commons-lang3 3.4
commons-net 3.4
commons-io 2.4
ehcache-core 2.6.11
shiro 1.3.2
lucene 3.6.2
htmlparser 2.1
quartz 2.2.2
poi 3.13
ant 1.9.6
prettytime 4.0.1.Final
owasp-java-html-sanitizer 20160924.1
UserAgentUtils 1.20
weixin4j-mp 1.7.4
imgscalr 4.2
jcaptcha 2.0.0
jodconverter-core 1.0.5
jacob 1.14.3
im4java 1.4.0
aliyun-sdk-mns 1.1.8
IKAnalyzer 2012_u6
qq-connect-Sdk4J 2.0.0
weibo4j-oauth2 beta3.1.1
mysql-connector-java 5.1.49
jsp-api 2.2.1
powermock 1.6.6
freemarker 2.3.25
... ...

更多可以看:

image-20240124164831357

我们可以对所使用的 Jspxcms 的第三方组件的版本进行版本比对,以判断该版本是否受到已知漏洞的影响

image-20240123180321623

漏洞分析

XSS

XSS漏洞一般从功能点去回溯审计。

网站的评论区往往是存储型 XSS 漏洞的“重灾区”,若研发人员未能对评论数据同时做好“输入校验、过滤”以及“输出转义”,则很容易受到存储型 XSS 的危害。因此在审计时,我们将把“输入点”与“输出点”作为关注对象。

下面开始审计:

在首页随便打开一条新闻,然后提交评论,使用burpsuite抓包或者F12

image-20240123173504090

image-20240123173518396

image-20240123173556182

可以看到请求路径是/comment_submit。

定位源码位置:

image-20240123173709706

下个断点,调试模式运行:

image-20240123173840457

再次评论,可以看到变量 text 接收了评论的内容

image-20240123174042182

跟进submit,在service层处理 text的位置 下断点

可以看到使用了 comment 对象的属性去保存 text 然后传递给 service.save ,text 的内容没有被改变

image-20240123174905592

跟进 service.save

在调用 dao 层的位置下断点

image-20240123175416465

可以看到看到 text 的内容还是没有改变

该方法调用了“CommentDao 接口的实现类的对象”的 save 方法,继续审计该方法,可以发现算法直接将 Comment 对象存入了数据库

image-20240123175727006

通过上述分析可知,用户评论功能这一输入点并未对输入数据进行参数校验或过滤直接存入了数据库。

但是在文章页面并没有触发XSS,可以猜测该网站已经在“输出点”(表现层)进行了转义工作。

接着,让我们来检查“输出点”,通过Response可以看到评论的内容在请求 /comment_list 时得到,并且该内容进行了HTML实体编码。

image-20240123180248783

使用 IDEA 的搜索功能查找该前端页面

image-20240123181630917

下断点调试一下:

image-20240123182222264

跟进 site.getTemplate 可以看到前端页面路径是 /1/default/sys_comment_list.html。

image-20240123182346071

定位到该文件,查看该页面是如何做转义处理的

image-20240123182712471

[#escape x as (x)!?html] 是一个FreeMarker模板中的指令,用于对变量进行HTML转义。

通过使用 [#escape x as (x)!?html],可以确保变量 x 中的特殊HTML字符被转义,以防止在HTML输出中引发意外的结果或潜在的安全漏洞。

我们之前在看 pom.xml 文件就可以发现该网站采用了模板引擎“Freemarker”

image-20240123181245675

通过查阅与 Freemarker 的“转义”相关的开发文档也发现 Jspxcms 对 Freemarker 转义的说明

image-20240123183413558

虽然 Info 页面已经做了“输出转义”的工作,那么是否会有其他跟评论相关的模板未做转义工作呢?

检查模板文件,可以发现模板文件sys_member_space_comment.html 未做转义输出

image-20240123184455832

继续在源码中搜索文件名sys_member_space_comment.html

image-20240123184640308

image-20240123184708297

sys_member_space.html 引用了它:当 HTTP 请求参数 type 的值为 comment 时,动态引用了 sys_member_space_comment.html 文件

继续搜索sys_member_space.html

image-20240123184859437

找到了它的控制器类

image-20240123185111218

space 方法使用了模板,也就是说访问路径的格式为 /space/{id} 时就能触发 XSS 了

image-20240123185305757

SSRF

SSRF 漏洞出现的场景有很多,如在线翻译、转码服务、图片收藏/下载、信息采集、邮件系统或者从远程服务器请求资源等。通常我们可以通过浏览器查看源代码查找是否在本地进行了请求,也可以使用 DNSLog 等工具进行测试网页是否被访问。但对于代码审计人员来说,通常可以从一些 http 请求函数入手,审计 SSRF 漏洞时需要关注的一些敏感函数:

HttpClient.execute() 
HttpClient.executeMethod() 
HttpURLConnection.connect() 
HttpURLConnection.getInputStream() 
URL.openStream() 
URL.openConnection()
openConnection()
HttpServletRequest() 
BasicHttpEntityEnclosingRequest() 
DefaultBHttpClientConnection() 
BasicHttpRequest() 
urlConnection.getInputStream
OkHttpClient.newCall.execute
Request.Get.execute
Request.Post.execute              
ImageIO.read

实战中可以先黑盒找一下请求外部地址的功能点,来定位关键位置,比如

image-20240124113842053

这里我们直接搜索敏感函数

SSRF1

直接使用 IDEA 搜索HttpClient.execute

HttpClient.execute 是 Apache HttpClient 库中的一个方法,用于执行 HTTP 请求并返回响应。

image-20240124114251042

挨个点击去看一下,我们需要能够控制url才行。

这里我们找到了fetchHtml方法

image-20240124120932105

查找用法

image-20240124133847878

它被当前类的另一个 fetchHtml() 调用

image-20240124133934721

继续查找用法

可以看到fetchUrl方法中url是直接通过参数传入的

image-20240124134254353

构造相应URL传参即可:

这里url从当前页面只能看到/ext/collect/fetch_url.do

但是因为这是后台程序,后台路径都以cmscp开头。这从主入口 Application.java就能看出来

image-20240124143245810

任何以 "/cmscp/" 开头的请求路径都将被映射到后台 Servle

image-20240124141038782

利用成功。当然这里只能利用http 或 https 协议去扫描端口或探测内网服务。不支持其他协议。

SSRF2

继续搜索其他敏感函数

openConnection

image-20240124151033213

定位到ueditorCatchImage函数,该函数的功能是获取并下载远程 URL 图片

image-20240124153007176

可以看到url是通过 http请求里的 source[]参数获得到,并且对于传入的 URL 并没有进行过滤,在得到 URL 的值后, 直接带入 openConnection(),这就造成了SSRF漏洞。

但是上述代码中将 openConnection() 返回的对象强制转换为 HttpURLConnection,如果传入的是非 http 或 https 协议, 则会报错。因此,该 SSRF 也是只能利用 http 或 https 协议去扫描端口或探测内网服务。

确定了存在漏洞,下一步就是寻找该代码对应的路径和功能点的位置:

查找ueditorCatchImage的用法

image-20240124153625116

可以看到两个用法,都是UploadController,一个前台,一个后台,代码是类似的,看一个就好

我们这里看前台的:

image-20240124154134242

可以看到路径是/ueditor,并且action参数等于catchimage的话就会调用ueditorCatchImage方法

那么我们构造请求如下:

image-20240124154429523

即可成功利用。

可以发现当该端口开放时,页面返回的内容带有 SUCCESS 字符。若是该端口未开放则返回 500 错误

image-20240124154505859

RCE1

在审计 RCE 漏洞时,首先要观察该项目所依赖的第三方 Jar 包,目的是了解项目有没有使用包含已知漏洞的第三方组件,如果使用了,那么参数是否可控也是我们需要确定的。

在《第三方组件漏洞审计》部分我们已经列出了Jspxcms 使用的一些第三方组件。当时我们发现目标使用了 Shiro 1.3.2,是存在Padding Oracle Attack(shiro-721)漏洞的

image-20240124161925420

但是想要触发 RCE 还需要一个利用链,所以我们还要在项目依赖的 Jar 包中 看看有没有可用的利用链,可以与ysoserial的利用链进行对比:

image-20240124172903136

首先对于Hibernate的两个利用链,Jspxcms 中引用了 Hibernate 5.0.12 版本

image-20240124173454425

但是测试该版本利用不了。

接下来是CC链,ysoserial中集成了好几条Commons Collections3.2.1版本下的利用链。 不过Jjspxcms中引用了的是commons-collections3.2.2。在 3.2.2 版本中 Apache Commons-collections 对一些不安全的 Java 类的序列化支持增加了开关,默认为关闭状态,因此也没法利用了。

image-20240124173949362

再往后找,到了commons-beanutils链, ysoserial 中 Commons-beanutils 的利用链不仅需要 Commons-beanutils,同时还需要 Commons-collections 以及 Commons-logging,也就是说需要目标中同时存在这 3 个第三方库的依赖,这条利用链才有效,好巧不巧在jspxcms中都有:

image-20240124174611401

但是依赖包版本和ysoserial中的有一些差异

我们需要在ysoserial源码的pom.xml文件中更换为jspxcms的版本,然后重新打包,生成payload尝试利用

image-20240124181708706

我们这里直接用shiro反序列化漏洞的利用工具(https://github.com/inspiringz/Shiro-721)进行测试:

首先前台登录勾选 自动登录,获取 rememberMe cookie

image-20240125105934415

生成payload:

image-20240125151003458

利用:

image-20240125151219129

image-20240125183642286

image-20240125192956253

文件解压漏洞(RCE2)

这个漏洞在文件管理的压缩包上传功能,上传的压缩包会被自动解压,如果我们在压缩包中放入 war 包并配合解压后目录穿越,war包就会被移动到tomcat的webapps目标下,而tomcat会自动解压部署war包。

分析一下:

上传抓包

image-20240124185815657

image-20240124185830037

该接口对应 /src/main/java/com/jspxcms/core/web/back/WebFileUploadsController.java 的 unzip 方法

image-20240124185907017

对 unzip 方法进行跟进,发现它的具体实现在/src/main/java/com/jspxcms/core/web/back/WebFileControllerAbstractor.java 中。在对 ZIP文件进行解压时,程序调用了 AntZipUtil 类的 unzip 方法

image-20240124190004075

对 AntZipUtil 类的 unzip 方法进行跟进,可发现该方法未对 ZIP 压缩包中的文件名进行参数校验就进行文件的写入。这样的代码写法会引发“目录穿越漏洞”:

image-20240124190347082

所以我们创建包含jsp webshell的war包:

image-20240124190543233

制作恶意 ZIP 文件

image-20240124190650057

上传完之后连接 webshell 成功 RCE

image-20240124190759683

这里测试需要启动 tomcat 做测试,而不是 IDEA 的 SpringBoot,否则可能无法成功。

Freemarker模板注入(RCE3)

这里其实也可以看作是一个功能

我们知道目标站点前端使用了Freemark模板引擎,Freemark是有模板注入漏洞的。

在Jspxcms后台模板文件处允许我们上传自定义模板,我们可以上传一个含有漏洞的模板

例如弹一个计算器:

index.html:

[#escape x as (x)!?html]
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"/>
</head>
<body>

${"freemarker.template.utility.Execute"?new()("calc")}

</body>
</html>
[/#escape]

先新建一个test文件夹,然后上传index.html

image-20240125135914357

然后转到网站设置,将模板主题更换为test,保存

image-20240125140034417

然后访问首页,即可弹计算器:

image-20240125143653816

参考

https://xz.aliyun.com/t/10891

《Java代码审计》

posted @ 2022-05-09 11:22  yokan  阅读(836)  评论(0编辑  收藏  举报