CVE-2023-0669: GoAnywhere MFT RCE 漏洞链分析

CVE-2023-0669: GoAnywhere MFT RCE 漏洞链深度分析

0x01 漏洞背景与详情

CVE-2023-0669 是 Fortra GoAnywhere MFT 中一个非常典型、也非常有现实破坏力的管理面漏洞。它的危险点不只是“可执行命令”,而是打在了企业对外文件交换平台上,这类系统往往天然承载高价值文件、外联账号、合作伙伴连接器和批处理任务。

  • CVE ID: CVE-2023-0669
  • 影响产品: Fortra GoAnywhere MFT
  • 受影响版本: 7.1.1 及更早版本
  • 修复版本: 7.1.2
  • 核心组件: LicenseResponseServlet
  • 漏洞类型: 不安全反序列化 / 预认证命令执行
  • 现实影响:
    • 远程代码执行
    • 新增未授权管理账号
    • 文件下载与数据外流
    • 落地 JSP/工具型后门
    • 作为后续勒索或批量窃密入口

需要注意的是,NVD 的 CVSS 3.1 记录显示 PR:H,但公开研究普遍指出,真正的危险点在于只要攻击者能触达管理面端口或借浏览器间接触达该端口,就可能在未完成正常登录流程的情况下触发漏洞。因此在真实暴露面治理中,应把它当作“管理面暴露导致的近似预认证 RCE”来理解,而不是简单理解为“必须先有高权限账号”。

0x02 漏洞原理分析

1. 问题入口在 LicenseResponseServlet

GoAnywhere 管理端提供了许可证处理逻辑,相关请求会进入 LicenseResponseServlet,并处理参数 bundle。公开分析表明,该参数最终会进入类似 LicenseAPI.getResponse() -> LicenseController.getResponse() -> BundleWorker.unbundle() 的调用链。

2. bundle 并不是普通文本,而是“加密包裹后的序列化对象”

这个漏洞最关键的一点在于:bundle 不是简单 JSON 或表单字段,而是一个经过特定算法处理的对象数据。GoAnywhere 会先对其做解密/拆包,然后把结果交给 Java 反序列化流程。

这意味着攻击者如果能:

  1. 伪造符合目标版本格式的 bundle
  2. 让服务端成功解密
  3. 把恶意 Java 序列化对象送入反序列化链

就可以把“许可证响应处理”转化成“反序列化执行面”。

3. 根因不是单点加密问题,而是“信任了攻击者可构造对象”

公开 PoC、Exploit-DB helper 以及 Metasploit 模块都说明,攻击者可以针对 GoAnywhere 不同签名版本构造 bundle,并用公开可还原的派生参数完成加密,再把恶意序列化对象提交到目标。

真正的漏洞根因是:

  • 服务端会对攻击者可控数据做反序列化
  • 反序列化前缺乏足够可信边界校验
  • 加密包装没有形成真正的安全边界

所以本质上,这是一个被“许可证响应流程”包装起来的 Java 反序列化 RCE

0x03 漏洞链细节

这条链可以抽象为下面几个阶段。

阶段一:发现管理面

GoAnywhere 的 Web Client 并不是漏洞入口,真正危险的是 Admin Console。公开测绘显示,很多实例把管理面直接暴露在 8000/8001 端口。

阶段二:命中 /goanywhere/lic/accept

公开分析与 Metasploit 模块都表明,危险端点是:

  • /goanywhere/lic/accept

部分研究与日志片段还出现了携带附加 path segment 的变体路径,本质上都落到同一许可证处理逻辑。

阶段三:构造 bundle

攻击者先生成恶意 Java 序列化对象,再按 GoAnywhere 的历史版本差异选取对应的 bundle 包装方式。

研究中常见两种签名/加密分支:

  • Version 1
  • Version 2,通常以 "$2" 作为版本后缀

这也是为什么公开利用代码普遍会探测或切换版本,而不是“一条 payload 打天下”。

阶段四:服务端解包并反序列化

服务端对 bundle 进行解密、拆包后,将内部对象反序列化。若 gadget 链可用,就会进入命令执行。

