针对 Liferay CE 7.0.3 GA4 的安全研究:以 root 身份实现端到端复现的未认证 RCE(CVE-2020-7961 类漏洞),另有 16 项发现——其中 8 项以上没有已知 CVE。智能体循环漏洞狩猎:基于 Docker 的 25 个生成器、22 个评判器、9 个实时验证器。包含完整证据链与一键检测器。
这是一次对 Liferay Portal CE 7.0.3 GA4(git 标签 7.0.3-ga4,提交 b2d7cc68a)的安全审计,采用 RAPTOR loop-hunt 方法论执行:确定性侦察 → 25 个隔离的生成 agent 阅读原始源码 → 22 个独立裁决 agent 基于原始源码进行驳斥 → 9 个实况验证器攻击 Docker 中的真实 GA4 实例。
头条: 以
root身份的无认证 RCE 已端到端复现(CVE-2020-7961 类别),另有 8 个经实况验证的漏洞 —— 其中数个没有已知 CVE。
⚠️ 法律/伦理: 此处所有内容均针对自托管的测试实例。Liferay CE 7.0 已停止维护(EOL)(最后一个版本 7.0.6 GA7,2018 年);这些问题上游未修补。仅可对你拥有或被明确授权测试的系统使用此材料。
状态:✅ 已在 Docker GA4 实例上实况验证 · 🔬 经代码确认(独立裁决 agent 从原始源码重新推导出完整链路) · 🧪 待实况验证/受配置门控
含驳回理由的完整精选清单:FINDINGS.md · 叙述性报告:REPORT.md
用作既有知识的约 50 个已知 Liferay 7.0.x 问题目录:PRIOR-ART.md(OSV [email protected]、NVD 扫描、Code White / CERT-EU 公告)。
"新发现" = 截至 2026-07,在 OSV/NVD/Liferay 公告中未找到匹配的 CVE;这些发现尚未提交 CVE 编号申请(该产品线已停止维护(EOL))。
CVE-2020-15840(双重编码 URL 过滤器绕过)、CVE-2024-8980 + CVE-2025-43748(CSRF → 脚本控制台 RCE)、CVE-2021-33335(公司管理员接管——GA4 处于受影响区间的下限)、CVE-2017-1000425(flash.jsp XSS)、CVE-2021-29040(详细的 JSONWS 错误信息)、CVE-2022-41414 / CVE-2023-33949(枚举/注册默认值)、CVE-2025-62261(明文重置令牌——NVD 直接点名 7.0.3 GA4)。参见 PRIOR-ART.md。
台账:TRIED.md(所有尝试,含 3 个已记录的空跑切片)· INVENTORY.md(覆盖率分母)· 环境/测试夹具:ENV.md
没有官方的 liferay/portal:7.0.3-ga4 镜像,因此请从官方捆绑包构建:
# Dockerfile
FROM openjdk:8-jdk
RUN apt-get update && apt-get install -y --no-install-recommends unzip curl \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSL -o /tmp/liferay.zip \
"https://downloads.sourceforge.net/project/lportal/Liferay%20Portal/7.0.3%20GA4/liferay-ce-portal-tomcat-7.0-ga4-20170613175008905.zip" \
&& unzip -q /tmp/liferay.zip -d /opt \
&& mv /opt/liferay-ce-portal-7.0-ga4 /opt/liferay \
&& rm /tmp/liferay.zip
EXPOSE 8080 11311
CMD ["/opt/liferay/tomcat-8.0.32/bin/catalina.sh", "run"]
docker build -t liferay-ga4 .
docker run -d --name liferay-ga4 -p 8080:8080 liferay-ga4
# first boot takes several minutes — wait for it:
until [ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/)" = 200 ]; do sleep 10; done
然后在 http://localhost:8080/ 完成一次性设置向导(默认 HSQL 数据库;向导会为 [email protected] 设置管理员密码)。
tools/liferay_ga4_check.py 是一个单文件、仅使用标准库的 Python 3 脚本——只要将它指向任意 GA4 实例,它就会测试所有经实况验证的发现:
# passive validation of all findings (safe, no payloads detonated)
python3 tools/liferay_ga4_check.py http://localhost:8080
# with an account (self-registration is on by default) for the poller sink test
python3 tools/liferay_ga4_check.py http://localhost:8080 --user [email protected] --password '***'
# full RCE proof (opt-in): drops a SELF-DELETING JSP via the deserialization file-write
# gadget and fetches the command output; adjust --web-root to your install
python3 tools/liferay_ga4_check.py http://localhost:8080 --rce \
--web-root /opt/liferay/tomcat-8.0.32/webapps/ROOT
针对默认 GA4 安装的预期输出:9 项发现为 VULNERABLE(易受攻击)(F-1、F-1+RCE、F-2、F-4、F-5*、F-8、F-11、F-12、F-13*),另有 F-10 确认为不易受攻击(隧道屏障有效)。*F-5 和 F-13 需要测试夹具参数(--leg-uuid/--version-id、--wcd-page/--group-id/--article-id)——参见 --help。
反序列化 gadget 在脚本内部以纯 Python 生成(已对照本次行动中使用的 ysoserial AspectJWeaver payload 进行字节级验证)——无需 Java、jar 包或 ysoserial。
密码重置票据(128 位 UUID、一次性使用、24 小时)、票据登录时更新会话、使用每公司 SecureRandom 密钥的 AES-128 记住我 Cookie、默认 PBKDF2 哈希、门户全域 XML 栈(默认禁用外部实体)、WebDAV/SharePoint 摘要认证门禁、/api/axis|/api/liferay|/api/atom 的 localhost IP 锁定、上传路径验证、/combo /sprite 目录遍历防护、脚本控制台与 Gogo Web UI 的 omni-admin 门禁。
覆盖率已按组件对照完整清单进行追踪(TRIED.md)。未覆盖:整个 4 GB 代码树的逐函数级审查(仅依赖 Semgrep 锚点)、modules/apps 中 foundation/web-experience 之外大部分模块(仅文件级审查)、F-2 gadget 研究、非默认配置的实况测试(F-9/F-14)、以及 PDFBox 2.0.3 依赖 CVE 的可达性。循环是为了撰写报告而暂停,并非因为已无路可走。
| ID | 发现 | 严重性 | 认证 | 状态 | 证据 |
|---|
| F-1 | JSONWS 类型覆盖 → 任意类实例化 + setter → 以 root 身份 RCE(c3p0 HexAsciiSerializedMap → ObjectInputStream → AspectJWeaver 文件写入 → JSP) | 严重 | 无 | ✅ | verified/f1-jsonws-deser-rce.md |
| F-2 | /poller/* jabsorb javaClass 提示 → 任意类实例化 + 字段注入,发生在 userId 校验之前 | 高(潜在) | 任意账户(默认开启自助注册) | ✅ sink / RCE 分支开放 | verified/F-2-poller.md |
| F-4 | XML-RPC pingback.ping 先取回后校验 → 盲 SSRF + 内网端口预言机(已触达 127.0.0.1:11311 上的 Gogo shell) | 中等 | 无 | ✅ | verified/f4-xmlrpc-pingback-ssrf.md |
| F-5 | SyncDownloadServlet versionId IDOR → 读取任意 DL(文档库)文件版本(跨站点,对流式传输的对象无 VIEW 校验) | 高 | 无(经由访客可见的 "leg" 路径) | ✅ | verified/F-5.md |
| F-6 | XSL 模板引擎忽略沙箱(secureProcessing=false,restricted 被丢弃)→ document() SSRF 以及 XSLTC rt:exec 命令执行 | 严重 | 站点模板作者 | ✅ | verified/F-6-F-7-template-engines.md |
| F-7 | Velocity 和 FreeMarker 受限模板暴露原始 propsUtil / saxReaderUtil → 门户属性 + file:// 泄露给访客 | 高 | 模板作者 | ✅ | verified/F-6-F-7-template-engines.md |
| F-8 | 通过 /image/*?img_id=N 的 Image_ 表 IDOR —— 无令牌,前缀作用域校验可通过前缀替换绕过,顺序 ID 可枚举 | 中等 | 无 | ✅ | verified/f-8-image-idor.md |
| F-11 | SimpleCaptcha = 4 位 PIN,猜错后从不失效,访客计数器从不递增 → 约 5k 次请求即可攻破 | 中等 | 无 | ✅ | verified/f11-f12-captcha-reminder.md |
| F-12 | 忘记密码:用户枚举 + 找回答案预言机无需验证码(新会话绕过);对于无安全问题账户,空答案会触发真实的重置票据 | 中-高 | 无 | ✅ | verified/f11-f12-captcha-reminder.md |
| F-13 | Web Content Display 请求参数覆盖(groupId/articleId/ddmTemplateKey)→ 跨站点读取非访客文章(默认 journal.article.view.permission.check.enabled=false) | 高 | 无(需要在访客页面上有一个 WCD) | ✅ | verified/F-13-wcd-param-override.md |
| F-3 | OSGi axis-extender 在模块 SOAP 服务上跳过 ServiceAccessPolicy / 远程访问标记 | 中等(配合 WSDD 模块时为高) | 无 | 🔬 | judge/axis-spring-remoting.md |
| F-9 | OpenID 在断言验证之前将受害者账户链接到攻击者的 OpenID → 账户接管 | 高 | 无(OpenID 已启用,非默认) | 🔬 🧪 | judge/sso-autologin.md |
| F-10 | TunnelServlet readObject 仅由类黑名单保护;classpath 上存在 ROME/JdbcRowSetImpl/c3p0/AspectJWeaver gadget | 潜在严重 | 可信对端(共享密钥 + 允许的主机) | ✅ 认证前屏障有效 | verified/f10-f20-tunnel-auth-pipeline.md |
| F-14 | TokenAutoLogin 信任裸 SM_USER 请求头(无验证、无 IP 白名单) | 中等 | 无(已启用 token SSO,非默认) | 🔬 🧪 | judge/sso-autologin.md |
| F-15 | 站点管理员的 LAR 导入走私 RolesAdminPortletDataHandler → 批量删除公司角色 / 清除权限 | 中等 | 站点管理员 | 🔬 | judge/export-import-lar.md |
| F-16 | OpenSocial(不在默认捆绑包中):认证前 makeRequest SSRF、/gadgets/ifr 来源 JS、可伪造的安全令牌 → 冒充、存储型 XSS | 高 ×4 | 无 / 站点成员 | 🔬(视部署而定) | judge/opensocial-shindig.md |
| F-17 | WSRP(不在默认捆绑包中):认证前 ProxyServlet SSRF;标记端点 → 任意 portlet 渲染 + 布局 typeSettings 持久化 | 中等 | 无 | 🔬(视部署而定) | judge/wsrp.md |
| 发现 | 已知 CVE? | 关联 |
|---|
| F-1 JSONWS 反序列化 RCE | CVE-2020-7961(CISA KEV,已在野外被利用) | 复现 + 独立重新推导。 确认在 GA4 中未修补;已使用 AspectJWeaver 文件写入 gadget 证明完整链路(公开 PoC 通常使用 JdbcRowSetImpl JNDI)。 |
F-10 TunnelServlet readObject | CVE-2020-15842(类别匹配) | 已知类别。 确认仅依赖黑名单的反序列化防护;认证前屏障已实况验证(无共享密钥/允许主机则不可利用)。 |
F-7 模板 propsUtil 逃逸 | CVE-2020-13445(模板注入,FreeMarker/Velocity) | 变体。 同一缺陷类别(模板 API 未能限制敏感对象),机制不同:原始 PropsImpl/saxReaderUtil 对象在受限上下文内部暴露。 |
| F-12(枚举部分) | CVE-2021-33321(login.secure.forgot.password=false) | 已知的不安全默认值 —— 已实况独立确认。 |
| F-12(预言机 + 空答案重置票据) | 未找到 | 新发现。 第 2 步通过全新 JSESSIONID 绕过验证码;空 answer 可为无安全问题账户在零秘密知识的情况下创建有效的 24 小时重置票据。 |
| F-11 SimpleCaptcha 暴力破解 | 未找到(CVE-2019-6588 是另一个验证码问题——XSS) | 新发现。 4 位 PIN + 不失效 + 绕过访客计数器。 |
| F-2 poller jabsorb 反序列化 | 未找到 | 新发现。 sink 已实况确认;武器化受 LiferaySerializer 字段注入阻碍(开放研究)。 |
| F-4 pingback SSRF 预言机 | 未找到 | 新发现。 |
F-5 sync versionId IDOR | 未找到 | 新发现。 |
| F-6 XSL 引擎 RCE | 未找到(CVE-2020-13445 仅涵盖 FreeMarker/Velocity) | 新发现。 XSL 引擎在以往所有模板注入修复的范围之外。 |
F-8 Image_ IDOR | 未找到 | 新发现。 |
| F-13 WCD 跨站点读取 | 未找到 | 新发现。 根因是不安全默认值(journal.article.view.permission.check.enabled=false),外加一条新的投递路径(portlet 请求参数覆盖)。 |
| F-3 axis-extender SAP 绕过 | 未找到 | 新发现。 |
| F-9 OpenID 先链接后验证 | 未找到 | 新发现。 |
F-14 SM_USER 请求头信任 | 未找到 | 新发现。 |
| F-15 LAR 角色 data-handler 走私 | 未找到 | 新发现。 |
| F-16 / F-17 OpenSocial / WSRP | 未找到 | 新发现,但这些模块不在默认 GA4 捆绑包中(Liferay-Releng-Bundle: false)。 |
| 轮次 | 执行内容 | 输出 |
|---|
| 0 — 确定性 | raptor-sca 依赖审计(727 个依赖)、17 条 Semgrep 规则(1,098 个锚点)、威胁模型、来自 web.xml 的入口点清单、既有 CVE 目录 | SCA.md SEMGREP.md THREAT-MODEL.md ENTRYPOINTS.md PRIOR-ART.md |
| 1 — 生成 | 25 个隔离 agent,每个组件切片 × 缺陷类别视角一个,推理仅依据原始源码(无先前摘要——反锚定) | 45 个候选,见 candidates/ |
| 2 — 裁决 | 22 个独立 agent 基于原始源码驳斥每个候选;判定成立需要代码中可见的证据("不要假设未见的层是安全的") | judge/ |
| 3 — 实况验证 | 9 个 agent 攻击 Docker GA4 实例;每项声明均有捕获的请求/响应佐证;强制清理 | verified/ |