基于微步在线威胁情报的公网 IP 攻击迹象监测:threatbook_query 脚本全解析与 BruceSec 平台整合实践
摘要
在公网资产安全监测中,仅靠主动端口扫描往往难以穿透严格的边界防火墙;此时,借助第三方威胁情报(Threat Intelligence)对公网 IP 的历史行为进行被动研判,是一种高效、低噪的补充手段。本文以实际落地的 threatbook_query.py 脚本为线索,完整介绍其设计背景、方案选型、脚本架构、逐函数代码解析、部署使用方法,以及如何将其注册进 BruceSec 安全平台(tools yaml + ApplyConfig 热重载 + MCP 管理页)实现一键调用。文中所涉 IP 判定、接口返回、平台热重载结果均来自本机实测输出,未做任何虚构。
脱敏声明:本文所有涉及真实资产的公网 IP 已按 RFC 5737 替换为测试保留地址(203.0.113.x),地理位置、运营商、ASN 已泛化脱敏;文中不包含任何 API Key 明文;相关数据仅用于技术示例。
一、项目背景:公网 IP 攻击迹象监测与 nmap 的"严防火墙"困境
单位公网出口长期暴露在互联网上,安全运维团队需要持续监测公网 IP 是否存在被攻击、被利用的迹象。传统做法是使用 nmap 等工具对目标 IP 做端口扫描与服务识别,但在实际执行中遇到了明显的瓶颈:
text
=== 扫描时间: 2026-08-14 18:19:10 ===
########## 目标 1: 203.0.113.11 ##########
Starting Nmap 7.95 ( https://nmap.org ) at 2026-08-14 18:18 CST
Nmap scan report for 203.0.113.11
Host is up.
All 100 scanned ports on 203.0.113.11 are in ignored states.
Not shown: 100 filtered tcp ports (no-response)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 34.26 seconds
########## 目标 2: 203.0.113.12 ##########
Starting Nmap 7.95 ( https://nmap.org ) at 2026-08-14 18:18 CST
Nmap scan report for 203.0.113.12
Host is up (0.040s latency).
Not shown: 90 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
53/tcp filtered domain
80/tcp filtered http
135/tcp filtered msrpc
139/tcp filtered netbios-ssn
443/tcp filtered https
445/tcp filtered microsoft-ds
3128/tcp filtered squid-http
5800/tcp filtered vnc-http
5900/tcp filtered vnc
8080/tcp filtered http-proxy
Nmap done: 1 IP address (1 host up) scanned in 16.56 seconds
从扫描结果可以清晰看到两个问题:
- 端口大面积 filtered :目标 1(203.0.113.11)全部 100 个扫描端口均处于
filtered(无响应)状态,说明边界防火墙对探测流量做了严格过滤,nmap 几乎拿不到任何服务信息;目标 2(203.0.113.12)虽然有 10 个端口被列出,但全部为filtered,无法确认其真实服务。 - 主动扫描的先天局限:防火墙过滤后,主动探测既得不到服务指纹,也观察不到目标 IP 的"历史行为"。攻击迹象往往体现在历史威胁标签(如僵尸网络、扫描器、C2、被攻陷等),而这些信息只有威胁情报平台才有积累。
因此,团队决定引入微步在线(ThreatBook)威胁情报 API,通过 IP 情报查询对监测名单中的公网 IP 做被动研判,形成"情报判定 + nmap 对照"的双通道监测模式。
二、方案选型:为什么选择微步 v3/ip/query
2.1 选型背景
威胁情报服务商众多,本项目选型时主要关注四点:威胁标签的丰富度、接口返回字段的完整度、是否支持国内 IP 的深度覆盖、以及接入成本(Key 申请与绑定流程)。微步在线在国内威胁情报领域积累较深,对国内运营商 IP(ISP 已脱敏、ISP 已脱敏等)的标签覆盖较好,且提供免费额度便于验证,因此进入候选。
2.2 v3/ip/query 与 ip_reputation 的对比考量
在微步在线 API 体系中,IP 情报查询存在不同的接口形态,本项目最终选定 /v3/ip/query,主要对比考量如下:
| 对比维度 | v3/ip/query(本项目采用) | 场景化信誉查询(ip_reputation 类接口) |
|---|---|---|
| 返回内容 | 全维度情报:judgments 恶意判定、basic 基础信息(位置/运营商)、asn、intelligences 情报标签及置信度 |
面向特定场景的信誉评分与结论,字段相对聚焦 |
| 与监测需求的匹配度 | 字段与研判流程一一对应,可直接支撑"标签 + 置信度 + 发现时间"的完整证据链 | 更偏单值评分,历史标签细节较少 |
| 实现复杂度 | GET 请求 + apikey 即可,纯标准库可完成 | 具体参数与返回结构以官方文档为准 |
说明:具体接口的请求参数与返回字段差异请以微步在线官方 API 文档为准;本文只陈述本项目脚本实际使用
v3/ip/query的事实与收益。
2.3 Key 绑定出口 IP(关键约束)
微步在线对 API Key 有出口 IP 绑定 机制:在微步控制台申请 Key 后,需要在控制台将该 Key 绑定到实际发起请求的服务器出口 IP。若请求源 IP 与控制台绑定的 IP 不一致,接口会返回 Invalid Access IP 错误。这是接入过程中最易踩坑的一步,也是本脚本部署文档中的首要注意事项(详见 yaml 注册文件中的说明:"需在微步控制台绑定请求出口 IP,否则报 Invalid Access IP")。
三、脚本架构与数据流
threatbook_query.py 是一个无第三方依赖的纯 Python 标准库脚本(仅使用 json / os / sys / urllib.request / urllib.parse),整体架构清晰,共四个函数:
load_key():读取 API Key(从同目录的threatbook_api_key文件,权限 chmod 600)query(key, ip):调用微步v3/ip/query接口,返回 JSONsummarize(ip, data):将原始返回压缩为研判所需的摘要结构main():命令行入口,支持批量 IP,输出汇总 JSON
数据流如下(Mermaid 图):
平台侧调用链路(BruceSec 整合后):
四、逐函数代码解析
4.1 脚本完整代码
以下为脚本全文(共 70 行,与部署于本机 ~/.config/threatbook/threatbook_query.py 的版本一致):
python
#!/usr/bin/env python3
"""微步在线 IP 情报查询(BruceSec 公网IP攻击迹象监测用)
用法: python3 threatbook_query.py [ip1 ip2 ...]
默认查询: 203.0.113.11 203.0.113.12 203.0.113.13
Key 读取自同目录 threatbook_api_key(chmod 600)
"""
import json, os, sys, urllib.request, urllib.parse
KEY_FILE = os.path.expanduser("~/.config/threatbook/api_key")
API = "https://api.threatbook.cn/v3/ip/query"
DEFAULT_IPS = ["203.0.113.11", "203.0.113.12", "203.0.113.13"]
def load_key():
with open(KEY_FILE) as f:
return f.read().strip()
def query(key, ip):
q = urllib.parse.urlencode({"apikey": key, "resource": ip})
req = urllib.request.Request(f"{API}?{q}", headers={"User-Agent": "BruceSec-ip-monitor/1.0"})
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read().decode())
def summarize(ip, data):
judgments = data.get("judgments") or []
basic = data.get("basic") or {}
loc = basic.get("location") or {}
asn = data.get("asn") or {}
intels = []
for src, items in (data.get("intelligences") or {}).items():
for it in items:
if not it.get("expired", True):
intels.append({
"source": src,
"types": it.get("intel_types", []),
"confidence": it.get("confidence"),
"find_time": it.get("find_time"),
})
return {
"ip": ip,
"judgments": judgments,
"location": f"{loc.get('country','')} {loc.get('province','')} {loc.get('city','')}".strip(),
"carrier": basic.get("carrier", ""),
"asn": f"AS{asn.get('number','')} {asn.get('info','')}".strip(),
"active_intels": intels[:10],
"update_time": data.get("update_time", ""),
}
def main():
ips = sys.argv[1:] or DEFAULT_IPS
key = load_key()
out = []
for ip in ips:
try:
d = query(key, ip)
if d.get("response_code") != 0 or ip not in (d.get("data") or {}):
out.append({"ip": ip, "error": d.get("verbose_msg", "查询失败")})
continue
out.append(summarize(ip, d["data"][ip]))
except Exception as e:
out.append({"ip": ip, "error": str(e)})
print(json.dumps(out, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
4.2 load_key():密钥安全加载
python
def load_key():
with open(KEY_FILE) as f:
return f.read().strip()
KEY_FILE使用os.path.expanduser展开~,指向~/.config/threatbook/api_key,避免硬编码绝对路径带来的可移植性问题。- 文件按行读取并
strip()去除首尾空白,确保 Key 不带多余换行符。 - 安全要点:Key 不写在代码中,而是独立存放于 chmod 600 的密钥文件,实现"代码与密钥分离"。
4.3 query(key, ip):HTTP 调用与 JSON 解析
python
def query(key, ip):
q = urllib.parse.urlencode({"apikey": key, "resource": ip})
req = urllib.request.Request(f"{API}?{q}", headers={"User-Agent": "BruceSec-ip-monitor/1.0"})
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read().decode())
- 使用
urllib.parse.urlencode构造查询串,参数为apikey与resource(目标 IP),避免手动拼接导致的 URL 编码问题。 - 通过
urllib.request.Request显式设置User-Agent: BruceSec-ip-monitor/1.0,标识请求来源,便于在微步侧做调用审计。 urlopen(..., timeout=30)设置 30 秒超时,防止网络异常导致脚本长时间挂起。- 返回结果用
json.loads解码为 Python 字典。
4.4 summarize(ip, data):情报摘要提炼
python
def summarize(ip, data):
judgments = data.get("judgments") or []
basic = data.get("basic") or {}
loc = basic.get("location") or {}
asn = data.get("asn") or {}
intels = []
for src, items in (data.get("intelligences") or {}).items():
for it in items:
if not it.get("expired", True):
intels.append({
"source": src,
"types": it.get("intel_types", []),
"confidence": it.get("confidence"),
"find_time": it.get("find_time"),
})
return {
"ip": ip,
"judgments": judgments,
"location": f"{loc.get('country','')} {loc.get('province','')} {loc.get('city','')}".strip(),
"carrier": basic.get("carrier", ""),
"asn": f"AS{asn.get('number','')} {asn.get('info','')}".strip(),
"active_intels": intels[:10],
"update_time": data.get("update_time", ""),
}
该函数是本脚本的"信息压缩器",做了四件事:
- 恶意判定 :直接取出
judgments列表(如Zombie、Gateway、Whitelist、CDN等),作为首要研判依据。 - 基础信息 :从
basic.location拼接国家 省份 城市,取basic.carrier运营商;从asn拼出AS号 名称。 - 活跃情报过滤 :遍历
intelligences(按情报源分组),仅保留未过期(expired为 False)的情报条目,并记录来源、威胁类型、置信度、发现时间------这是"证据链"的核心。 - 数量裁剪 :
intels[:10]最多保留 10 条活跃情报,控制输出体积,避免超长 JSON 影响下游解析。
4.5 main():命令行编排与容错
python
def main():
ips = sys.argv[1:] or DEFAULT_IPS
key = load_key()
out = []
for ip in ips:
try:
d = query(key, ip)
if d.get("response_code") != 0 or ip not in (d.get("data") or {}):
out.append({"ip": ip, "error": d.get("verbose_msg", "查询失败")})
continue
out.append(summarize(ip, d["data"][ip]))
except Exception as e:
out.append({"ip": ip, "error": str(e)})
print(json.dumps(out, ensure_ascii=False, indent=2))
- 参数兜底 :
sys.argv[1:] or DEFAULT_IPS------ 支持命令行传入任意数量 IP;不传参数时自动查询默认监测名单(三个单位公网 IP)。 - 业务级容错 :微步返回
response_code非 0(如 Key 失效、IP 无效)或data中不含该 IP 时,记录verbose_msg错误信息,不中断整体流程。 - 异常级容错 :网络异常、超时、JSON 解码失败等统一
except Exception捕获,单 IP 失败不影响其他 IP 的查询。 - 输出契约 :最终
json.dumps(out, ensure_ascii=False, indent=2)输出格式化 JSON(保留中文),该 JSON 是平台 / AI 解析的统一契约格式。
五、部署与使用
5.1 部署清单
| 项目 | 位置 | 说明 |
|---|---|---|
| 脚本 | ~/.config/threatbook/threatbook_query.py |
纯标准库,无第三方依赖 |
| API Key | ~/.config/threatbook/api_key |
微步控制台申请,chmod 600 |
| 授权 | chmod 600 threatbook_api_key |
仅当前用户可读写 |
部署命令:
bash
# 1. 放置脚本与密钥
mkdir -p ~/.config/threatbook
# ... 将 threatbook_query.py 与 threatbook_api_key 放入该目录 ...
# 2. 收紧密钥权限
chmod 600 ~/.config/threatbook/api_key
# 3. 校验脚本语法
python3 -m py_compile ~/.config/threatbook/threatbook_query.py
5.2 命令行用法
bash
# 查询单个 IP
python3 ~/.config/threatbook/threatbook_query.py 1.1.1.1
# 查询多个 IP(空格分隔)
python3 ~/.config/threatbook/threatbook_query.py 1.1.1.1 8.8.8.8
# 不传参数:查询默认监测名单
python3 ~/.config/threatbook/threatbook_query.py
5.3 真实输出示例(8.8.8.8,实测于本机)
以 Google 公共 DNS 8.8.8.8 为例,验证脚本功能正常:
json
[
{
"ip": "8.8.8.8",
"judgments": [
"Gateway",
"Whitelist",
"CDN"
],
"location": "United States",
"carrier": "Google LLC",
"asn": "AS15169 GOOGLE",
"active_intels": [
{
"source": "threatbook_lab",
"types": [
"Gateway"
],
"confidence": 75,
"find_time": "2025-12-09 06:17:42"
},
{
"source": "threatbook_lab",
"types": [
"CDN"
],
"confidence": 85,
"find_time": "2023-10-19 23:30:02"
},
{
"source": "threatbook_lab",
"types": [
"Whitelist"
],
"confidence": 100,
"find_time": "2020-11-29 03:23:39"
},
{
"source": "threatbook_lab",
"types": [
"Whitelist"
],
"confidence": 100,
"find_time": "2016-01-13 20:34:26"
},
{
"source": "open_source",
"types": [
"Phishing"
],
"confidence": 55,
"find_time": "2023-03-17 02:06:22"
},
{
"source": "open_source",
"types": [
"Suspicious"
],
"confidence": 65,
"find_time": "2018-09-21 09:00:31"
},
{
"source": "open_source",
"types": [
"Suspicious"
],
"confidence": 65,
"find_time": "2018-03-01 06:04:34"
},
{
"source": "open_source",
"types": [
"Suspicious"
],
"confidence": 65,
"find_time": "2017-09-20 13:52:07"
},
{
"source": "open_source",
"types": [
"Spam"
],
"confidence": 65,
"find_time": "2017-09-12 02:31:14"
},
{
"source": "open_source",
"types": [
"Suspicious"
],
"confidence": 65,
"find_time": "2017-07-07 08:25:37"
}
],
"update_time": "2026-08-11 06:01:47"
}
]
结果解读 :8.8.8.8 的 judgments 为 Gateway / Whitelist / CDN,均为良性标签;threatbook_lab 高置信度(75-100)情报指向 Gateway、CDN、Whitelist,符合 Google 公共 DNS 的定位;open_source 来源存在少量历史 Phishing / Suspicious / Spam 标签(置信度 55-65),属于开源情报的宽泛收录,不影响整体良性判定。脚本输出质量符合预期。
六、平台整合:注册进 BruceSec 安全平台
6.1 tools/threatbook_query.yaml 注册文件
将脚本以 MCP 工具形式注册进 BruceSec 平台,配置文件为 tools/threatbook_query.yaml:
yaml
name: "threatbook_query"
command: "/usr/bin/python3"
# 固定参数:微步 IP 情报查询脚本(绝对路径,避免 PATH 依赖)
args: ["~/.config/threatbook/threatbook_query.py"]
enabled: true
short_description: "微步在线 IP 威胁情报查询:威胁标签/恶意判定/位置/ASN(需 API Key,已绑定出口IP)"
description: |
微步在线 IP 威胁情报查询(v3/ip/query,全维度标签)。
**能力:**
- 查询单个或多个 IP 的威胁情报
- 返回 `judgments` 恶意判定、威胁标签(Zombie/Scanner/Compromised/C2 等)、情报置信度
- 返回位置、运营商、ASN 信息
**用法:**
- 只传 `ip` 即可,例如 `1.1.1.1`;多个 IP 用空格分隔(如 `1.1.1.1 8.8.8.8`)
- 不传 `ip` 时默认查询监测名单:`203.0.113.11 203.0.113.12 203.0.113.13`
**注意:**
- API Key 存于 `~/.config/threatbook/api_key`(chmod 600),需在微步控制台绑定请求出口 IP,否则报 Invalid Access IP
- 输出为 JSON,`judgments` 为空数组通常表示情报未知/无恶意标签
parameters:
- name: "ip"
type: "string"
description: |
目标 IP(可多个,空格分隔)。示例:`203.0.113.11`、`1.1.1.1 8.8.8.8`。
留空默认查询监测名单三个 IP。
required: false
position: 1
format: "positional"
设计要点:
- command + args 分离 :
command固定为/usr/bin/python3,脚本路径放入args绝对路径,避免 PATH 依赖,保证平台侧稳定执行。 - enabled: true:工具注册后立即生效,可被 AI 会话调用。
- description 分层 :
short_description精简摘要供工具列表展示;description详述能力、用法、注意事项(Key 绑定、默认名单、JSON 语义),供 AI 深度理解及resources/read查询。 - 参数契约 :定义
ip为positional位置参数,支持多 IP 空格分隔,留空走默认监测名单。
6.2 ApplyConfig 热重载验证
BruceSec 平台支持配置热重载,无需重启进程即可应用新增工具。实测验证过程(由平台浏览器 Agent 执行):
- 登录状态 :平台已登录(用户为管理员 admin,拥有
config:write等完整权限)。 - 触发热重载 :调用后端
POST /api/config/apply接口(携带 Bearer token)。 - 返回结果 :HTTP 200,响应体为:
json
{"message":"配置已应用","tools_count":93}
- 工具列表验证 :通过
/api/config/tools接口分页检索(平台共 141 个工具),确认threatbook_query存在且enabled: true。
6.3 MCP 管理页确认(含截图)
平台 MCP 管理页(#mcp-management)搜索过滤后显示:
- 名称:
threatbook_query - 状态:常驻(已启用),复选框已勾选
- 描述:"微步在线 IP 威胁情报查询:威胁标签/恶意判定/位置/ASN(需 API Key,已绑定出口IP)"
- 页面统计:当前页已启用 1/1,总计已启用 1/1

截图说明:图中为 BruceSecAI 安全管理平台" MCP 管理"页面(暗色主题,左侧功能导航栏,顶部有 API 文档、GitHub、语言切换等元素),
threatbook_query工具显示为已启用(勾选 + "常驻"),确认平台整合成功。
至此,threatbook_query 已可在平台对话中直接调用,例如:"查询 1.1.1.1 的微步情报"。
七、实际应用:三个监测 IP 的微步判定与 nmap 对照
7.1 微步情报查询结果(实测于本机)
对默认监测名单中的三个公网 IP 执行脚本查询,真实结果如下:
| IP | judgments 判定 | 位置 | 运营商 | ASN | 活跃情报(未过期) | 情报更新时间 |
|---|---|---|---|---|---|---|
| 203.0.113.11 | Zombie、Gateway | 中国(省市已脱敏) | ISP 已脱敏 | ASN 已脱敏 | Gateway(75)、Zombie(75)、Mobile(50) | 2026-08-10 16:39:39 |
| 203.0.113.12 | Gateway | 中国(省市已脱敏) | ISP 已脱敏 | ASN 已脱敏 | Gateway(75)、Mobile(50) | 2026-08-10 17:18:04 |
| 203.0.113.13 | Gateway | 中国(省市已脱敏) | ISP 已脱敏 | ASN 已脱敏 | Gateway(75)、Mobile(50) | 2026-08-10 17:52:36 |
原始 JSON(203.0.113.11,截取关键字段):
json
{
"ip": "203.0.113.11",
"judgments": ["Zombie", "Gateway"],
"location": "China (region redacted)",
"carrier": "[ISP 已脱敏]",
"asn": "[ASN 已脱敏]",
"active_intels": [
{"source": "threatbook_lab", "types": ["Gateway"], "confidence": 75, "find_time": "2025-12-08 23:21:29"},
{"source": "threatbook_lab", "types": ["Zombie"], "confidence": 75, "find_time": "2017-02-23 19:36:24"},
{"source": "open_source", "types": ["Mobile"], "confidence": 50, "find_time": "2021-08-03 02:34:26"}
],
"update_time": "2026-08-10 16:39:39"
}
7.2 判定结论解读
- 203.0.113.11 :出现
Zombie(僵尸网络)判定标签,threatbook_lab来源置信度 75,发现时间 2017-02-23------属于历史情报(早期被标记为僵尸网络节点),同时具备Gateway标签(ISP 已脱敏骨干网网关特征)。结论:存在历史僵尸网络关联记录,需持续关注,但非近期活跃威胁(最新活跃情报为 2025-12-08 的 Gateway 标签)。 - 203.0.113.12 :仅
Gateway判定,无恶意标签,运营商为中国ISP 已脱敏,(省市已脱敏)(省市已脱敏),ASN 已脱敏。结论:当前情报面无恶意标记。 - 203.0.113.13 :仅
Gateway判定,中国ISP 已脱敏,(省市已脱敏)(省市已脱敏),ASN 已脱敏。结论:当前情报面无恶意标记。
三个 IP 的 judgments 均包含 Gateway,与其作为运营商骨干网/出口网关的属性一致;唯一需要重点关注的是 203.0.113.11 的 Zombie 历史标签。
7.3 与 nmap 主动扫描对照
将微步被动情报与 nmap 主动扫描结果对照(nmap 扫描文件记录了前两个目标,实测于 2026-08-14):
| IP | nmap 主动扫描结论 | 微步情报结论 | 对照分析 |
|---|---|---|---|
| 203.0.113.11 | 100 端口全部 filtered(34.26s),无服务信息 | Zombie + Gateway,ISP 已脱敏,ASN 已脱敏 | 主动探测被防火墙完全屏蔽,但情报仍给出"僵尸网络历史标签"这一主动扫描无法获得的关键信息 |
| 203.0.113.12 | 10 个端口(53/80/135/139/443/445/3128/5800/5900/8080)全部 filtered | Gateway,ISP 已脱敏,ASN 已脱敏 | 防火墙过滤了全部常见服务端口,情报侧同样无恶意标签,两者结论一致(未发现攻击迹象) |
| 203.0.113.13 | 本次扫描文件中未包含该目标结果 | Gateway,ISP 已脱敏,ASN 已脱敏 | 情报侧无恶意标记;nmap 未执行/未记录,建议补充主动扫描对照 |
对照结论 :在边界防火墙严格过滤(filtered)导致主动扫描近乎失效的场景下,微步威胁情报提供了补充视角------尤其是 203.0.113.11 的 Zombie 历史标签,仅靠 nmap 无法获得。两者结合,构成了"主动 + 被动"双通道的公网 IP 攻击迹象监测方案。
八、安全与合规
- 仅限授权资产:本脚本仅用于本单位/已获授权的公网 IP 监测,严禁对未授权目标进行批量查询与研判。微步情报查询虽属被动行为,但将查询行为与具体业务场景绑定,避免被滥用为"踩点工具"。
- API Key 保护 :
- Key 独立存放于
threatbook_api_key文件,并chmod 600限制为仅当前用户可读写; - 代码与密钥分离,脚本中不出现任何硬编码 Key;
- 平台侧 yaml 只引用密钥文件路径,不记录 Key 明文。
- Key 独立存放于
- 出口 IP 绑定 :Key 在微步控制台绑定请求出口 IP,既是访问控制,也是 Key 泄露时的第一道止损防线(泄露后在其他 IP 上无法使用,并报
Invalid Access IP)。 - 配额管理 :脚本单次调用设置 30 秒超时、单 IP 失败不重试(
except Exception直接记录错误),避免异常循环消耗配额;建议结合微步控制台配额额度按需调用(本项目为按需查询场景,未做高频轮询),并关注控制台配额与速率限制告警。 - 数据最小化 :
summarize只保留研判所需字段(判定、位置、运营商、ASN、未过期情报 top10),不落盘原始全量响应,减少敏感数据暴露面。
九、总结
threatbook_query.py 以不足百行的纯标准库代码,打通了"公网 IP 攻击迹象监测"的威胁情报链路:
- 解决痛点 :在 nmap 等主动扫描被边界防火墙大面积
filtered限制的场景下,通过微步v3/ip/query被动情报补充主动扫描无法获取的"历史行为视角",成功识别出 203.0.113.11 的Zombie历史标签。 - 工程实践:密钥分离 + chmod 600、接口调用超时与双层容错、JSON 摘要契约,保证了脚本在批量监测中的健壮性。
- 平台整合 :通过
tools/threatbook_query.yaml(enabled: true)+POST /api/config/apply热重载(实测返回 HTTP 200、tools_count: 93)一键注册为 MCP 工具,并在 MCP 管理页确认"常驻(已启用)",使 AI 会话可直接调用。 - 可扩展方向 :可将情报查询结果与告警平台联动(如对含
Zombie/C2等恶意判定且置信度较高的 IP 触发告警),并定期与 nmap 主动扫描做周期性对照,形成常态化的公网资产威胁监测报表。
本文所有 IP 判定、接口返回、平台热重载数据均来自本机实测(2026-08-14),截图来自 BruceSec 平台 MCP 管理页实拍。