阶段五:RCE 之后转为平台控制与数据窃取

厂商后续调查显示,攻击者并不满足于“打一条命令验证成功”,而是进一步:

  • 创建未授权用户
  • 借新增账号下载文件
  • 落地 Errors.jsp
  • 投放 Netcat

这说明 CVE-2023-0669 在实战中更多被当作数据交换平台接管入口,而不是一次性的临时 RCE。

0x04 POC 思路

出于安全考虑,不提供可直接运行的 exp,只保留研究型 POC 思路。

研究型 POC 的最小逻辑

  1. 确认目标是否暴露管理面端口。
  2. 确认目标是否存在 /goanywhere/lic/accept 处理路径。
  3. 构造一个安全测试用的序列化对象,而不是直接执行系统命令。
  4. 按目标版本使用匹配的 bundle 打包方式。
  5. 发送到许可证响应端点,观察状态码、报错差异和日志栈。

防守型验证重点

防守团队做内网自查时,POC 不应该追求“弹 shell”,而应该优先验证:

  • 目标是否仍能处理外部提交的 bundle
  • 目标对 Version 1 / Version 2 是否都响应
  • 是否出现典型反序列化异常栈
  • 修复后是否从旧版的异常响应变为新版本的拦截响应

一个很实用的验证思路

公开研究提到,漏洞实例在命中后往往返回 HTTP 500,而修复后的版本可能返回 HTTP 400 或直接拒绝请求。因此蓝队在隔离环境中,可把“响应差异 + 日志差异”作为是否已修补的重要辅助依据。

0x05 高级实战利用姿势 (Weaponization)

1. 不必强依赖公网直连,也可以走“浏览器辅助触达”

Rapid7 分析特别值得注意的一点是:攻击者未必非要从公网直接连到管理端口。只要企业内部有人能访问该管理面,攻击者就可能借助:

  • 钓鱼邮件
  • 开放重定向
  • 内部用户浏览器跳转

把受害者浏览器当成“代打通道”,间接把恶意请求送到内网可达的 Admin Console。这让“只做源 IP 限制”不再是完整防线。

2. 版本自适应是批量利用的关键

公开利用代码之所以稳定,核心并不只是 gadget,而是能对 Version 1 / Version 2 的打包方式自适应。这意味着攻击者可以把“漏洞是否存在”与“版本兼容性探测”合并到同一套扫描利用链里,形成自动化批量打法。

3. 最终目的通常不是交互 shell,而是接管平台业务能力

厂商事后调查表明,真实攻击者后续动作更偏向:

  • 新建管理/业务账号
  • 下载托管文件
  • 落地 Errors.jsp
  • 部署 Netcat

这说明攻击者真正看中的,是:

  • 平台上已经汇聚的文件
  • 平台保存的外部系统凭据
  • 与合作伙伴、SFTP、云存储的信任关系

也就是说,GoAnywhere 失陷后的价值通常比一台普通 Web 服务器更高。

4. RCE 上下文经常就是高价值服务账号

Huntress 公开案例里,后续命令执行链是在 GoAnywhereSvcAccttomcat.exe 上下文下发生的。这种上下文往往已经具备:

  • 对应用目录的写权限
  • 对批处理任务的访问能力
  • 对中间件与日志目录的读写能力

因此攻击者常常不需要再额外提权,就已经能完成落地、持久化和数据回传。

5. MFT 平台失陷后的扩大战果

如果环境里保存了外部系统集成凭据,后续很容易扩大为:

  • 合作伙伴数据接口被连带访问
  • 云存储密钥泄露
  • 交换文件被批量导出
  • 与勒索团伙常见的“只偷不加密”流程结合

从 2023 年多个 MFT 事件看,这也是此类平台反复成为高价值攻击目标的原因。

0x06 应急排查与日志痕迹分析

1. 先查访问入口

优先在 Web 访问日志、反向代理日志、WAF 日志中检索:

  • /goanywhere/lic/accept
  • /goanywhere/lic/accept/
  • 带异常 path segment 的 /lic/accept 请求
  • 管理端口 8000/8001 上的非常规来源访问

