WebGoat-代码审计报告

20次阅读
没有评论

WebGoat 代码审计报告

审计对象: OWASP WebGoat (WebGoat 2026.2-SNAPSHOT) — 基于 Java 25 + Spring Boot 4.1.0 + Thymeleaf + HSQLDB 的故意设计存在漏洞的 Web 安全教学靶场,含主应用 WebGoat(:8080/WebGoat) 与伴生应用 WebWolf(:9090/WebWolf)
审计时间: 2026-08-12
审计范围: 全站 Java 源码(webgoat-container 框架层、lessons/* 约 30 个课程模块、webwolf 伴生应用)、安全配置(WebSecurityConfig、application-*.properties)、Thymeleaf 模板
审计目的: 定位可导致系统权限/系统数据、用户权限/用户数据、应用权限/应用数据泄露或篡改的漏洞(反序列化、命令执行/RCE、SQL 注入、未授权访问、硬编码密钥/账号密码、XSS、SSRF、越权)

⚠️ 重要声明: WebGoat 是有意的漏洞靶场,lessons/* 下的"漏洞"绝大多数是项目故意构造的教学样例。本报告的价值在于区分:框架/容器层真实缺陷(非课程故意,最具实战价值)与课程故意漏洞(教学用途,仍逐条记录供学习)。本报告仅作防御性安全研究参考,禁止将其中任何技术用于未授权目标。


一、审计结论摘要

# 漏洞类别 严重级别 是否故意 主要位置 最大影响
1 越权 + 路径穿越(WebWolf 文件服务器) 🔴 严重 否·框架缺陷 webwolf/FileServer.java:75、webwolf/WebSecurityConfig.java:37-44、MvcConfiguration.java:25 匿名跨用户下载任意文件;登录用户路径穿越写入任意文件
2 匿名发信 + 存储型 XSS(WebGoat 邮箱) 🔴 严重 否·框架缺陷 MailboxController.java:58-65、mailbox.html:142 未认证向任意用户邮箱注入 XSS → 窃取会话/Cookie
3 未授权访问(Actuator 配置泄露) 🟠 高 否·框架缺陷 application-webgoat.properties:76-77、container/WebSecurityConfig.java:44 未认证读取 /actuator/env、/actuator/configprops,泄露数据源/密钥库/OAuth 配置
4 存储型 XSS(WebWolf requests 页) 🟠 高 否·框架缺陷 webwolf/templates/requests.html:39,47 请求头携带脚本 → 所有 WebWolf 用户触发存储型 XSS
5 硬编码管理员账号(重启后重置) 🟠 高 否·框架缺陷 container/users/DefaultUserInitializer.java:25-27,35-49 已知 webgoat-admin/webgoat 管理员口令,重置后仍会被还原
6 越权(任意邮箱清空 / OAuth 覆盖口令) 🟠 高 否·框架缺陷 MailboxController.java:67-71、RegistrationController.java:65 未认证 DELETE /mail 清空全部用户邮件;OAuth 登录覆盖已有用户口令
7 反序列化 RCE(XStream 1.4.5) 🔴 严重 是·课程(版本为真实依赖风险) lessons/vulnerablecomponents/VulnerableComponentsLesson.java:26-42、pom.xml:111 CVE-2013-7285 反序列化远程代码执行
8 反序列化(ObjectInputStream) 🟠 高 是·课程 lessons/deserialization/InsecureDeserializationTask.java:42-45 无白名单 readObject() → 构造 payload 执行命令
9 XXE 🟠 高 是·课程 lessons/xxe/CommentsCache.java:68-82 外部实体 → 任意文件读取 / SSRF / OOB 数据外带
10 SQL 注入 🔴 严重 是·课程 lessons/sqlinjection/*、lessons/jwt/claimmisuse/JWTHeaderKIDEndpoint.java:74-76 拖库、认证绕过、篡改数据
11 路径穿越(上传,课程) 🟠 高 是·课程 lessons/pathtraversal/ProfileUploadBase.java:48-53 等 覆盖课程目录文件、读取隐藏 secret
12 硬编码密钥 / 账号密码 🟠 高 是·课程(框架亦存在) lessons/jwt/JWTRefreshEndpoint.java:45、lessons/spoofcookie/*、lessons/authbypass/* 伪造 JWT / 直接登录 / 账号接管
13 XSS(课程) 🟠 高 是·课程 lessons/xss/* 窃取 Cookie/会话
14 SSRF 🟡 中 是·课程 lessons/ssrf/SSRFTask2.java:34、lessons/jwt/claimmisuse/JWTHeaderJKUEndpoint.java:55-57 泄露服务器公网 IP / 内网探测
15 越权 / 认证绕过(课程) 🟠 高 是·课程 lessons/idor/*、lessons/authbypass/*、lessons/missingac/*、lessons/challenges/challenge8/* 查看/篡改他人数据、提权
16 弱会话 / 开放重定向(课程) 🟡 中 是·课程 lessons/hijacksession/*、lessons/openredirect/* 会话预测劫持 / 钓鱼跳转

结论: 本靶场在课程层覆盖了用户要求的全部漏洞类别(均故意构造)。真正有价值的是框架/容器层 6 组非课程缺陷(#1–#6):WebWolf 文件服务的匿名越权 + 路径穿越、邮箱的匿名存储型 XSS、Actuator 未授权配置泄露、requests 页存储型 XSS、硬编码管理员账号(重启还原)、以及全局越权清理接口。其中 #1、#2 组合可在未登录情况下完成跨用户文件读写与 XSS 会话窃取,是攻击面最大、且不随任何"安全级别"而收敛的真实问题。


二、漏洞详情

说明:每项标注 是否故意——「否·框架缺陷」为真实漏洞(重点);「是·课程」为靶场故意教学漏洞。


2.1 🔴 越权 + 路径穿越 — WebWolf 文件服务器(框架缺陷)

🔴 2.1.1 匿名跨用户文件下载(IDOR)

  • 文件: src/main/java/org/owasp/webgoat/webwolf/WebSecurityConfig.java:37-44、MvcConfiguration.java:25
// WebWolf WebSecurityConfig.java
auth.requestMatchers(
        HttpMethod.GET,
        "/fileupload/**",
        "/files/**",      // ← 匿名可 GET
        "/landing/**",
        "/PasswordReset/**")
    .permitAll();
// MvcConfiguration.java:25
registry.addResourceHandler("/files/**").addResourceLocations("file:///" + fileLocation + "/");
  • 利用: 未登录 GET http://127.0.0.1:9090/WebWolf/files/{任意用户名}/{文件名} 直接下载任意用户上传的文件(WebWolf 文件目录 fileLocation 按用户名分子目录,但下载端点不校验归属)。
  • 影响: 跨用户敏感文件泄露(课程中常存放 flag / 私钥 / 凭据)。

🔴 2.1.2 路径穿越任意文件写入(需登录)

  • 文件: src/main/java/org/owasp/webgoat/webwolf/FileServer.java:75
var destinationDir = new File(fileLocation, username);          // fileLocation=/tmp/webwolf-fileserver
var destinationFile = destinationDir.toPath().resolve(multipartFile.getOriginalFilename());
Files.copy(is, destinationFile);                                 // 原始文件名直接 resolve,无净化
  • 利用: 登录后 POST /WebWolf/fileupload,文件名 ../../../../etc/cron.d/pwn(三级 .. 即可从 /tmp/webwolf-fileserver/{user} 逃逸到 / 下)→ 写入任意路径(父目录存在即可,如覆盖应用可读写的配置文件、写入 crontab/SSH authorized_keys 等,受运行用户权限约束)。
  • 影响: 若 WebGoat/WebWolf 以较高权限运行 → 本地任意文件写 → 潜在 RCE;最低限度也可跨用户覆盖文件。
  • 是否故意: 否·框架缺陷(WebSecurityConfig 的 GET 放行 + MvcConfiguration 静态映射 + FileServer 无净化,三层叠加)。

2.2 🔴 匿名发信 + 存储型 XSS — WebGoat 邮箱(框架缺陷)

🔴 2.2.1 POST /mail 匿名注入 + th:utext 存储型 XSS

  • 文件: src/main/java/org/owasp/webgoat/container/WebSecurityConfig.java:49-50、container/mailbox/MailboxController.java:58-65、resources/webgoat/templates/mailbox.html:142
// WebSecurityConfig.java —— 为课程"发信"开放,但未校验发件人/收件人
.requestMatchers(HttpMethod.POST, "/mail").permitAll()

// MailboxController.java —— Email 全部字段(recipient/sender/title/contents)由客户端提交
@PostMapping("/mail")
@ResponseStatus(HttpStatus.CREATED)
public void sendEmail(@RequestBody Email email) {
  email.setTime(LocalDateTime.now());
  mailboxRepository.save(email);          // 未校验 recipient 归属、未校验 contents
}
<!-- mailbox.html:142 —— contents 未经转义直接输出 -->
<pre th:utext="${mail.contents}">contents</pre>
  • 利用(未认证):
    1. POST /WebGoat/mail,body {"recipient":"victim","sender":"attacker","title":"hi","contents":"<script>fetch('/WebGoat/WebWolf?x='+document.cookie)</script>"}
    2. 受害用户打开邮箱 → th:utext 原样渲染 <script> → XSS 在受害者 WebGoat 会话中执行,窃取 JSESSIONID / 执行任意操作。
  • 影响: 未认证存储型 XSS,跨用户投毒;配合邮箱会话可完全接管受害者 WebGoat 会话。
  • 是否故意: 否·框架缺陷(POST /mail 放行是课程需要,但 Email 对象缺少收件人校验、contents 未编码,属实现缺陷)。

🟠 2.2.2 DELETE /mail 全局清空(越权)

  • 文件: MailboxController.java:67-71
@DeleteMapping("/mail")
@ResponseStatus(HttpStatus.ACCEPTED)
public void deleteAllMail() {
  mailboxRepository.deleteAll();          // 无认证、无归属校验,清空全部用户邮件
}
  • 利用: 未登录 DELETE /WebGoat/mail → 所有用户的邮件被删除(含课程密码重置邮件)。
  • 影响: 全局数据破坏(DoS);@DeleteMapping 也未在 /mail 的 permitAll 列表内,但 CSRF 全局关闭 + 无方法级鉴权(.anyRequest().authenticated() 已覆盖,需确认方法级)——至少任意已登录用户可越权清空他人邮件。
  • 是否故意: 否·框架缺陷。

2.3 🟠 未授权访问 — Actuator 配置泄露(框架缺陷)

  • 文件: src/main/resources/application-webgoat.properties:75-80、src/main/java/org/owasp/webgoat/container/WebSecurityConfig.java:44
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=env, health,configprops
spring.security.oauth2.client.registration.github.client-id=${WEBGOAT_OAUTH_CLIENTID:dummy}
spring.security.oauth2.client.registration.github.client-secret=${WEBGOAT_OAUTH_CLIENTSECRET:dummy}
server.ssl.key-store-password=${WEBGOAT_KEYSTORE_PASSWORD:password}
.requestMatchers(..., "/actuator/**").permitAll()   // 未认证
  • 利用: 未登录 GET /WebGoat/actuator/env、/WebGoat/actuator/configprops、/WebGoat/actuator/health:
    • configprops 暴露全部 @ConfigurationProperties 绑定值(数据源 URL、WebGoat/WebWolf 路径、webgoat.* 全部配置);
    • env 暴露环境变量/属性源(Spring Boot 会对名称含 password/secret/key 的值打码,但非敏感配置、服务地址、端口、数据源结构、OAuth client-id 等全部可见);
    • health show-details=always 暴露健康检查明细(DB 状态等)。
  • 影响: 未认证应用配置信息泄露,为后续攻击提供侦察面(内网地址、依赖版本、凭据默认值线索)。
  • 是否故意: 否·框架缺陷(/actuator/** permitAll 放行过度)。

2.4 🟠 存储型 XSS — WebWolf requests 页面(框架缺陷)

  • 文件: src/main/resources/webwolf/templates/requests.html:39,47、src/main/java/org/owasp/webgoat/webwolf/requests/LandingPage.java、WebWolfTraceRepository.java
<!-- requests.html:39 —— 请求路径未转义 -->
<span th:utext="${trace.date}"/> | <span th:utext="${trace.path}"/>
<!-- requests.html:47 —— 请求完整记录(含请求头)未转义,Jackson 默认不转义 HTML -->
<pre th:utext="${trace.json}"/>
  • 利用:
    1. 路径: GET /WebWolf/landing/... 为 permitAll(WebSecurityConfig.java:37-44),路径会被记录;Tomcat 默认拒绝原始 </>,但 %3C 编码路径在部分中间件/编码形态下可触发。
    2. 请求头(更直接): 未登录发送 GET /WebWolf/landing/x,附带请求头 X-Inject: <script>alert(document.cookie)</script> → 该请求被 WebWolfTraceRepository 记录 → trace.json 经 Jackson 序列化,Jackson 默认不转义 </>/&,<script> 以字面形式进入 JSON → th:utext 原样输出 → 所有访问 /WebWolf/requests 的用户触发存储型 XSS。
  • 影响: 跨用户存储型 XSS(WebWolf 会话 Cookie 名 WEBWOLFSESSION);可进一步与 WebWolf 内功能联动。
  • 是否故意: 否·框架缺陷(th:utext + 未做输出的 HTML 编码)。

2.5 🟠 硬编码管理员账号(重启后重置)— 框架缺陷

  • 文件: src/main/java/org/owasp/webgoat/container/users/DefaultUserInitializer.java:25-27,35-49
private static final String ADMIN_USERNAME = "webgoat-admin";
private static final String DEFAULT_USER_USERNAME = "webgoat-user";
private static final String DEFAULT_PASSWORD = "webgoat";

// 每次启动都重新断言 admin 口令 —— 即使管理员中途改密,重启后仍被还原
userRepository.save(new WebGoatUser(ADMIN_USERNAME, DEFAULT_PASSWORD, WebGoatUser.ROLE_ADMIN));
  • 配套: container/WebSecurityConfig.java:96-98 使用 NoOpPasswordEncoder(明文存储密码);/service/admin/** 由 WEBGOAT_ADMIN 角色保护(管控正确,但口令本身公开且可预测)。
  • 影响: 任何知道默认口令的人可用 webgoat-admin/webgoat 登录管理员后台(AdminController,含重置任意用户密码、查看用户列表等);管理员改密无效,重启后口令还原。默认普通用户 webgoat-user/webgoat 同理。
  • 是否故意: 否·框架缺陷("可预测凭据 + 明文存储 + 重启还原"三重组合;作为教学工具可接受,部署到真实环境即高危)。

2.6 🟠 越权 — 邮箱清理 / OAuth 口令覆盖(框架缺陷)

🟠 2.6.1 OAuth 登录覆盖已有用户口令(账号 DoS / 潜在接管)

  • 文件: src/main/java/org/owasp/webgoat/container/users/RegistrationController.java:61-65、UserService.java:44-55
// RegistrationController.java:65 —— OAuth 登录路径直接 addUser,未走 UserValidator 查重
@GetMapping("/login-oauth.mvc")
public String loginOauth(Authentication authentication) {
  userService.addUser(authentication.getName(), UUID.randomUUID().toString());
  ...
}
// UserService.java:47 —— 无条件 save,覆盖同名已存在用户的口令
var webGoatUser = userRepository.save(new WebGoatUser(username, password));
  • 利用: 若某用户的目标 WebGoat 用户名与其 OAuth 身份名(如 GitHub 邮箱/昵称)一致,攻击者注册同名 OAuth 账号登录 → addUser 将目标用户口令覆盖为随机 UUID(普通注册路径 RegistrationController:55 有 UserValidator 查重拦截,但 OAuth 路径无此校验)。
  • 影响: 已有用户口令被覆盖(账号 DoS);被覆盖后攻击者可能以该 OAuth 身份继续访问其数据。UserService.java:78 的 CREATE SCHEMA "<username>" SQL 拼接由 UserForm 的 @Pattern("[a-z0-9-]*") 约束,风险被控。
  • 是否故意: 否·框架缺陷(两条注册路径校验不一致)。

2.7 🔴 反序列化 / RCE

🔴 2.7.1 XStream 反序列化 RCE(CVE-2013-7285,版本为真实依赖风险)

  • 文件: src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLesson.java:26-42、pom.xml:111,140-142
XStream xstream = new XStream();
xstream.setClassLoader(Contact.class.getClassLoader());
xstream.alias("contact", ContactImpl.class);
xstream.ignoreUnknownElements();
...
contact = (Contact) xstream.fromXML(payload);     // 未配置安全白名单
<xstream.version>1.4.5</xstream.version>   <!-- 1.4.5 < 1.4.7,未含默认反序列化安全框架 -->
  • 利用: 课程环境为演示样例;若该组件被用于真实解析外部 XML,1.4.5 版本可被 ysoserial 式 gadget(如 EventHandler/PriorityQueue/ImageIO$ContainsFilter 等)触发 RCE。
  • 影响: 远程代码执行(取决于 classpath gadget)。注意: commons-collections 3.2.1 仅为 pom 属性,经典 ysoserial 链不在 classpath,实际利用受限,但版本本身是真实 CVE 载体。
  • 是否故意: 是·课程(依赖版本为真实未修复风险)。

🟠 2.7.2 ObjectInputStream 无白名单反序列化

  • 文件: src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserializationTask.java:42-47、src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java:46-67
// InsecureDeserializationTask.java
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)));
Object o = ois.readObject();                 // readObject 先于 instanceof 校验执行
if (!(o instanceof VulnerableTaskHolder)) { ... }

// VulnerableTaskHolder.java —— 恶意 readObject 触发命令执行(受限)
private void readObject(ObjectInputStream stream) throws Exception {
  ...
  if ((taskAction.startsWith("sleep") || taskAction.startsWith("ping")) && taskAction.length() < 22) {
    Process p = Runtime.getRuntime().exec(taskAction);   // Runtime.exec(全库唯一非测试 RCE 点)
  }
}
  • 利用: 构造序列化 payload(taskAction 以 sleep/ping 前缀开头、长度 <22)→ 服务端 readObject 执行受限系统命令。
  • 影响: 受限命令执行(长度/前缀限制)。属课程演示,但 readObject 先执行后校验是无白名单反序列化的典型反面教材。
  • 是否故意: 是·课程。

🟠 2.7.3 不安全反序列化工具类

  • 文件: src/main/java/org/owasp/webgoat/lessons/deserialization/SerializationHelper.java:20-26 —— 通用 ObjectOutputStream/ObjectInputStream 封装,无类型白名单。
  • 是否故意: 是·课程。

2.8 🟠 XXE(课程)

  • 文件: src/main/java/org/owasp/webgoat/lessons/xxe/CommentsCache.java:68-82
protected Comment parseXml(String xml, boolean securityEnabled) {
  var xif = XMLInputFactory.newInstance();
  if (securityEnabled) {                       // 安全开关默认 false,且所有调用方传 false
    xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");     // 仅在此才禁用外部 DTD
    xif.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
  }
  var xsr = xif.createXMLStreamReader(new StringReader(xml));
  ...
}
  • 调用方: SimpleXXE.java:54、ContentTypeAssignment.java:60、BlindSendFileAssignment.java:79 均传 false → 外部 DTD/实体始终可用。
  • 利用: XML 中定义 <!ENTITY xxe SYSTEM "file:///etc/passwd"> → 任意文件读取;SYSTEM "http://..." → SSRF;结合 OOB(外部 DTD 外带)实现盲注数据外带。
  • 影响: 任意文件读取 / SSRF / 数据外带(课程层)。
  • 是否故意: 是·课程。

2.9 🔴 SQL 注入(课程)

以下均为课程故意样例,共同特征:字符串拼接 SQL + 无参数化。按子模块汇总:

文件 位置 注入点
lessons/sqlinjection/introduction/SqlInjectionLesson2.java :48-49 直接执行用户提交的 query
.../SqlInjectionLesson3.java :45-47 直接执行用户 query(UPDATE/DELETE)
.../SqlInjectionLesson4.java :44-46 直接执行用户 query
.../SqlInjectionLesson5a.java :47-48 last_name = ' + accountName 拼接
.../SqlInjectionLesson5b.java :45-49 PreparedStatement 但 userid = + accountName 拼接(参数化失效)
.../SqlInjectionLesson8.java :49-54 last_name = ' + name 拼接(二次注入写入 access_log)
.../SqlInjectionLesson9.java :50-53 同上,DB 内容再进查询(二次注入)
.../SqlInjectionLesson10.java :49,56 action LIKE '% + action 拼接 + 堆叠查询(DROP 表)
lessons/sqlinjection/advanced/SqlInjectionLesson6a.java :54,69-72 last_name = ' + accountName 拼接
.../SqlInjectionChallenge.java :59-62 多参数拼接
lessons/sqlinjection/mitigation/Servers.java :50-53 ORDER BY + 标识符拼接(盲注)
lessons/jwt/claimmisuse/JWTHeaderKIDEndpoint.java :74-76 WHERE id = ' + kid 拼接(JWT kid 头 → SQLi)
lessons/challenges/challenge5/Assignment5.java :44-49 userid/columns 双参数拼接
  • 示例(JWTHeaderKIDEndpoint.java:74-76):
ResultSet rs = connection.createStatement().executeQuery(
    "SELECT key FROM jwt_keys WHERE id = '" + kid + "'");   // kid 来自 JWT 头
  • 影响: 任意 SQL 执行、拖取用户表/密码、认证绕过、篡改数据。
  • 框架层相关: UserService.java:78 CREATE SCHEMA "<username>" 拼接已由用户名正则 [a-z0-9-]* 约束,风险被控(非课程,但属正向加固示例)。
  • 是否故意: 是·课程。

2.10 🟠 路径穿越(上传,课程)

文件 位置 漏洞
lessons/pathtraversal/ProfileUploadBase.java :48-53 new File(uploadDirectory, fullName),文件名可含 ../ 穿越课程目录
.../ProfileUploadFix.java :43 仅 replace("../","") 一次 → ....// 绕过
.../ProfileUploadRetrieval.java :93-113 用 getQueryString() 原文(含 %2e%2e%2f)而非解码后的 getParameter() 校验 → URL 编码绕过读取 path-traversal-secret.jpg
.../ProfileZipSlip.java :75-82 new File(tmpZipDirectory, e.getName()) 解压条目名未校验 → Zip Slip
  • 影响: 课程目录内任意文件读写、读取隐藏 secret 图片。
  • 是否故意: 是·课程(getQueryString vs getParameter 是经典双解码绕过教学点)。

2.11 🟠 硬编码密钥 / 账号密码

🟠 2.11.1 JWT 签名密钥硬编码(课程)

  • 文件: src/main/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpoint.java:45-46,73,91
public static final String PASSWORD = "bm5nhSkxCXZkKRy4";
private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4";   // HS512 签名密钥,源码可见
Jwts.builder().signWith(SignatureAlgorithm.HS512, JWT_PASSWORD) ...
Jwts.parser().setSigningKey(JWT_PASSWORD).parse(...)
  • 利用: 读取源码密钥 → 自行签发任意用户身份/admin 的 JWT。
  • 是否故意: 是·课程(另有 JWTHeaderKIDEndpoint 的 kid 注入点做引导)。

🟠 2.11.2 课程内其余硬编码凭据

文件 位置 硬编码内容
lessons/spoofcookie/SpoofCookieAssignment.java — 明文账号 webgoat/webgoat、admin/admin、tom/apasswordfortom + 可逆 Cookie 加密
lessons/authbypass/AccountVerificationHelper.java — 安全问题答案 Dr. Watson/Baker Street,userId 1223445
lessons/missingac/MissingFunctionACUsers.java — 固定加盐 DeliberatelyInsecure1234 + 可伪造 Cookie 会话
lessons/challenges/challenge7/Assignment7.java :36 管理员密码链接 375afe1104f4a487a73823c50a9292a2 + new Random(seeded) 可预测
lessons/challenges/SolutionConstants.java :10 PASSWORD="!!webgoat_admin_1234!!",PINCODE 藏于 PNG 字节
lessons/insecurelogin/InsecureLoginTask.java :21 CaptainJack/BlackPearl 明文登录
application-webgoat.properties :14,79-80 SSL 密钥库口令默认 password;OAuth client-secret 默认 dummy(框架默认值)
  • 影响: 伪造令牌、绕过认证、直接登录/接管账号。
  • 是否故意: 是·课程(配置文件默认值为框架层,多为占位符)。

2.12 🟠 XSS(课程)

文件 位置 类型
lessons/xss/CrossSiteScriptingLesson5a.java :63-65 反射型:cart.append("<p>... " + field1 + ...) 未编码
lessons/xss/stored/StoredXssComments.java :40,73-91 存储型:评论区评论内容原样存储/回显
lessons/xss/stored/stored-xss.html 模板 th:utext 存储型评论未转义输出
  • 是否故意: 是·课程。

2.13 🟡 SSRF(课程)

🟡 2.13.1 ifconfig.pro SSRF(受限)

  • 文件: src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask2.java:34
if (url.matches("http://ifconfig\\.pro")) { ... }   // String.matches() 全串匹配 → 仅允许该单一主机
  • 分析: matches() 隐含首尾锚定,http://ifconfig.pro@127.0.0.1、http://ifconfig.pro.evil.com 等均不通过。SSRF 被严格限制在单主机,仅可获取服务器公网 IP。
  • 影响: 受限信息泄露(公网 IP)。
  • 是否故意: 是·课程(安全写法 matches() 反而成为教学点:用白名单 URL 匹配防御 SSRF 的可行性边界)。

🟡 2.13.2 JWT jku 头 SSRF

  • 文件: src/main/java/org/owasp/webgoat/lessons/jwt/claimmisuse/JWTHeaderJKUEndpoint.java:55-57
var jku = decodedJWT.getHeaderClaim("jku");
var jwkProvider = new JwkProviderBuilder(new URL(jku.asString())).build();   // 攻击者控制 URL
  • 利用: 篡改 JWT 头 jku 指向内网/任意地址 → 服务端拉取 JWKS(URL 类发起请求)→ SSRF(内网端口探测、读取响应差异)。
  • 是否故意: 是·课程。

🟡 2.13.3 XXE 侧 SSRF

  • 见 2.8:CommentsCache 外部实体 SYSTEM "http://内网地址" 即 SSRF。
  • 是否故意: 是·课程。

2.14 🟠 越权 / 认证绕过(课程)

文件 位置 漏洞
lessons/idor/* — IDOR:tom/cat、bill/buffalo 等固定 userId 2342384/2342388,篡改 id 越权读取/修改他人资料
lessons/authbypass/* — 认证绕过:硬编码安全问题答案(见 2.11.2)
lessons/challenges/challenge8/Assignment8.java :44-55 动词型认证绕过:仅校验 GET,X-HTTP-Method-Override/POST 即可绕过后端只允许 GET 的检查
lessons/missingac/MissingFunctionACUsers.java — Mass Assignment:提交 {"admin": true} 提权;Cookie 加盐固定可伪造
lessons/spoofcookie/SpoofCookieAssignment.java — Cookie 可逆编码,篡改即变身份
lessons/hijacksession/cas/HijackSessionAuthenticationProvider.java :24-30 可预测会话 ID:++id + "-" + epochMilli(计数器 + 毫秒时间戳)
  • 影响: 查看/篡改任意用户数据、垂直提权为 admin、会话预测劫持。
  • 是否故意: 是·课程。

2.15 🟡 开放重定向(课程)

  • 文件: src/main/java/org/owasp/webgoat/lessons/openredirect/OpenRedirectRealRedirect.java:18-22
@GetMapping("/openredirect/real")
public ModelAndView real(@RequestParam("url") String url) {
  return new ModelAndView("redirect:" + url);    // 任意 302 跳转
}
  • 影响: 钓鱼跳转(配合伪造登录页可窃取凭据)。
  • 是否故意: 是·课程。

2.16 🟡 其余框架层弱项(真实,影响有限)

项 位置 说明
CSRF 全局关闭 container/WebSecurityConfig.java:70、webwolf/WebSecurityConfig.java:47 .csrf(csrf -> csrf.disable()) → 任何有状态操作可被跨站伪造(与 XSS 叠加放大)
安全响应头关闭 container/WebSecurityConfig.java:71 .headers(headers -> headers.disable()) → 无 CSP/X-Frame-Options,配合 XSS 更易利用
明文密码存储 container/WebSecurityConfig.java:96-98、webwolf/WebSecurityConfig.java:84-87 NoOpPasswordEncoder 明文存储,配合硬编码账号(2.5)直接可读
堆栈回显 application-webgoat.properties:1、application-webwolf.properties:1 spring.web.error.include-stacktrace=always → 错误信息泄露内部路径/类名
管理员后台口令明文回显 container/users/AdminController.java:159-169 重置密码后临时口令在响应体明文返回(仅 admin 可触发,风险可控)
  • 是否故意: 否·框架缺陷(多数为教学工具设计取舍,但部署即生效)。

三、攻击面汇总(框架 vs 课程)

攻击面 是否需登录 真实/课程 一句话结论
GET /WebWolf/files/** 任意文件下载 否 真实 匿名跨用户读文件
POST /WebWolf/fileupload 路径穿越写文件 是 真实 任意路径文件写
POST /WebGoat/mail + 邮箱 XSS 否 真实 匿名存储型 XSS → 会话窃取
DELETE /WebGoat/mail 否* 真实 全局邮件清空
GET /WebGoat/actuator/env|configprops|health 否 真实 未授权配置泄露
GET /WebWolf/landing/** 请求头 XSS 否 真实 存储型 XSS 全用户触发
webgoat-admin/webgoat 否 真实 硬编码管理员口令,重启还原
/login-oauth.mvc 覆盖口令 是 真实 OAuth 同名账号覆盖目标口令
lessons/* 全部漏洞 是 课程 教学样例,见 §2.7–2.15

⚠️ 特别说明:WebGoat 默认监听 127.0.0.1、WebWolf 默认监听 127.0.0.1:9090(application-*.properties server.address)。上述真实缺陷在本机/教学环境危害可控;一旦对外网部署(WEBGOAT_HOST=0.0.0.0)或与真实数据联动,框架缺陷即为最高优先级修复项。


四、修复建议(防御视角)

  1. WebWolf 文件服务:GET /files/** 改为要求登录并校验目录归属(authentication.getName() 与路径用户一致);FileServer 对 getOriginalFilename() 做 Path.normalize() + 校验 startsWith(destinationDir) + 拒绝 ..,或改用随机文件名存储。
  2. 邮箱接口:POST /mail 校验 recipient 存在且与发送会话相关;deleteAllMail 改为按当前用户删除;模板将 th:utext 改为 th:text(对 contents 做 HTML 编码)。
  3. Actuator:移除 /actuator/** 的 permitAll,仅暴露 health 并收紧 show-details;env/configprops 要求认证;敏感值用环境变量注入而非默认占位。
  4. requests 页:th:utext 全部改 th:text;对 trace.json 中的请求头做 HTML 转义。
  5. 硬编码账号:webgoat-admin 口令改为首次启动随机生成并持久化;移除每次重启的口令重断言;密码改用 BCryptPasswordEncoder。
  6. 注册一致性:OAuth 登录路径复用 UserValidator 的查重逻辑,禁止覆盖已有用户名。
  7. 反序列化:升级 xstream ≥1.4.7(配置 XStream.setupDefaultSecurity + 白名单);ObjectInputStream 改用 ObjectInputFilter/白名单;VulnerableTaskHolder 的 readObject 禁止执行命令。
  8. XXE:所有 XML 解析默认禁用外部 DTD/实体(securityEnabled 默认 true),开启 ACCESS_EXTERNAL_DTD 为空、禁止 DOCTYPE。
  9. SQL 注入:课程外层若复用到真实数据,全部改参数化查询;JWTHeaderKIDEndpoint 的 kid 改为 PreparedStatement。
  10. XSS:所有 th:utext 改为 th:text 或对输出做 HTML 编码;恢复安全响应头(CSP、X-Frame-Options)。
  11. CSRF:恢复 CSRF 防护或使用 SameSite=Lax + 双提交 Token(至少保护改密/重置等高危操作)。
  12. 会话:HijackSessionAuthenticationProvider 的会话 ID 改用 CSPRNG(SecureRandom);webgoat.user.directory 敏感文件避免落盘明文。

五、审计范围与方法

  • 全量阅读 webgoat-container 框架层(安全配置、用户体系、邮箱、Actuator)、webwolf(文件服务、请求记录、静态映射)与 lessons/* 各课程模块源码;
  • 全站 grep 危险 API:Runtime.exec、ProcessBuilder、XStream.fromXML、ObjectInputStream.readObject、URL、openStream、executeQuery、Statement.execute、createStatement、th:utext、\.html\(、redirect:;
  • 全站 grep 硬编码凭据模式:PASSWORD、secret、key、admin、default、password=;
  • 逐一验证每个框架层缺陷的权限配置链(WebSecurityConfig → Controller → Repository → 模板),并对 SSRFTask2.matches()、Jackson 默认 HTML 转义行为、Tomcat 路径字符限制等做了代码级确认;
  • 参考文档: OWASP Top 10 / OWASP WebGoat 源码 c596b729 (2026-08)。
正文完
 0