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
- jspxcms安装包(部署到Tomcat用来复现):https://www.ujcms.com/uploads/jspxcms-9.0.0-release.zip
- jspxcms源码包(部署到IDEA进行分析):https://www.ujcms.com/uploads/jspxcms-9.0.0-release-src.zip
MySQL 5.5.53
jspxcms源码包
在主目录中,src 目录为存放源码的目录,database 为存储 SQL 文件目录
创建名为 jspxcms_test 的数据库,并导入SQL 文件
create database jspxcms_test;
use jspxcms_test;
source mysql.sql;
接着打开 IDEA,选择 Open or Import,导入 Jspxcms 项目
再打开/src/main/resources/application.propertis 文件,修改 url、username、password 的值,其余保持默认即可
配置文件修改好后,继续修改 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相兼容的版本
因此将 pom.xml 文件中 的 MySQL 版本修改成 5.1.x 即可:
修改好后保存文件,点击重新加载maven
完成之后,在 Environment 选项中选择相应的 JDK 版
运行项目
访问http://127.0.0.1:8080/ ,即可看到该项目的主界面
访问 http://localhost:8080/cmscp/index.do,即可看到该项目管理界面的主界面
输入用户名为 admin,密码为空,单击登录按钮即可访问后台主界面
至此,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:跨域策略的配置文件
看完目录结构,可以浏览一下网站的功能点,前台、后台能交互的地方都挨个点点看看
可以在功能列表中寻找可能出现的漏洞点,如 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 |
... | ... |
更多可以看:
我们可以对所使用的 Jspxcms 的第三方组件的版本进行版本比对,以判断该版本是否受到已知漏洞的影响
漏洞分析
XSS
XSS漏洞一般从功能点去回溯审计。
网站的评论区往往是存储型 XSS 漏洞的“重灾区”,若研发人员未能对评论数据同时做好“输入校验、过滤”以及“输出转义”,则很容易受到存储型 XSS 的危害。因此在审计时,我们将把“输入点”与“输出点”作为关注对象。
下面开始审计:
在首页随便打开一条新闻,然后提交评论,使用burpsuite抓包或者F12
可以看到请求路径是/comment_submit。
定位源码位置:
下个断点,调试模式运行:
再次评论,可以看到变量 text 接收了评论的内容
跟进submit,在service层处理 text的位置 下断点
可以看到使用了 comment 对象的属性去保存 text 然后传递给 service.save ,text 的内容没有被改变
跟进 service.save
在调用 dao 层的位置下断点
可以看到看到 text 的内容还是没有改变
该方法调用了“CommentDao 接口的实现类的对象”的 save 方法,继续审计该方法,可以发现算法直接将 Comment 对象存入了数据库
通过上述分析可知,用户评论功能这一输入点并未对输入数据进行参数校验或过滤直接存入了数据库。
但是在文章页面并没有触发XSS,可以猜测该网站已经在“输出点”(表现层)进行了转义工作。
接着,让我们来检查“输出点”,通过Response可以看到评论的内容在请求 /comment_list
时得到,并且该内容进行了HTML实体编码。
使用 IDEA 的搜索功能查找该前端页面
下断点调试一下:
跟进 site.getTemplate 可以看到前端页面路径是 /1/default/sys_comment_list.html。
定位到该文件,查看该页面是如何做转义处理的
[#escape x as (x)!?html]
是一个FreeMarker模板中的指令,用于对变量进行HTML转义。
通过使用 [#escape x as (x)!?html]
,可以确保变量 x
中的特殊HTML字符被转义,以防止在HTML输出中引发意外的结果或潜在的安全漏洞。
我们之前在看 pom.xml 文件就可以发现该网站采用了模板引擎“Freemarker”
通过查阅与 Freemarker 的“转义”相关的开发文档也发现 Jspxcms 对 Freemarker 转义的说明
虽然 Info 页面已经做了“输出转义”的工作,那么是否会有其他跟评论相关的模板未做转义工作呢?
检查模板文件,可以发现模板文件sys_member_space_comment.html
未做转义输出
继续在源码中搜索文件名sys_member_space_comment.html
sys_member_space.html
引用了它:当 HTTP 请求参数 type 的值为 comment 时,动态引用了 sys_member_space_comment.html
文件
继续搜索sys_member_space.html
找到了它的控制器类
space 方法使用了模板,也就是说访问路径的格式为 /space/{id} 时就能触发 XSS 了
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
实战中可以先黑盒找一下请求外部地址的功能点,来定位关键位置,比如
这里我们直接搜索敏感函数
SSRF1
直接使用 IDEA 搜索HttpClient.execute
HttpClient.execute
是 Apache HttpClient 库中的一个方法,用于执行 HTTP 请求并返回响应。
挨个点击去看一下,我们需要能够控制url才行。
这里我们找到了fetchHtml
方法
查找用法
它被当前类的另一个 fetchHtml() 调用
继续查找用法
可以看到fetchUrl
方法中url是直接通过参数传入的
构造相应URL传参即可:
这里url从当前页面只能看到/ext/collect/fetch_url.do
但是因为这是后台程序,后台路径都以cmscp开头。这从主入口 Application.java就能看出来
任何以 "/cmscp/" 开头的请求路径都将被映射到后台 Servle
利用成功。当然这里只能利用http 或 https 协议去扫描端口或探测内网服务。不支持其他协议。
SSRF2
继续搜索其他敏感函数
openConnection
定位到ueditorCatchImage函数,该函数的功能是获取并下载远程 URL 图片
可以看到url是通过 http请求里的 source[]
参数获得到,并且对于传入的 URL 并没有进行过滤,在得到 URL 的值后, 直接带入 openConnection(),这就造成了SSRF漏洞。
但是上述代码中将 openConnection() 返回的对象强制转换为 HttpURLConnection,如果传入的是非 http 或 https 协议, 则会报错。因此,该 SSRF 也是只能利用 http 或 https 协议去扫描端口或探测内网服务。
确定了存在漏洞,下一步就是寻找该代码对应的路径和功能点的位置:
查找ueditorCatchImage
的用法
可以看到两个用法,都是UploadController,一个前台,一个后台,代码是类似的,看一个就好
我们这里看前台的:
可以看到路径是/ueditor
,并且action
参数等于catchimage
的话就会调用ueditorCatchImage
方法
那么我们构造请求如下:
即可成功利用。
可以发现当该端口开放时,页面返回的内容带有 SUCCESS 字符。若是该端口未开放则返回 500 错误
RCE1
在审计 RCE 漏洞时,首先要观察该项目所依赖的第三方 Jar 包,目的是了解项目有没有使用包含已知漏洞的第三方组件,如果使用了,那么参数是否可控也是我们需要确定的。
在《第三方组件漏洞审计》部分我们已经列出了Jspxcms 使用的一些第三方组件。当时我们发现目标使用了 Shiro 1.3.2,是存在Padding Oracle Attack(shiro-721)漏洞的
但是想要触发 RCE 还需要一个利用链,所以我们还要在项目依赖的 Jar 包中 看看有没有可用的利用链,可以与ysoserial的利用链进行对比:
首先对于Hibernate的两个利用链,Jspxcms 中引用了 Hibernate 5.0.12 版本
但是测试该版本利用不了。
接下来是CC链,ysoserial中集成了好几条Commons Collections3.2.1版本下的利用链。 不过Jjspxcms中引用了的是commons-collections3.2.2。在 3.2.2 版本中 Apache Commons-collections 对一些不安全的 Java 类的序列化支持增加了开关,默认为关闭状态,因此也没法利用了。
再往后找,到了commons-beanutils链, ysoserial 中 Commons-beanutils 的利用链不仅需要 Commons-beanutils,同时还需要 Commons-collections 以及 Commons-logging,也就是说需要目标中同时存在这 3 个第三方库的依赖,这条利用链才有效,好巧不巧在jspxcms中都有:
但是依赖包版本和ysoserial中的有一些差异
我们需要在ysoserial源码的pom.xml文件中更换为jspxcms的版本,然后重新打包,生成payload尝试利用
我们这里直接用shiro反序列化漏洞的利用工具(https://github.com/inspiringz/Shiro-721)进行测试:
首先前台登录勾选 自动登录,获取 rememberMe cookie
生成payload:
利用:
文件解压漏洞(RCE2)
这个漏洞在文件管理的压缩包上传功能,上传的压缩包会被自动解压,如果我们在压缩包中放入 war 包并配合解压后目录穿越,war包就会被移动到tomcat的webapps目标下,而tomcat会自动解压部署war包。
分析一下:
上传抓包
该接口对应 /src/main/java/com/jspxcms/core/web/back/WebFileUploadsController.java
的 unzip 方法
对 unzip 方法进行跟进,发现它的具体实现在/src/main/java/com/jspxcms/core/web/back/WebFileControllerAbstractor.java
中。在对 ZIP文件进行解压时,程序调用了 AntZipUtil 类的 unzip 方法
对 AntZipUtil 类的 unzip 方法进行跟进,可发现该方法未对 ZIP 压缩包中的文件名进行参数校验就进行文件的写入。这样的代码写法会引发“目录穿越漏洞”:
所以我们创建包含jsp webshell的war包:
制作恶意 ZIP 文件
上传完之后连接 webshell 成功 RCE
这里测试需要启动 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
然后转到网站设置,将模板主题更换为test,保存
然后访问首页,即可弹计算器:
参考
《Java代码审计》