重点关注:

  • 来自公网的非常规源地址
  • 短时间内重复 POST/GET 触发
  • 命中后返回 500 的异常请求

2. 检索 GoAnywhere 应用日志

公开资料建议排查:

  • userdata/logs/[system_name]-goanywhere.log
  • 集群环境中全部归档日志

重点搜索关键词:

  • LicenseResponseServlet
  • BundleWorker.unbundle
  • LicenseController.getResponse
  • Error parsing license response
  • BundleException
  • ObjectInputStream.readObject

公开研究中可见的异常栈特征之一是:

com.linoma.license.gen2.BundleException: Class name not accepted: java.util.PriorityQueue
at com.linoma.license.gen2.BundleWorker.unbundle(BundleWorker.java:136)
at com.linoma.license.gen2.LicenseController.getResponse(LicenseController.java:441)

这类错误并不等价于“利用成功”,但对蓝队来说,它已经是非常强的探测信号,说明有人在向许可证处理链灌入异常对象。

3. 账号与审计日志非常关键

Fortra 官方调查明确提到,攻击者曾:

  • 创建未授权用户
  • 用这些账号下载文件

因此应重点审查:

  • 新增管理员账号
  • 名称陌生、来源不明的 Web 用户
  • 由系统自动创建但无法解释的账号
  • 短期内大量文件下载记录

4. 文件落地痕迹

已公开的事件中,攻击者被观察到落地:

  • Errors.jsp
  • Netcat

因此应检查:

  • GoAnywhere 安装目录
  • adminroot
  • Web 根目录与临时目录
  • Tomcat 工作目录
  • JSP、WAR、JAR 的新增或异常修改

5. 进程与后利用痕迹

Huntress 事件中与该漏洞利用时序相关的后续行为包括:

  • certutil 拉取远端资源
  • rundll32.exe C:\Users\Public\gamft.dll,ChkdskExs
  • 伪装成 NVIDIA 崩溃上报的计划任务

重点可搜索:

  • certutil -urlcache
  • rundll32
  • gamft.dll
  • NvTmRep_CrashReport
  • tomcat.exe 触发的系统命令

如果在 GoAnywhere 主机上看到 tomcat.exe 拉起本地系统命令、下载 DLL、创建计划任务,这基本应按已失陷处理,而不是按“普通漏洞扫描”处理。

0x07 修复与缓解建议

1. 立即升级到 7.1.2 或更高版本

这是最直接的修复手段。对历史镜像、灾备节点、集群节点也要同步核验,避免“主节点已修、旁路节点未修”的情况。

2. 不能马上升级时,先下线 LicenseResponseServlet

官方早期缓解思路是修改:

  • [install_dir]/adminroot/WEB-INF/web.xml

移除或注释 LicenseResponseServlet 及其 /lic/accept/ 映射,再重启服务。对于集群环境,必须在每个节点一致处理。

3. 不要让 Admin Console 暴露公网

这条建议对 MFT 平台尤其重要。应至少做到:

  • 管理面不公网暴露
  • 仅允许 VPN / 跳板 / 白名单接入
  • 对管理端启用更严格认证控制
  • 把 Web Client 与 Admin Console 分开治理

4. 按“已失陷”而不是“已修复”来处置

补丁只能阻止继续利用,不能撤销已经完成的入侵。若发现异常日志、异常用户或可疑文件,应同时执行:

  • 隔离主机
  • 保全日志与镜像
  • 删除可疑账号前先取证
  • 检查文件下载与外传范围
  • 审核所有与 GoAnywhere 关联的外部连接器

5. 轮换密钥与外部联系统凭据

Fortra 明确建议在缓解后继续:

  • 轮换 Master Encryption Key
  • 重置所有密码和密钥
  • 包括外部交易伙伴和集成系统的凭据

这是因为 MFT 平台通常会保存大量外部系统访问材料,失陷后影响范围可能大于单机。

0x08 参考资料