
简介FofaViewer又称“佛法”是一款基于FOFA搜索引擎的批量搜索爬虫工具专为网络安全研究人员、渗透测试工程师及资产测绘人员设计可快速定位和梳理互联网公开资产辅助漏洞挖掘、攻击面分析与风险评估。其依托FOFA庞大的网络资产数据库通过图形化界面实现高效数据抓取。资源为跨平台Java工具包共2个文件fofaviewer.jar为可执行主程序内置友好界面config.properties为配置文件用于填写FOFA API Key、调节搜索限制与输出设置压缩包整体仅32.69MB体积小巧下载后即可运行。工具支持按关键字、域名、IP范围、协议类型等条件进行批量检索结果可导出为CSV或Excel便于后续数据处理同时支持定时搜索任务帮助持续监控资产变化。通过简单配置API凭证即可在界面中完成搜索、筛选、排序与导出全流程。已有2015人学习下载适合需要高效开展网络资产发现、批量数据抓取与安全分析的专业人员。1. 别再手动翻页点收藏批量网络资产搜索该交给 FofaViewer很多安全工程师查 FOFA 还停在浏览器里翻页搜完复制粘贴重复劳动全耗在点“下一页”上。FofaViewer 把 FOFA 的查询能力搬到了本地 GUI配合一份config.properties就能把批量查询、翻页、导出做成一次可重复的工程动作。我推荐它的理由不是省鼠标而是它让“整理一批网络资产”这个行为从手动劳动变成了可留痕、可回放的流程。如果你在攻防演练前收集目标系统的暴露面或是在日常监控里对比某类设备的上线情况这个工具能覆盖从构思 query 到拿到 CSV 的完整链路。当然前提是你在授权范围内使用它的数据结果。下面我从压缩包内部结构开始拆一直讲到拿它做资产变更监控中间会顺带把 FOFA 语法和几个配置参数一并讲透。2. 解包 FofaViewer_1.1.11_JDK8JDK8 适配与 config.properties 凭证链路2.1 压缩包里有什么为什么要用 JDK8解压后是典型的免安装 Java 客户端核心文件只有fofaviewer.jar和config.properties。没有注册表写入也不依赖运行时安装属于解压即用型。但这里有一个前置条件必须用 JDK 8。FofaViewer 的界面层基于 JavaFX而 JavaFX 从 JDK 11 开始被移出标准 JDK直接丢给高版本解释器会报ClassNotFoundException: javafx.application.Application。所以别看到java -version显示 17 就去启动老老实实准备一个 JDK 8u202 以上的版本。# 指定 JDK8 路径启动避免高版本 JavaFX 缺失导致闪退 /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Xms512m -Xmx1g -jar fofaviewer.jar这段命令强制指定 JDK8 的完整路径-Xms512m是堆内存初始值-Xmx1g是最大堆。GUI 客户端不需要吃太多内存1G 足够渲染几万行表格真正耗内存的是你后端解析 CSV 的过程工具本身只做请求和展示堆调太大反而拖慢启动。如果你的机器多版本共存务必写成绝对路径否则系统 PATH 里那个新版本会把启动过程拦下来。启动后主界面直接出来不需要走登录弹窗因为鉴权全部从本地配置文件读取。接下来要做的就是把 FOFA 账号凭证填进去。2.2 配置 API 凭证config.properties 的最小可跑形态FOFA 的 API 鉴权需要两个字段账号邮箱和 API Key。API Key 在 FOFA 官网个人中心里生成会员等级对应单次查询条数上限。FofaViewer 把这些信息统一收在config.properties里。不同版本包的键名可能略有差异但核心字段是固定的下面这份是最小可跑示例fofa_emailyournameexample.com fofa_api_keyxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx default_size1000 page_max5 thread_count4 timeout_sec10 export_formatcsv result_fieldshost,ip,port,protocol,title,domainfofa_email和fofa_api_key是请求签名的原材料缺一个都会在查询时收到401 auth fail。default_size控制单次请求返回条数FOFA 服务端有硬上限设 1000 是比较稳的起点想拉大之前先确认账号额度。page_max决定翻页次数理论上总数据量等于default_size * page_max但最终以账号权限和查询命中数为准。thread_count是并发线程数不要设太高FOFA 对单 IP 的 QPS 限制很严格默认 4 足够。result_fields控制返回列的顺序这直接决定导出后的列头结构。配置完成后建议不要一上来就做大范围搜索先用titletest这种窄条件试一次看右侧结果数量是否正常变化。如果搜索按钮一直无响应先确认fofa_email用的邮箱是否就是注册 FOFA 账号的那个邮箱API Key 是否在个人中心重新生成过。很多老用户手里拿的还是旧版页面的 Key已经过期但 GUI 只笼统报auth fail不会告诉你具体哪个字段失效只能两边同时替换一次。下面这张表能帮你快速定位常见启动与查询报错报错特征优先排查配置调整方向启动报 JavaFX 类缺失JDK 版本换 JDK 8u202不要用 11/17 运行查询返回401 auth failfofa_email / fofa_api_key检查 Key 是否多复制了空格或换行每次只出 100 条default_size调大确认账号额度翻到第三页报错thread_count / timeout_sec降低线程数增加超时时间导出的 xlsx 打不开export_format改用 csv 或换 Excel 插件2.3 让包里的 key 安全落地本地配置的权限边界config.properties是明文文件密钥等于直接躺在磁盘上。这个包没有做混淆或加密所以你拿到后第一步不是改参数而是收权限。Linux 和 macOS 上执行chmod 600 config.propertiesWindows 上放到当前用户目录并取消继承权限。这一步的意义在于 jar 包不内嵌任何敏感信息它在运行时现场读文件谁读得到文件谁就能用你的 FOFA 余额。常看见有人图方便把配置连同结果一起传网盘这是把数据泄露写成必然事件。正确姿势是配置文件留在本机工作目录里只保留 jar 和导出结果。到这里你已经具备跑通链路的基础JDK8 启动、配置鉴权、点击搜索。但让批量搜索真正高效的关键在查询语法FofaViewer 能发挥多少价值完全取决于你输入的 query 表达得准不准。3. 批量搜索不是粘贴关键字FOFA 查询语法与 FofaViewer 执行策略3.1 FOFA 的字段运算符是批量搜索的命门FofaViewer 只是个 GUI 壳真正决定数据质量的是 FOFA 查询表达式。很多人把网页版title后台直接粘进来以为逻辑通了实际和网页端行为差很多。FOFA API 不保留 UI 层的隐式过滤所有条件必须显式写成“字段值”条件之间用、||、!连接。最常见的批量筛选字段如下字段含义示例典型用途host主机名可带端口host.example.com圈定某个企业域名ip单个 IP 或 CIDRip1.2.3.0/24扫某个网段暴露面port端口号port3389找公网 RDP 主机protocol应用层协议protocolssh定位 SSH 服务status_codeHTTP 状态码status_code200过滤存活 Web 服务body响应体内容bodywps响应体特征识别banner底层服务指纹bannerweblogic识别非 HTTP 中间件字段与值必须用双引号包裹裸写ip1.2.3.4会直接触发 FOFA 的语法检查报错。所有逻辑符在 API 模式下必须自己写全网页端展示的标签筛选和 API 接口不是同一套语义直接把网页上复制来的条件贴进 FofaViewer有可能出现结果差异。这个字段优先级的概念同时也是后续拼 query 时的基本功。在组合条件时还要注意 FOFA API 的运算符优先级。优先级高于||但没有隐式括号。举例来说titleadmin || titlemanage countryCN的解读是前半段先做 OR再与country做 AND而不是两个 title 各自与 country 做 AND。所以我一般会给每个分支显式加括号(titleadmin || titlemanage) countryCN。这个细节在 GUI 里很容易验证在脚本里对字符串拼接尤其常见漏掉括号就可能多出大量非预期结果。批量搜索应当从宽到窄做多轮收敛。第一轮用最少条件探道路第二轮加特征第三轮拿完整表达式翻页。3.2 FofaViewer 如何把“批量”落地为可翻页任务GUI 里批量的实现看起来只是“填词、设数量、点击”但背后是 FOFA API 的search/all接口在按size和page做循环。page_max就是循环上限。工具在每页数据到达后追加渲染直到达到上限或返回结果不足一页。这个行为在脚本侧可以直接复现用 requests 请求 FOFA 接口做同样的事import requests import base64 import time email yournameexample.com api_key xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx query protocolredis countryCN fields host,ip,port,protocol # 请求头按 FOFA API 要求对查询表达式做 base64 编码 fofa_enc base64.b64encode(query.encode(utf-8)).decode(utf-8) for page in range(1, 6): params { email: email, key: api_key, qbase64: fofa_enc, fields: fields, size: 1000, page: page, } resp requests.get(https://fofa.info/api/v1/search/all, paramsparams, timeout30) data resp.json() if data.get(error) or not data.get(results): break for row in data[results]: print(row) time.sleep(2)这段代码的逻辑是每次带page参数请求 1000 条qbase64是 FOFA 规定必须对查询表达式做 base64 编码的字段fields控制返回列结构。time.sleep(2)用于降速避免在短窗口内触发限流。注意data[results]是二维数组不是字典列表因为它严格按fields的顺序输出。FofaViewer 的翻页策略和这段脚本本质相同如果你需要抓超过 GUI 能处理的数量级可以把page循环接上while直到某次返回结果数量小于size才终止。如果查询结果里包含大量看起来重复的 URL建议先检查查询条件是否太单一。比如只写domainexample.com而不带hostFOFA 可能把同一 IP 下多个虚拟主机条目全部返回看起来像重复其实每一行是不同的 Host 头。对安全测试来说这是有效数据但要交给业务部门时就按ip维度去重。FofaViewer 不会在工具内部自动去重默认把服务端原始数据原样展示去重需求只能导出后处理。3.3 组件指纹和业务搜索条件的设计一次搜索两条路设计查询之前先想清楚要的是精确还是召回。拿 Web 后台举例title管理后台的召回范围很窄很多后台标题不带这几个字这时要换成bodyadmin bodylogin做特征组合。反过来想要降低误报率就用body微信登录 bodyadmin这种强业务特征组合。FOFA 的body用于匹配 HTTP 响应体banner用于匹配端口服务的原始指纹两者不能直接互换。如果你的目标是给某个客户做资产面梳理我一般会用一组锚点查询至少包含domain、title、icon_hash其中之一再配合country和status_code做过滤。.example.com的写法会命中所有子域及其关联 IP这是做资产测绘时最高效的锚点。逐条把锚点查询在 FofaViewer 里执行结果会自动追加到视图配合去重逻辑就能拿到该目标的网络资产全貌。这里有一个值得留意的细节FOFA 的host字段是带协议和端口的完整目标domain字段是纯域名域二者在导出结果里是独立列后续处理别混用。批量搜索的真正价值是拿同一套查询周期性地去跑跑完比对差异。这要求你的查询条件写得像代码一样稳定字段顺序固定过滤条件不做临时调整。4. 结果导出与排错CSV/Excel 背后的数据治理和限速约束4.1 导出格式选择与字段对齐先把 CSV 的坑埋了FofaViewer 的导出能力覆盖 CSV 和 Excel 两种格式。实践经验是优先选 CSV。Java 导出的 CSV 编码在不同平台可能不一致Windows 下常见 GBKmacOS 下是 UTF-8Excel 直接打开可能乱码而导出为 xlsx 时某些版本会把长 IP 列自动转成文本后续在离线数据里做端口合并反而要多一步处理。正确做法是在 GUI 选 CSV再用 Python 做统一清洗import pandas as pd # 读取时统一按字符串解析防止端口被转换为浮点数 df pd.read_csv(fofa_export.csv, dtypestr) df df.drop_duplicates(subset[ip, port]) df[host] df[host].str.replace(r^https?://, , regexTrue) df df[[host, ip, port, protocol, title]] df.to_csv(fofa_clean.csv, indexFalse, encodingutf-8-sig)用dtypestr读取所有列是为了避免port被 pandas 解析成 int导致端口21变成21.0。drop_duplicates以ip和port组合作为唯一键过滤 FOFA 翻页时可能出现的重复记录。utf-8-sig输出编码带 BOM让 Excel 打开就是正常中文。不要直接在 Excel 里对结果做筛选几万行数据体量会卡死交给 pandas 最合适。导出后的表结构检查可以看下面这条验证路径检查项命令通过标准行数wc -l fofa_clean.csv等于 GUI 显示条数 1表头列数awk -F, {print NF; exit}等于result_fields列数编码file fofa_clean.csvUnicode text, UTF-8IP 是否规整cut -d, -f2 | head无 http 前缀、无 CIDR 混合4.2 那些让你以为工具坏了其实是 API 限速的场景在线服务使用过程中有三类现象很常见。第一类搜索前几页正常第三页起一直转圈多是触发了 FOFA 的单 IP 限速不是工具卡死。第二类导出文件为空但查询有结果多半是timeout_sec过短请求在客户端超时服务端已准备好数据却没传完。第三类查询结果总比网页端少这是账号等级在起作用同样的size1000普通账号可能只返回 500。处理这些问题的建议是把thread_count降到 2timeout_sec增大到 30然后使用 FofaViewer 的手动加载下一页来翻页。不要依赖 GUI 的自动连续翻页手动可以在每页之间留下人工节奏反而比线程并发更稳妥。如果换成脚本实现脚本必须加退避比如遇到rate limited就 sleep 5 秒再重试前一页请求。4.3 让导出的结果真正可用Domain 合并与端口存活验证结果拿到 CSV 里才是数据处理的开端。FOFA 返回的host经常是https://1.2.3.4:8443而domain可能是同名站点两者需要分场景使用。做资产备案时按domain分组做暴露面评估时按host反解。如果做端口存活验证不要试图用 icmp直接对ip:port发起 TCP 连接测试因为很多资产本身禁止 ping。# 过滤掉纯 IP 格式保留域名/CDN 类条目以便人工复核 cat fofa_clean.csv | awk -F, {print $1} | grep -vE ^[0-9](\.[0-9]){3} | head -50这条命令取出host列并筛掉纯 IPv4 格式剩下的是包含域名或超链接格式的行用于人工复核那些 FOFA 里没有 IP 化的资产条目。实际使用中这类条目往往对应 CDN 节点直接跳过即可。对端口存活做批量探测时只验证 FOFA 结果里的服务端口不要扫全端口这是成本最低的存活语义。另外很多人在 FOFA 结果里把protocol和port混为一谈protocol是 FOFA 识别到的应用层服务可能是 ssh、http、rdp而port是实际数字端口。两者不一致时优先相信protocol因为 FOFA 对协议识别是通过 banner 探测得到的端口可能被动过映射。比如内网某台设备公网映射到 2222FOFA 识别为 ssh端口列是 2222。导出后做端口存活验证时要用 2222 而不是 22。5. 复用导出结果做资产变更监控一次搜索与两次差分脚本FofaViewer 是 GUI 工具不适合做成常驻服务。但它的导出文件很适合做周期性快照。我拿它做资产变更监控的思路非常简单固定一条查询每周在同一个时间执行一次搜索并导出 CSV然后用脚本对比相邻两次导出的差异新增和下线资产一目了然。这么做比依赖平台订阅更贴合内部对历史数据的留痕要求。具体操作分三步。第一步在 FofaViewer 里固定result_fields和查询条件导出为week1.csv和week2.csv。第二步写一个差分脚本把每行数据转换成一个集合元组用集合运算拿到新增和消失的条目。代码示例如下import csv def parse_csv(path): with open(path, newline, encodingutf-8-sig) as f: reader csv.reader(f) # 先跳过表头避免首行参与集合运算 headers next(reader) return headers, {tuple(row) for row in reader} h1, week1 parse_csv(week1.csv) h2, week2 parse_csv(week2.csv) assert h1 h2, 列头必须一致否则结果无意义 new_assets week2 - week1 gone_assets week1 - week2 print(新增资产, len(new_assets)) print(下线资产, len(gone_assets))这段脚本的关键点是next(reader)它把表头行先读掉避免表头参与集合运算。导出文件用utf-8-sig编码后直接按行比较host、ip、port等相关字段在这一时间段内没有变化时集合长度会更稳定。列头不相同时脚本直接assert失败避免拿不同字段顺序的数据强行比较。第三步把脚本挂进定时任务。如果希望退出码能暴露差异就在文件末尾加一行sys.exit(1 if new_assets else 0)然后用系统 cron 或写批处理文件让监控端感知到结果集变化。因为 FofaViewer 手动执行是主线脚本只做后处理所以工具侧改参数不影响这个数据链路。最后一个经验是在二次检查时优先关注new_assets里那些status_code200且协议是 http/https 的条目它们才是真正暴露的 Web 资产其他诸如开放端口出去的服务往往由防火墙策略动态调整不能直接等同于业务变化。本文还有配套的精品资源点击获取