mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-12 18:58:10 +02:00
Add files via upload
This commit is contained in:
4 files changed
+36
-256
No files matched your search
+11
-1
@@ -16,7 +16,7 @@ args:
|
|||||||
# ==================================================
|
# ==================================================
|
||||||
|
|
||||||
# Quake API基础URL
|
# Quake API基础URL
|
||||||
base_url = "https://quake.360.cn/api/v3/search/quake_service"
|
base_url = "https://quake.360.net/api/v3/search/quake_service"
|
||||||
|
|
||||||
# 解析参数(从JSON字符串或命令行参数)
|
# 解析参数(从JSON字符串或命令行参数)
|
||||||
def parse_args():
|
def parse_args():
|
||||||
@@ -178,6 +178,16 @@ args:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
results = result_data.get("data", [])
|
results = result_data.get("data", [])
|
||||||
|
if isinstance(results, dict):
|
||||||
|
nested = None
|
||||||
|
for key in ("data", "items", "matches", "results", "list", "records"):
|
||||||
|
value = results.get(key)
|
||||||
|
if isinstance(value, list):
|
||||||
|
nested = value
|
||||||
|
break
|
||||||
|
results = nested if nested is not None else []
|
||||||
|
if not isinstance(results, list):
|
||||||
|
results = []
|
||||||
meta = result_data.get("meta", {})
|
meta = result_data.get("meta", {})
|
||||||
pagination = meta.get("pagination", {}) if isinstance(meta, dict) else {}
|
pagination = meta.get("pagination", {}) if isinstance(meta, dict) else {}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ parameters:
|
|||||||
required: true
|
required: true
|
||||||
flag: "-a"
|
flag: "-a"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# -p, --ports;范围请用 range (-r),勿把 1-1000 填进 ports
|
# -p, --ports;范围请用 range (-r),勿把 1-1000 填进 ports
|
||||||
- name: "ports"
|
- name: "ports"
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -36,7 +35,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "-p"
|
flag: "-p"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# -r, --range(与 ports 列表二选一或按官方说明组合)
|
# -r, --range(与 ports 列表二选一或按官方说明组合)
|
||||||
- name: "range"
|
- name: "range"
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -47,7 +45,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "-r"
|
flag: "-r"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# -u, --ulimit
|
# -u, --ulimit
|
||||||
- name: "ulimit"
|
- name: "ulimit"
|
||||||
type: "int"
|
type: "int"
|
||||||
@@ -56,7 +53,6 @@ parameters:
|
|||||||
flag: "-u"
|
flag: "-u"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
default: 5000
|
default: 5000
|
||||||
|
|
||||||
# --scripts:none | default | custom(CLI 默认 default)
|
# --scripts:none | default | custom(CLI 默认 default)
|
||||||
- name: "scripts"
|
- name: "scripts"
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -73,7 +69,6 @@ parameters:
|
|||||||
- "none"
|
- "none"
|
||||||
- "default"
|
- "default"
|
||||||
- "custom"
|
- "custom"
|
||||||
|
|
||||||
# -g, --greppable:仅端口列表,无 Nmap 输出
|
# -g, --greppable:仅端口列表,无 Nmap 输出
|
||||||
- name: "greppable"
|
- name: "greppable"
|
||||||
type: "bool"
|
type: "bool"
|
||||||
@@ -82,7 +77,6 @@ parameters:
|
|||||||
flag: "-g"
|
flag: "-g"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
default: false
|
default: false
|
||||||
|
|
||||||
# -b, --batch-size [default: 4500]
|
# -b, --batch-size [default: 4500]
|
||||||
- name: "batch_size"
|
- name: "batch_size"
|
||||||
type: "int"
|
type: "int"
|
||||||
@@ -90,7 +84,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "-b"
|
flag: "-b"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# -t, --timeout ms [default: 1500]
|
# -t, --timeout ms [default: 1500]
|
||||||
- name: "timeout_ms"
|
- name: "timeout_ms"
|
||||||
type: "int"
|
type: "int"
|
||||||
@@ -98,7 +91,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "-t"
|
flag: "-t"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# --scan-order serial | random [default: serial]
|
# --scan-order serial | random [default: serial]
|
||||||
- name: "scan_order"
|
- name: "scan_order"
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -109,7 +101,6 @@ parameters:
|
|||||||
options:
|
options:
|
||||||
- "serial"
|
- "serial"
|
||||||
- "random"
|
- "random"
|
||||||
|
|
||||||
# --top:top 1000 端口
|
# --top:top 1000 端口
|
||||||
- name: "top_ports"
|
- name: "top_ports"
|
||||||
type: "bool"
|
type: "bool"
|
||||||
@@ -118,7 +109,6 @@ parameters:
|
|||||||
flag: "--top"
|
flag: "--top"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
default: false
|
default: false
|
||||||
|
|
||||||
# -e, --exclude-ports
|
# -e, --exclude-ports
|
||||||
- name: "exclude_ports"
|
- name: "exclude_ports"
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -126,7 +116,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "-e"
|
flag: "-e"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# -x, --exclude-addresses
|
# -x, --exclude-addresses
|
||||||
- name: "exclude_addresses"
|
- name: "exclude_addresses"
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -134,7 +123,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "-x"
|
flag: "-x"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
# --tries [default: 1]
|
# --tries [default: 1]
|
||||||
- name: "tries"
|
- name: "tries"
|
||||||
type: "int"
|
type: "int"
|
||||||
@@ -142,7 +130,6 @@ parameters:
|
|||||||
required: false
|
required: false
|
||||||
flag: "--tries"
|
flag: "--tries"
|
||||||
format: "flag"
|
format: "flag"
|
||||||
|
|
||||||
- name: "additional_args"
|
- name: "additional_args"
|
||||||
type: "string"
|
type: "string"
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
+13
-240
@@ -2,296 +2,70 @@ name: "virustotal_search"
|
|||||||
command: "python3"
|
command: "python3"
|
||||||
args:
|
args:
|
||||||
- "-c"
|
- "-c"
|
||||||
- |
|
- "import sys\nimport json\nimport requests\nimport os\nimport time\n\n# ==================== VirusTotal 配置 ====================\n# 请在此处配置您的 VirusTotal API 密钥\n# 您也可以在环境变量中设置:VT_API_KEY\n# enable 默认为 false,需开启才能调用该MCP\nVT_API_KEY = \"\" # 请填写您的 VirusTotal API 密钥\n# =======================================================\n\n# VirusTotal API 基础 URL\nBASE_URL = \"https://www.virustotal.com/api/v3\"\n\ndef parse_args():\n \"\"\"解析命令行参数\"\"\"\n # 尝试从第一个参数读取 JSON 配置\n if len(sys.argv) > 1:\n try:\n arg1 = str(sys.argv[1])\n config = json.loads(arg1)\n if isinstance(config, dict):\n return config\n except (json.JSONDecodeError, TypeError, ValueError):\n pass\n\n # 传统位置参数方式\n config = {}\n if len(sys.argv) > 1:\n config['domain'] = str(sys.argv[1])\n if len(sys.argv) > 2:\n try:\n config['limit'] = int(sys.argv[2])\n except (ValueError, TypeError):\n pass\n if len(sys.argv) > 3:\n config['include_ips'] = sys.argv[3].lower() in ('true', '1', 'yes')\n return config\n\ndef query_virustotal_subdomains(domain, api_key, limit=100, include_ips=False):\n \"\"\"\n 查询 VirusTotal 的子域名信息\n \n Args:\n domain: 要查询的域名\n api_key: VirusTotal API 密钥\n limit: 返回结果数量限制\n include_ips: 是否包含 IP 地址信息\n \n Returns:\n dict: 包含查询结果的字典\n \"\"\"\n # 构建 API 请求 URL\n url = f\"{BASE_URL}/domains/{domain}/subdomains\"\n \n headers = {\n \"x-apikey\": api_key,\n \"accept\": \"application/json\"\n }\n \n params = {\n \"limit\": min(limit, 40) # API 限制最大 40\n }\n \n all_results = []\n next_url = None\n \n try:\n # 处理分页\n while True:\n if next_url:\n response = requests.get(next_url, headers=headers, timeout=30)\n else:\n response = requests.get(url, headers=headers, params=params, timeout=30)\n \n response.raise_for_status()\n data = response.json()\n \n # 提取子域名数据\n if 'data' in data and data['data']:\n for item in data['data']:\n if 'id' in item:\n subdomain_info = {\n 'subdomain': item['id'],\n 'type': item.get('type', 'domain'),\n }\n \n # 如果 include_ips 为 True,尝试获取解析 IP\n if include_ips and 'attributes' in item:\n attributes = item.get('attributes', {})\n # 这里简化处理,实际可能需要额外的 API 调用\n subdomain_info['last_dns_records'] = attributes.get('last_dns_records', [])\n \n all_results.append(subdomain_info)\n \n # 检查是否有下一页\n if 'links' in data and 'next' in data['links'] and len(all_results) < limit:\n next_url = data['links']['next']\n # 避免请求过快\n time.sleep(0.5)\n else:\n break\n else:\n break\n \n # 如果已达到限制,停止获取\n if len(all_results) >= limit:\n break\n \n # 处理返回结果\n if all_results:\n return {\n \"status\": \"success\",\n \"domain\": domain,\n \"total_found\": len(all_results),\n \"results\": all_results[:limit],\n \"message\": f\"成功获取 {len(all_results[:limit])} 个子域名\"\n }\n else:\n return {\n \"status\": \"success\",\n \"domain\": domain,\n \"total_found\": 0,\n \"results\": [],\n \"message\": f\"未找到 {domain} 的子域名\"\n }\n \n except requests.exceptions.RequestException as e:\n error_msg = str(e)\n error_result = {\n \"status\": \"error\",\n \"message\": f\"API 请求失败: {error_msg}\",\n \"suggestion\": \"请检查网络连接、API 密钥是否正确,或 VirusTotal API 服务是否可用\"\n }\n \n # 处理特定 HTTP 状态码\n if hasattr(e, 'response') and e.response:\n status_code = e.response.status_code\n if status_code == 401:\n error_result[\"message\"] = \"API 密钥Line truncated
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
|
|
||||||
# ==================== VirusTotal 配置 ====================
|
|
||||||
# 请在此处配置您的 VirusTotal API 密钥
|
|
||||||
# 您也可以在环境变量中设置:VT_API_KEY
|
|
||||||
# enable 默认为 false,需开启才能调用该MCP
|
|
||||||
VT_API_KEY = "" # 请填写您的 VirusTotal API 密钥
|
|
||||||
# =======================================================
|
|
||||||
|
|
||||||
# VirusTotal API 基础 URL
|
|
||||||
BASE_URL = "https://www.virustotal.com/api/v3"
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
"""解析命令行参数"""
|
|
||||||
# 尝试从第一个参数读取 JSON 配置
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
try:
|
|
||||||
arg1 = str(sys.argv[1])
|
|
||||||
config = json.loads(arg1)
|
|
||||||
if isinstance(config, dict):
|
|
||||||
return config
|
|
||||||
except (json.JSONDecodeError, TypeError, ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 传统位置参数方式
|
|
||||||
config = {}
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
config['domain'] = str(sys.argv[1])
|
|
||||||
if len(sys.argv) > 2:
|
|
||||||
try:
|
|
||||||
config['limit'] = int(sys.argv[2])
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
pass
|
|
||||||
if len(sys.argv) > 3:
|
|
||||||
config['include_ips'] = sys.argv[3].lower() in ('true', '1', 'yes')
|
|
||||||
return config
|
|
||||||
|
|
||||||
def query_virustotal_subdomains(domain, api_key, limit=100, include_ips=False):
|
|
||||||
"""
|
|
||||||
查询 VirusTotal 的子域名信息
|
|
||||||
|
|
||||||
Args:
|
|
||||||
domain: 要查询的域名
|
|
||||||
api_key: VirusTotal API 密钥
|
|
||||||
limit: 返回结果数量限制
|
|
||||||
include_ips: 是否包含 IP 地址信息
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: 包含查询结果的字典
|
|
||||||
"""
|
|
||||||
# 构建 API 请求 URL
|
|
||||||
url = f"{BASE_URL}/domains/{domain}/subdomains"
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"x-apikey": api_key,
|
|
||||||
"accept": "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
params = {
|
|
||||||
"limit": min(limit, 40) # API 限制最大 40
|
|
||||||
}
|
|
||||||
|
|
||||||
all_results = []
|
|
||||||
next_url = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 处理分页
|
|
||||||
while True:
|
|
||||||
if next_url:
|
|
||||||
response = requests.get(next_url, headers=headers, timeout=30)
|
|
||||||
else:
|
|
||||||
response = requests.get(url, headers=headers, params=params, timeout=30)
|
|
||||||
|
|
||||||
response.raise_for_status()
|
|
||||||
data = response.json()
|
|
||||||
|
|
||||||
# 提取子域名数据
|
|
||||||
if 'data' in data and data['data']:
|
|
||||||
for item in data['data']:
|
|
||||||
if 'id' in item:
|
|
||||||
subdomain_info = {
|
|
||||||
'subdomain': item['id'],
|
|
||||||
'type': item.get('type', 'domain'),
|
|
||||||
}
|
|
||||||
|
|
||||||
# 如果 include_ips 为 True,尝试获取解析 IP
|
|
||||||
if include_ips and 'attributes' in item:
|
|
||||||
attributes = item.get('attributes', {})
|
|
||||||
# 这里简化处理,实际可能需要额外的 API 调用
|
|
||||||
subdomain_info['last_dns_records'] = attributes.get('last_dns_records', [])
|
|
||||||
|
|
||||||
all_results.append(subdomain_info)
|
|
||||||
|
|
||||||
# 检查是否有下一页
|
|
||||||
if 'links' in data and 'next' in data['links'] and len(all_results) < limit:
|
|
||||||
next_url = data['links']['next']
|
|
||||||
# 避免请求过快
|
|
||||||
time.sleep(0.5)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# 如果已达到限制,停止获取
|
|
||||||
if len(all_results) >= limit:
|
|
||||||
break
|
|
||||||
|
|
||||||
# 处理返回结果
|
|
||||||
if all_results:
|
|
||||||
return {
|
|
||||||
"status": "success",
|
|
||||||
"domain": domain,
|
|
||||||
"total_found": len(all_results),
|
|
||||||
"results": all_results[:limit],
|
|
||||||
"message": f"成功获取 {len(all_results[:limit])} 个子域名"
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
"status": "success",
|
|
||||||
"domain": domain,
|
|
||||||
"total_found": 0,
|
|
||||||
"results": [],
|
|
||||||
"message": f"未找到 {domain} 的子域名"
|
|
||||||
}
|
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
error_msg = str(e)
|
|
||||||
error_result = {
|
|
||||||
"status": "error",
|
|
||||||
"message": f"API 请求失败: {error_msg}",
|
|
||||||
"suggestion": "请检查网络连接、API 密钥是否正确,或 VirusTotal API 服务是否可用"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 处理特定 HTTP 状态码
|
|
||||||
if hasattr(e, 'response') and e.response:
|
|
||||||
status_code = e.response.status_code
|
|
||||||
if status_code == 401:
|
|
||||||
error_result["message"] = "API 密钥无效或未授权"
|
|
||||||
error_result["suggestion"] = "请检查 VirusTotal API 密钥是否正确,或在 https://www.virustotal.com/ 获取有效密钥"
|
|
||||||
elif status_code == 429:
|
|
||||||
error_result["message"] = "API 请求频率超限"
|
|
||||||
error_result["suggestion"] = "请稍后再试,VirusTotal API 有严格的速率限制(免费版每分钟4次)"
|
|
||||||
elif status_code == 404:
|
|
||||||
error_result["message"] = f"域名 '{domain}' 不存在或未找到"
|
|
||||||
|
|
||||||
return error_result
|
|
||||||
|
|
||||||
try:
|
|
||||||
config = parse_args()
|
|
||||||
|
|
||||||
if not isinstance(config, dict):
|
|
||||||
error_result = {
|
|
||||||
"status": "error",
|
|
||||||
"message": f"参数解析错误: 期望字典类型,但得到 {type(config).__name__}",
|
|
||||||
"type": "TypeError"
|
|
||||||
}
|
|
||||||
print(json.dumps(error_result, ensure_ascii=False, indent=2))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# 获取 API 密钥(从配置或环境变量)
|
|
||||||
api_key = os.getenv('VT_API_KEY', VT_API_KEY).strip()
|
|
||||||
|
|
||||||
if not api_key:
|
|
||||||
error_result = {
|
|
||||||
"status": "error",
|
|
||||||
"message": "缺少 VirusTotal API 密钥",
|
|
||||||
"required_config": ["VT_API_KEY"],
|
|
||||||
"note": "请在 YAML 文件的 VT_API_KEY 配置项中填写您的 VirusTotal API 密钥,或在环境变量 VT_API_KEY 中设置。API 密钥可在 https://www.virustotal.com/ 注册获取"
|
|
||||||
}
|
|
||||||
print(json.dumps(error_result, ensure_ascii=False, indent=2))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# 获取必需参数
|
|
||||||
domain = config.get('domain', '').strip()
|
|
||||||
if not domain:
|
|
||||||
error_result = {
|
|
||||||
"status": "error",
|
|
||||||
"message": "缺少必需参数: domain(要查询的域名)",
|
|
||||||
"required_params": ["domain"],
|
|
||||||
"examples": [
|
|
||||||
"example.com",
|
|
||||||
"google.com",
|
|
||||||
"baidu.com"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
print(json.dumps(error_result, ensure_ascii=False, indent=2))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# 获取可选参数
|
|
||||||
limit = config.get('limit', 100)
|
|
||||||
try:
|
|
||||||
limit = int(limit)
|
|
||||||
if limit < 1:
|
|
||||||
limit = 100
|
|
||||||
elif limit > 1000:
|
|
||||||
limit = 1000 # 限制最大 1000
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
limit = 100
|
|
||||||
|
|
||||||
include_ips = config.get('include_ips', False)
|
|
||||||
if isinstance(include_ips, str):
|
|
||||||
include_ips = include_ips.lower() in ('true', '1', 'yes')
|
|
||||||
|
|
||||||
# 执行查询
|
|
||||||
result = query_virustotal_subdomains(domain, api_key, limit, include_ips)
|
|
||||||
|
|
||||||
# 输出结果
|
|
||||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
error_result = {
|
|
||||||
"status": "error",
|
|
||||||
"message": f"执行出错: {str(e)}",
|
|
||||||
"type": type(e).__name__
|
|
||||||
}
|
|
||||||
print(json.dumps(error_result, ensure_ascii=False, indent=2))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
short_description: "VirusTotal 子域名查询工具,通过 VirusTotal API 被动收集域名子域名"
|
short_description: "VirusTotal 子域名查询工具,通过 VirusTotal API 被动收集域名子域名"
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
VirusTotal 子域名查询工具,利用 VirusTotal 聚合的历史 DNS 数据来发现目标域名的子域名。
|
VirusTotal 子域名查询工具,利用 VirusTotal 聚合的历史 DNS 数据来发现目标域名的子域名。
|
||||||
|
|
||||||
**主要功能:**
|
**主要功能:**
|
||||||
- 被动子域名收集:从 VirusTotal 历史 DNS 数据中检索子域名
|
- 被动子域名收集:从 VirusTotal 历史 DNS 数据中检索子域名
|
||||||
- 分页查询:支持大量子域名的获取
|
- 分页查询:支持大量子域名的获取
|
||||||
- IP 关联:可选包含 DNS 解析记录
|
- IP 关联:可选包含 DNS 解析记录
|
||||||
- 去重处理:自动去重返回结果
|
- 去重处理:自动去重返回结果
|
||||||
|
|
||||||
**使用场景:**
|
**使用场景:**
|
||||||
- 安全测试前期信息收集
|
- 安全测试前期信息收集
|
||||||
- 企业网络资产发现
|
- 企业网络资产发现
|
||||||
- 攻击面分析
|
- 攻击面分析
|
||||||
- 威胁情报收集
|
- 威胁情报收集
|
||||||
- 渗透测试信息收集
|
- 渗透测试信息收集
|
||||||
|
|
||||||
**数据来源:**
|
**数据来源:**
|
||||||
VirusTotal 聚合了来自多个来源的 DNS 数据,包括:
|
VirusTotal 聚合了来自多个来源的 DNS 数据,包括:
|
||||||
- 历史 DNS 解析记录
|
- 历史 DNS 解析记录
|
||||||
- 被动 DNS 数据库
|
- 被动 DNS 数据库
|
||||||
- 证书透明度日志
|
- 证书透明度日志
|
||||||
- 安全扫描数据
|
- 安全扫描数据
|
||||||
|
|
||||||
**注意事项:**
|
**注意事项:**
|
||||||
- **API 密钥必需**:需要在 VirusTotal 注册账号并获取 API 密钥
|
- **API 密钥必需**:需要在 VirusTotal 注册账号并获取 API 密钥
|
||||||
- **速率限制**:免费版 API 每分钟限制 4 次请求
|
- **速率限制**:免费版 API 每分钟限制 4 次请求
|
||||||
- **数据时效性**:数据基于历史扫描记录,可能不是实时的
|
- **数据时效性**:数据基于历史扫描记录,可能不是实时的
|
||||||
- **使用授权**:仅允许对您拥有合法授权的目标进行查询
|
- **使用授权**:仅允许对您拥有合法授权的目标进行查询
|
||||||
- **配额限制**:免费版每月有查询配额限制
|
- **配额限制**:免费版每月有查询配额限制
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
- name: "domain"
|
- name: "domain"
|
||||||
type: "string"
|
type: "string"
|
||||||
description: |
|
description: |
|
||||||
要查询的目标域名(必需)。
|
要查询的目标域名(必需)。
|
||||||
|
|
||||||
**格式要求:**
|
**格式要求:**
|
||||||
- 仅输入主域名,不要包含协议头(http://)或路径
|
- 仅输入主域名,不要包含协议头(http://)或路径
|
||||||
- 支持二级域名查询
|
- 支持二级域名查询
|
||||||
|
|
||||||
**示例值:**
|
**示例值:**
|
||||||
- "example.com"
|
- "example.com"
|
||||||
- "google.com"
|
- "google.com"
|
||||||
- "baidu.com"
|
- "baidu.com"
|
||||||
- "github.com"
|
- "github.com"
|
||||||
|
|
||||||
**注意事项:**
|
**注意事项:**
|
||||||
- 域名格式必须正确
|
- 域名格式必须正确
|
||||||
- 查询结果可能包含跨域子域名
|
- 查询结果可能包含跨域子域名
|
||||||
required: true
|
required: true
|
||||||
position: 2
|
position: 2
|
||||||
format: "positional"
|
format: "positional"
|
||||||
|
|
||||||
- name: "limit"
|
- name: "limit"
|
||||||
type: "int"
|
type: "int"
|
||||||
description: |
|
description: |
|
||||||
返回结果数量限制(可选)。
|
返回结果数量限制(可选)。
|
||||||
|
|
||||||
**说明:**
|
**说明:**
|
||||||
- 默认值:40
|
- 默认值:40
|
||||||
- 最大值:1000(API 限制)
|
- 最大值:1000(API 限制)
|
||||||
- 建议值:100-500
|
- 建议值:100-500
|
||||||
|
|
||||||
**注意事项:**
|
**注意事项:**
|
||||||
- 设置过大的值可能导致请求超时
|
- 设置过大的值可能导致请求超时
|
||||||
- API 单次返回限制为 40 条,超过会自动分页
|
- API 单次返回限制为 40 条,超过会自动分页
|
||||||
@@ -299,20 +73,19 @@ parameters:
|
|||||||
position: 3
|
position: 3
|
||||||
format: "positional"
|
format: "positional"
|
||||||
default: 40
|
default: 40
|
||||||
|
|
||||||
- name: "include_ips"
|
- name: "include_ips"
|
||||||
type: "bool"
|
type: "bool"
|
||||||
description: |
|
description: |
|
||||||
是否包含 IP 地址信息(可选)。
|
是否包含 IP 地址信息(可选)。
|
||||||
|
|
||||||
**说明:**
|
**说明:**
|
||||||
- true:在结果中包含 DNS 解析记录
|
- true:在结果中包含 DNS 解析记录
|
||||||
- false:仅返回子域名列表
|
- false:仅返回子域名列表
|
||||||
|
|
||||||
**注意事项:**
|
**注意事项:**
|
||||||
- 包含 IP 信息会增加 API 调用次数
|
- 包含 IP 信息会增加 API 调用次数
|
||||||
- 可能包含历史解析 IP,不一定准确
|
- 可能包含历史解析 IP,不一定准确
|
||||||
required: false
|
required: false
|
||||||
position: 4
|
position: 4
|
||||||
format: "positional"
|
format: "positional"
|
||||||
default: false
|
default: false
|
||||||
@@ -17,7 +17,7 @@ args:
|
|||||||
# ==================================================
|
# ==================================================
|
||||||
|
|
||||||
# ZoomEye API基础URL
|
# ZoomEye API基础URL
|
||||||
base_url = "https://api.zoomeye.org/v2/search"
|
base_url = "https://api.zoomeye.ai/v2/search"
|
||||||
|
|
||||||
# 解析参数(从JSON字符串或命令行参数)
|
# 解析参数(从JSON字符串或命令行参数)
|
||||||
def parse_args():
|
def parse_args():
|
||||||
@@ -78,7 +78,7 @@ args:
|
|||||||
"status": "error",
|
"status": "error",
|
||||||
"message": "缺少ZoomEye配置: api_key(ZoomEye API密钥)",
|
"message": "缺少ZoomEye配置: api_key(ZoomEye API密钥)",
|
||||||
"required_config": ["api_key"],
|
"required_config": ["api_key"],
|
||||||
"note": "请在YAML文件的ZOOMEYE_API_KEY配置项中填写您的API密钥,或在环境变量ZOOMEYE_API_KEY中设置。API密钥可在ZoomEye个人中心获取: https://www.zoomeye.org/user"
|
"note": "请在YAML文件的ZOOMEYE_API_KEY配置项中填写您的API密钥,或在环境变量ZOOMEYE_API_KEY中设置。API密钥可在ZoomEye个人中心获取: https://www.zoomeye.ai/user"
|
||||||
}
|
}
|
||||||
print(json.dumps(error_result, ensure_ascii=False, indent=2))
|
print(json.dumps(error_result, ensure_ascii=False, indent=2))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -174,6 +174,16 @@ args:
|
|||||||
# 格式化输出结果
|
# 格式化输出结果
|
||||||
# ZoomEye API 返回的数据在 data 字段中
|
# ZoomEye API 返回的数据在 data 字段中
|
||||||
data_list = result_data.get('data', [])
|
data_list = result_data.get('data', [])
|
||||||
|
if isinstance(data_list, dict):
|
||||||
|
nested = None
|
||||||
|
for key in ('data', 'items', 'matches', 'results', 'list', 'records'):
|
||||||
|
value = data_list.get(key)
|
||||||
|
if isinstance(value, list):
|
||||||
|
nested = value
|
||||||
|
break
|
||||||
|
data_list = nested if nested is not None else []
|
||||||
|
if not isinstance(data_list, list):
|
||||||
|
data_list = []
|
||||||
output = {
|
output = {
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"query": result_data.get('query', query),
|
"query": result_data.get('query', query),
|
||||||
|
|||||||
Reference in new issue
Block a user