FOFA cyberspace mapping for the agent: `fofa_account` reports the account quota, `fofa_search` runs one FOFA query and returns the matching rows plus the total match count, and `fofa_export` pages the full result set with a time cursor and writes CSV, JSON or TXT files incrementally into the session workspace; a CSV or TXT export that stopped at the time budget or on an upstream error can continue into the same file from its saved cursor. The API key is saved from the plugin page into the harness credential store.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:keyblues/dsh-fofatoto
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
This plugin publishes its README in Chinese only.
fofatoto(FOFA 网络空间测绘)的 DeepSeek Harness 插件:把 fofatoto 里真正值钱的 FOFA 查询语义搬进 DSH,让 Agent 直接调用工具,而不是拼 shell 调 exe。
- 包名:
dsh-fofatoto(Host + Web Client 双半) - 工具:
fofa_account、fofa_search、fofa_export(三个) - 插件页配置卡片:粘贴 API Key,写入 Harness 凭据库,不回显
- 对话卡片:三个工具各有默认收起的卡片(账号配额 / 语句 + 命中数 / 语句 + 行数),样式与 DSH 内置工具卡一致(同一套行头 + 详情卡结构、主题 token 与运行态扫光)
安装(DSH Desktop)
DSH Desktop 支持直接输入仓库地址安装:
打开侧边栏「插件」页;
点右上角「添加插件」→「安装第三方插件」;
在「包名或地址」里输入本仓库地址:
https://github.com/keyblues/dsh-fofatoto安装完成后进入本插件详情页,在配置卡片里粘贴 FOFA API Key(写入 Harness 凭据库,不落配置文件);
工具随插件自动注册:
fofa_account/fofa_search/fofa_export。
要求:Node.js ≥ 20(DSH 内置即可)、DSH >=0.2.1-rc.3 <0.3.0-0。
开发时可填本地目录绝对路径(DSH 会以 link: 方式安装),改完代码重载 bundle 即可生效。
更新插件后需要重启 DSH:运行中的进程不会重新加载已修改的 Host 模块。
从 fofatoto 移植了什么
| 已移植(JS 原生实现,无 Python 依赖) | 说明 |
|---|---|
FofaClient.search 语义 |
qbase64 编码、fields 归一、自定义 url 字段剥离、域名推断、错误分类与重试退避 |
search_all_efficient |
before="时间" 游标深翻页(可破 1 万条)、按 host 去重、批次限速、fill 比例 |
| 额度查询与中转站识别 | 内置 RELAY_INFO_APIS 域后缀匹配 + 官方兜底(与 fofatoto 一致,不引入额外配置);响应字段做多别名归一 |
| 导出器 | CSV(UTF-8 BOM,Excel 友好)、JSON、TXT(URL/IP/域名列表)、去重字段合并 |
字段全集 / build_url / 时间游标 |
逐条对齐,含 http,https 这类脏 protocol 的处理 |
| 未移植(刻意) | 原因 |
|---|---|
| 本地 Web UI、web_auth、登录限流 | DSH 已有 Web UI,本插件用插件页卡片代替 |
| CLI / argparse / banner / 进度条 / 配色 | 无终端界面需求 |
| GitHub 更新检查、自动升级 | 由 DSH 的 plugin manager 负责 |
批量文件模式(-b/-p) |
Agent 自己就能循环调用 fofa_export,或合并 ` |
favicon / icon_hash 查询(--icon) |
抓图标、算 murmur3、SSRF 防护是纯冗余:模型用 shell 调 fofatoto --icon 或 favicon_hash() 出 hash,再把 icon_hash="..." 交给 fofa_search 即可 |
移植代码与 fofatoto 同源(GPL-3.0),故本插件沿用 GPL-3.0-or-later。
工具
fofa_account — 查额度(不耗额度)
无参数。返回账户类型(官方/中转站)、Key 是否有效、今日剩余、剩余查询、到期时间、首次使用、Key 来源。测绘前先调它,和 fofatoto -c 等价。
fofa_search — 单页检索(1 次额度/调用)
| 参数 | 说明 |
|---|---|
query |
必填。FOFA 语句,如 domain="a.com" && port="443" |
size |
返回条数 1–10000,默认 50 |
page |
页码,默认 1(深翻页不稳定,全量请用 export) |
fields |
逗号分隔字段,默认 host,ip,port,protocol,domain,title(默认不含 server,需要时显式加);支持本地拼接的 url |
full |
是否 full 数据(含一年前),默认 false |
返回:匹配总数、本页行(对象数组)、IP 去重数;模型侧输出为紧凑 JSON(见下)。
输出格式(模型侧:一行摘要 + 紧凑 JSON;Web 侧:专用卡片)
三个工具的 output.render 都返回 「一行中文摘要 + 紧凑 JSON」:
- 摘要行让模型最快定位结果(账号状态/命中数/导出结论),JSON 与
output.schema一一对应,机器可直接解析,PTC 模式拿到的也是同一个规范值; - 官方
plugin_manager等数据型工具同样返回紧凑 JSON,这里只是在前面加了一行不参与解析的摘要; output.schema声明了全部字段(additionalProperties: false),nextBefore是string | null(null= 没有剩余数据,可直接appendTo续拉)。
样例(摘要行 + 省略的 JSON 体):
fofa_account:中转站 · Key 有效 · 今日剩余 91 · 剩余查询 不限 · 到期 2026-12-01fofa_search:命中 67 条 · 本页 2 条 · 去重 IP 1fofa_export:导出完成 · csv · 2 行 → C:\...\fofa-output\fofa_results_20261030_153000.csvfofa_export未拉完:导出未完成(time-budget) · csv · 10000 行 · 总匹配 25000 → …(可 appendTo 续拉)
Web 端在 tool.call.toolview keyed slot 里注册了三张专用卡片(不再走 generic 行):默认收起,
点击行头展开。行头、展开体和运行态都照抄 DSH 内置工具卡的实现(DisclosureRow 行头 + ToolDetails
详情卡 + TextShimmer 扫光),只用主题 token 上色,所以和内置工具卡混在一起不会突兀:
- 行头:工具字形(账号=地球、检索=放大镜、导出=下载)→ 标题 → 小圆点(8px 留白)→ 摘要 → 统计后缀
(4px 留白),和内置
ToolRow的summary+summarySuffix同构;悬停时字形换成展开箭头,颜色从 三级文字变二级;运行中标题、摘要一起做左→右扫光;失败时摘要用错误色,不额外加状态胶囊(内置卡片也不加)。 - 行头只留两个事实(做了什么 + 一句话统计),其余都在展开体里:
- 检索:
domain="baidu.com"+命中 78719 条; - 导出:
domain="baidu.com"+5 行(未拉完时后缀追加「部分完成」); - 账号:
中转站+今日剩余 100(Key 是否有效交给展开体的徽标和失败时的红色摘要); - 失败直接显示错误摘要;执行中显示语句或「执行中」。
- 检索:
- 展开体:一张官方样式的详情卡(细边框 + 大圆角 + 代码块底色),第一块是查询配置,后面是结果/文件:
- 检索:
语句(等宽)、条数、页码、字段、去重 IP,下面是本页最多 8 行结果(主机名为等宽主行, 次行为ip:port · 标题),超出部分提示…另有 N 行;本页没有结果时显示「本页没有结果。」; - 导出:
语句、条数上限(0 = 全部,缺省 = 默认 1000,带fill/full时一并显示)、字段、格式、去重字段,第二块是文件路径(等宽、可点击打开)与已写入/总匹配/接口调用/耗时/停止原因/游标; - 账号:首行是账户类型 + 有效/无效徽标,次行是
HTTP 200 · 来源 · 接口地址,字段为今日剩余、剩余查询、 到期、首次使用、VIP 等级、服务器。
- 检索:
- 尚未开始执行(
preparing)时只显示一行、不可展开;执行中可展开看到已到达的请求参数;失败时展开是 「错误」面板(错误色文本),只有结果完全解析不了时才退回「输出」面板;结果过大落盘时仍是详情卡 + 「结果过大已落盘」提示。
样式实现说明:内置卡片所在的 @deepseek-ai/dsh-client-ui-primitives 不允许被第三方插件当模块加载,
所以行头/详情卡/扫光的标记与 CSS 是从已安装的内置包里照着抄(类名改成插件自己的 fft_ 前缀),
颜色只引用主题 token(--dsw-alias-*、--dsw-radius-*、--dsw-font-*、--dsh-content-font-*)。
test/client-card.test.mjs 有一条用例守着「字面色值(#hex / rgb() / hsl())不出现、var() 只引用主题
token 前缀」这条约束,但它只能做静态前缀检查,无法证明 token 一定被主题定义。
与内置卡片的已知差异(有意为之,不影响观感一致性):没有 Inspect 按钮;详情卡列表不封顶 320px 滚动 (直接展开全部 8 行预览);导出文件的快捷入口在展开体里而不是收起行头(内置文件类工具在行头直接点开文件, 这里优先保留「语句 + 行数」摘要);行头只有整行点击一种展开方式。
查询配置来自调用参数(未在 output 里重复保存),旧会话日志里的纯 JSON 结果仍能正常回放。
结果过大时(例如 fofa_search size=1000)Harness 会把模型可见内容 spill 落盘,模型只看到预览 + 路径;
三个工具的 output.presentationMeta 另外持久化了一份有界的卡片事实(检索为 rowCount + 最多 8 行预览,
导出为文件/统计/游标),所以卡片在这种情况下仍能正常显示配置、条数和预览表,并提示「结果过大已落盘」。
fofa_export — 全量落盘(按批次数耗额度,增量写盘)
| 参数 | 说明 |
|---|---|
query |
必填。多目标可用 || 合并:domain="a.com" || domain="b.com" || ip="1.2.3.4"。续拉时可省略(沿用元数据) |
limit |
最多拉取条数,默认 1000;0 表示按总数(受 maxExportRows 保护);续拉时表示本次新增条数 |
format |
csv(默认)/json/txt |
fields |
同上,url 会自动拼好 |
dedup |
去重字段,默认按导出字段;常用 url、ip、ip,host、domain |
fill |
拉取比例 (0,1],默认 1;总量极大时用 0.8 省额度 |
fileName |
输出文件名(不含目录),缺省 fofa_results_<时间戳> |
appendTo |
断点续拉:传上次返回的 path,从保存的游标继续追加到同一文件(JSON 不支持) |
full |
是否 full 数据 |
行为:先 size=1 查总数 → 按 before="时间" 游标分页(每批 ≤1 万,批间隔默认 5s)→ 按 host 去重 → 写入 <会话工作区>/fofa-output/(可配 outputDir),重名自动 _1、_2。每批结果写完即 fsync,文件旁边还有 <文件>.meta.json 侧车记录格式/字段/游标,供续拉使用。
超时与数据安全
导出可能跑很久(深翻页、代理慢、中转站限流都会拖时间),所以做了三层保护:
- 每批立即落盘并 fsync:不是"全部拉完再写文件"。第 1 批写完哪怕第 2 批卡死,前 1 批也已经在磁盘上。
- 自己的时间预算(
maxExportSeconds,默认 240s):到点在批次之间主动收尾,返回partial: true、stoppedReason: "time-budget",并给出nextBefore游标——已经拉到的行完整保留。工具超时被设为maxExportSeconds + 60,正常情况下预算先生效,不会撞上 DSH 的TOOL_TIMEOUT。 - 断点续拉:
fofa_export appendTo="<上次的 path>" limit=<条数>从 meta 里的游标继续,追加到同一文件(不重复写表头),且跳过总数查询(省 1 次额度),已拉过的行不会重复消耗。
其他行为:
- 中途 HTTP 失败但已有数据 → 不抛错,返回
partial: true、stoppedReason: "upstream-error"+ 已落盘文件路径。 - 用户取消 / 进程重启:文件里是最后一个完整批次,最多丢正在写的那一批(批内一次写入,不会半行)。
- 成功但零结果 → 保留空文件与 meta(
stoppedReason: "empty");硬失败且一行未写 → 删除空文件,直接报错。 - 列顺序固定为「请求字段 + 去重字段」,JSON 用
[]闭合、CSV 带 UTF-8 BOM、TXT 按ip/domain/url自动选模式。 nextBefore为 FOFA 时间游标(YYYY-MM-DD HH:MM:SS),按-1s步进,与 fofatoto 一致。
本地开发与验证
node --check index.js
node --check client.js
node --test test/ # 单元测试;3 个 live 用例需 FOFA_TEST_KEY,默认 skip
在 DSH 里用 plugin_manager install_bundle 指向本目录可做 link 安装(开发调试用)。
配置
配置项都在 cordis.patch.yml 的 config 里,全部可选:
| 键 | 默认 | 说明 |
|---|---|---|
baseUrl |
https://fafaapi.info |
接口地址。默认按中转站配置;官方账号改 https://fofa.info;也可在插件页卡片直接改(持久化到本 profile 的 cordis.patch.yml,热重载生效) |
credentialRef |
FOFA_API_KEY |
凭据库引用名 |
apiKeyEnv |
FOFA_KEY |
环境变量名 |
apiKey |
空 | 直接写 Key(优先级最高,不推荐) |
timeoutMs |
45000 | 单次 HTTP 超时 |
retries |
2 | 单次请求重试次数 1–4 |
defaultFields |
host,ip,port,protocol,domain,title |
默认字段(不含 server) |
outputDir |
空 | 空 = <工作区>/fofa-output |
maxExportRows |
50000 | 单次导出条数上限 |
maxExportSeconds |
240 | 单次导出时间预算(秒,5–540);到点主动收尾,数据已落盘 |
rateLimitSeconds |
5 | 深翻页批次间隔 |
fofatotoConfigPath |
空 | 指向本机 fofatoto 的 config.json,未配置 Key 时复用其中 key |
Key 解析顺序:config.apiKey → 凭据库 FOFA_API_KEY → 环境变量 FOFA_KEY → fofatotoConfigPath 的 config.json。
推荐:在「插件」页打开 FOFATOTO 详情,粘贴 Key 保存(写入 Harness 凭据库,不落 profile 配置、不回显,卡片只显示尾号)。
接口地址与账号信息接口(按 fofatoto 规则)
接口地址 baseUrl 可配置:既决定搜索接口(/api/v1/search/all),也决定账号接口的基址。可在插件页卡片里直接改(保存走 Host configEditor:原子写本 profile 的 cordis.patch.yml + Loader 热重载),也可以写 YAML。
账号信息接口不参与配置,与 fofatoto 一致:代码里内置 RELAY_INFO_APIS 表,按域名后缀匹配(host === domain || host.endsWith('.' + domain),先命中先用):
| baseUrl | 检测结果 |
|---|---|
https://fafaapi.info(或任意 *.fafaapi.info) |
中转站:{base_url}/fofaapi/v1/validate-key?key={key} |
其他(https://fofa.info 等) |
官方:{base_url}/api/v1/info/my?key={key} |
要接入新的中转站,按 fofatoto 的方式改代码里这一张表即可(index.js 的 RELAY_INFO_APIS),不新增配置项。响应字段按 fofatoto 的归一化口径读取(valid/isvip、todayRemaining、totalRemaining/remain_api_query、expireTime/expiration、firstUsedAt),部分中转站把字段包在 data 里也能读。
「测试连接」支持用未保存的接口地址试通再存;configEditor 不可用的环境里接口地址输入会置灰并提示改 YAML(Key 仍可单独保存)。
切换官方账号:在本 profile 的 cordis.patch.yml 追加
- id: dsh-fofatoto
config:
baseUrl: https://fofa.info
与资产收集流程对接
对应 asset-collection skill 第②阶段:
fofa_account 看今日剩余,规划查询数
→ fofa_search domain="…" 看总量/样本,验证语句
→ fofa_export 落盘 CSV(--full --dedup url 等价参数都在)
→ fofa_icon 的位置改为:fofatoto --icon <url> → icon_hash="…" → fofa_search
老命令对照:
fofatoto.exe -c
→ fofa_account
fofatoto.exe 'domain="a.com"' -l 10000 -csv -f url --dedup url --full -o out.csv
→ fofa_export query='domain="a.com"' limit=10000 format=csv fields=url dedup=url full=true
安全与边界
- API Key 只存在本机(凭据库/环境变量/你的 fofatoto 配置),不写日志、不回显、不随工具结果返回。
- 插件路由与插件页同源,且要求自定义请求头,跨站页面无法静默改写 Key。
- 导出文件落在会话工作区内,文件名做了目录穿越过滤。
- 额度保护:
maxExportRows上限 +fofa_account前置检查;fofa_export并发不安全(同时多次导出会互相抢额度)。
许可
GPL-3.0-or-later。查询语义移植自同样以 GPL-3.0 发布的 fofatoto(同一作者)。
Links
More in this category
kenryu42/cc-safety-net★ 1900
Pre-execution guard that blocks destructive Git and filesystem commands and access to secrets such as SSH keys and .env files before a tool call runs.
ADWMC/helm-d#helmd★ 984
Security-analysis plugin for DeepSeek Harness: 33 tools spanning six security domains, evidence/reporting and toolbox, plus the case lifecycle, routing and tool ledger; a session-bound case workflow with an evidence chain, E-id validation and reproducible findings; 362 on-demand references; three hot-swappable persona profiles; and a four-tab workbench (armor / case / intercept / about) with case-state recovery after context compaction.
toby-bridges/api-relay-audit★ 904
Runs local security audits of AI API relays and LLM proxies from DeepSeek Harness, producing Markdown reports for prompt injection, model substitution signals, tool-call rewriting, error leakage, stream integrity, and profile-gated Web3 risks.
SeaOf0/dsh-redteam-model★ 807
Authorized-security DSH collection: nine work modes (redteam coordinator, pentest, code audit, binary analysis, attack-defense, AV evasion, incident response, cloud security, CTF solving) and fifteen runtime plugins, managed from a settings page with one-click deploy, install, update and uninstall.
howmp/dsh-pentest★ 616
Authorized pentest mode for DeepSeek Harness — exploration chain, assets and findings with a Web view.
PerryLink/dsh-auto-review★ 244
Second-model auto-review on the approval answerer chain: a read-only reviewer subagent returns structured allow/deny verdicts with reasons, fail-closed by default.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.