abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · prometheus-unix-socket-dial
类别: SSRF 可达性: 远程
Prometheus v3.15.0 (5241a27) - CNCF / Prometheus
v3.15.0 新增了 Unix 域套接字抓取(#12024 / #18091)。该路径是一个目标标签 __unix_socket__,而非操作员允许列表。http_sd 和 file_sd 会原样复制该标签。PopulateLabels 从不校验它。随后 newUnixSocketScrapeClient 调用 DialContext(ctx, "unix", socketPath),没有 filepath.Clean,没有允许列表,也不拒绝 ../ 或 Linux 抽象 @ 名称。
TCP 抓取无法做到这一点。 CheckTargetAddress 仍会丢弃包含 / 的 __address__ 值,因此 unix:///var/run/docker.sock 作为地址会被拒绝。新标签才是漏洞所在。
默认配置不会设置该标签。对 Prometheus 的未认证 HTTP 无法添加作业。这受 SD 门控。
| ID | 暂无 CVE |
| 类别 | SSRF(来自 SD 标签的未净化 unix Dial) |
| 可达性 | 远程(受 SD 门控:http_sd / file_sd 的写入者) |
| CWE | CWE-918、CWE-22 |
| CVSS | 高危:8.6 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N |
| 产品 | Prometheus |
| 受影响版本 | v3.15.0(5241a27fe3c6983549fccc32f6e65917408c63cd),镜像 prom/prometheus:v3.15.0 |
| 认证 | 受 SD 门控:http_sd / file_sd 标签的写入者(或将不可信元数据复制到 __unix_socket__ 的 relabel) |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
控制 http_sd JSON(或可写的 file_sd)就足够了。SD URL 是操作员配置。遗留问题是组 labels 可以设置 __unix_socket__,而 Prometheus 会对其发起 Dial。
| 权限 | 方法 / 汇聚点 | 实验验证或推断 |
|---|---|---|
| 连接 Prometheus UID 可打开的主机 unix 套接字 | 从 __unix_socket__ 经 clientForTarget -> DialContext(ctx, "unix", socketPath) | 实验验证。来自 http_sd 的路径 /sockets/jail/../oracle.sock;抓取健康状态 up |
在该路径中跟随 ../ | 无 filepath.Clean / 不拒绝 .. | 实验验证。内核将遍历解析为 /sockets/oracle.sock |
| 拨号 Linux 抽象套接字 | 对 @name 的相同 Dial | 实验验证。__unix_socket__=@prom-lab-oracle;抓取健康状态 up |
| 以 Prometheus UID 在该套接字上发起 HTTP GET | 抓取为 GET;__metrics_path__ 是请求路径 | 实验验证。GET /fs-traversal 和 /abstract;User-Agent Prometheus/;lab_witness 被摄取 |
| 访问 TCP 抓取无法命名的套接字 | CheckTargetAddress 拒绝 __address__ 中的 / | 实验验证。unix:///var/run/docker.sock 作为 __address__ 记录为 is not a valid hostname;不是活动目标;prometheus_target_sync_failed_total=1 |
| 若这些套接字在范围内,GET Docker Engine / kubelet HTTP API | __unix_socket__=/var/run/docker.sock 加上 Docker API 路径 | 推断。相同的未净化 Dial。本实验未挂载真实引擎套接字。JSON API 通常无法通过 exposition 解析,因此高危在于连接/GET,而非对 Docker JSON 的 TSDB 窃取 |
| 修改 Docker(创建容器、写入) | 抓取动词 | 已排除。抓取仅限 GET |
| 通过未认证 Prometheus HTTP 添加抓取作业 | /-/reload、admin API | 已排除。两个标志默认关闭;reload 无请求体 |
| 在默认示例配置上使用此漏洞 | __unix_socket__ 未设置;示例通过 TCP 抓取 localhost:9090 | 已排除。树内 k8s/consul/docker SD 仅发出 __meta_*;这些前缀在 relabel 后被删除 |
厂商安全模型已允许 SD 选择 TCP 抓取目标。新的原语是 __address__ 无法命名的宿主 IPC。
在 3.15 针对 UDS 抓取的 FEATURE 行之后,我固定了 prometheus/prometheus v3.15.0。此固定版本上的默认 OSS 关闭了 admin API、lifecycle HTTP、remote-write receiver 和 OTLP receiver。PopulateDiscoveredLabels 复制每个 http_sd 组标签。__unix_socket__ 不是 __meta_*,因此它在元数据清除后仍存活。PopulateLabels 仅检查 __address__。
func (sp *scrapePool) clientForTarget(t *Target) *http.Client {
socketPath := t.labels.Get(UnixSocketLabel)
if socketPath == "" {
return sp.client
}
client, err := newUnixSocketScrapeClient(socketPath, ...)
func newUnixSocketScrapeClient(socketPath string, ...) (*http.Client, error) {
optFuncs = append([]config_util.HTTPClientOption{config_util.WithDialContextFunc(
func(ctx context.Context, _, _ string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "unix", socketPath)
},
)}, optFuncs...)
CheckTargetAddress 仍拒绝地址中的 /。URL() 从 __scheme__ / __address__ / __metrics_path__ 保留 scheme/host/path;套接字仅用于拨号。
已记录的误判:将其评为模型内 NONE,因为 SD 已选择 TCP 目标(新原语是宿主 IPC);将 unix:///var/run/docker.sock 作为 __address__ 视为漏洞(它被拒绝);声称默认示例配置就是此遗留问题。表演成分:反向 shell。预言机是 SD JSON 所命名套接字上的抓取健康状态 up。
python3 prometheus-unix-socket-dial-Abraxas-Labs.py
或
cd lab
./run.sh
prom/prometheus:v3.15.0 与一个 Python sidecar 共享 netns。Sidecar 在 127.0.0.1:8080/targets.json 提供 http_sd,并提供两个 unix HTTP 预言机:文件系统 /sockets/oracle.sock 和抽象 @prom-lab-oracle。Prometheus 发布在 127.0.0.1:19390。Admin API 和 lifecycle 保持关闭。
SUCCESS prometheus-unix-socket-dial sd=http_sd fs-traversal=yes abstract=yes tcp-slash-rejected=yes how=sd-labels PROMETHEUS-UNIX-SOCKET-DIAL-WITNESS
IOC:scrapeUrl=http://localhost:1/fs-traversal 和 /abstract,两者健康状态均为 up。TCP 斜杠从未成为活动目标。
在 __unix_socket__ 成为经过净化的绝对文件系统路径之前,不要从 SD 对其发起 Dial。拒绝空值、NUL、Linux 抽象 @ 名称、相对路径,以及 filepath.Clean 后的任何 ..。来自抓取 YAML 的前缀允许列表更强。除非该标签来自操作员配置,否则从 PopulateDiscoveredLabels 中丢弃它,也能关闭 SD 注入。
5241a27fe3c6983549fccc32f6e65917408c63cd)scrape/scrape.go · scrape/target.go · config/config.goGNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。无担保。