本文最后更新于 2025-02-10,墨迹未干时,知识正鲜活。随着时间推移,文章部分内容可能需要重新着墨,请您谅解。Contact

自部署FOFA

源码如下:

  • 友情提示:源码可以折叠,下面有我已经部署好的,可以开箱即用
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  // HTML content
  const html = `
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>FOFA 查询工具</title>
    <style>
        body {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            font-family: Arial, sans-serif;
        }
        .container {
            border: 1px solid #ddd;
            padding: 20px;
            border-radius: 5px;
        }
        .input-group {
            margin-bottom: 15px;
        }
        input[type="text"], input[type="number"] {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-sizing: border-box;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            width: 100%;
        }
        button:hover {
            background-color: #45a049;
        }
        #results {
            margin-top: 20px;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            min-height: 100px;
            white-space: pre-wrap;
            font-family: monospace;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>FOFA 查询工具</h2>
        
        <div class="input-group">
            <input type="text" id="query" name="query" placeholder="请输入关键词">
        </div>
        
        <div class="input-group">
            <input type="text" id="field" name="field" placeholder="field:例如host,link,ip,country_name" value="ip">
        </div>
        
        <div class="input-group">
            <input type="number" id="size" name="size" value="100" placeholder="size">
        </div>
        
        <div class="input-group">
            <input type="number" id="page" name="page" value="1" hidden>
        </div>
        
        <button onclick="query()">查询</button>
        
        <div id="results" title="点击复制内容" onclick="copyResults()"></div>
    </div>

    <script>
        async function query() {
            const query = document.getElementById('query').value;
            const field = document.getElementById('field').value;
            const size = document.getElementById('size').value;
            const page = document.getElementById('page').value;

            if (!query) {
                document.getElementById('results').innerHTML = '错误: 关键词不能为空';
                return;
            }

            document.getElementById('results').innerHTML = '查询中...';

            try {
                const response = await fetch('/api/fofa', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        query,
                        field,
                        size,
                        page
                    })
                });

                const data = await response.json();

                if (!data.error && data.results) {
                    const resultsHtml = data.results.join('\\n');
                    
                    document.getElementById('results').innerHTML = resultsHtml || 'No results found';
                } else if (data.errmsg) {
                    document.getElementById('results').innerHTML = '错误: ' + data.errmsg;
                } else {
                    document.getElementById('results').innerHTML = '错误: ' + (data.error || '未知错误');
                }
            } catch (error) {
                document.getElementById('results').innerHTML = '查询出错: ' + error.message;
            }
        }

        function copyResults() {
            const results = document.getElementById('results');
            navigator.clipboard.writeText(results.innerText.replace(/^\d+\. /, ''))
                .then(() => alert('已复制到剪贴板'))
                .catch(err => alert('复制失败: ' + err));
        }
    </script>
</body>
</html>
  `;

  // Handle API requests
  if (request.url.includes('/api/fofa')) {
    if (request.method === 'POST') {
      try {
        const { query, field, size, page } = await request.json();
        
        if (!query) {
          return new Response(JSON.stringify({ error: '关键词不能为空' }), {
            headers: { 
              'Content-Type': 'application/json',
              'Access-Control-Allow-Origin': '*'
            }
          });
        }

        const email = "[email protected]";  
        const apiKey = "cxxxxx【你的FOFA -API-KEY】xxxxxxxx";

        const encodedQuery = btoa(query);
        const url = `https://fofa.info/api/v1/search/all?email=${encodeURIComponent(email)}&key=${encodeURIComponent(apiKey)}&qbase64=${encodedQuery}&fields=${field}&size=${size}&page=${page}`;
        
        const response = await fetch(url);
        const data = await response.json();

        if (data.error) {
          return new Response(JSON.stringify({ error: data.errmsg || '查询失败' }), {
            headers: { 
              'Content-Type': 'application/json',
              'Access-Control-Allow-Origin': '*'
            }
          });
        }
        
        return new Response(JSON.stringify(data), {
          headers: { 
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
          }
        });
      } catch (error) {
        return new Response(JSON.stringify({ error: error.message }), {
          headers: { 
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
          }
        });
      }
    }
  }

  // Return the HTML page for all other requests
  return new Response(html, {
    headers: {
      'Content-Type': 'text/html',
    },
  });
}

将以上源码直接复制粘贴到cloudflare workers里部署即可,也可以修改为Html部署到静态托管网站。
成品如下,搭配KEY使用可免去无FOFA订阅烦恼:
https://fofa.lichensheng.us.kg/

屏幕截图 2024-11-26 100214.png

FOFA语法详解:

title="beijing"

从标题中搜索 "北京"

header="elastic"

从 HTTP 头中搜索 "elastic"

body="网络空间测绘"

从 HTML 正文中搜索 "网络空间测绘"

domain="qq.com"

搜索根域名带有 qq.com 的网站

icon_hash="-247388890"

搜索使用此 icon 的资产。仅限 FOFA 高级会员使用

host=".gov.cn"

从 URL 中搜索 ".gov.cn"。搜索要用 host 作为名称

port="6379"

查找对应 6379 端口的资产

icp="京ICP证030173号"

查找备案号为 "京ICP证030173号" 的网站。搜索网站类型资产

ip="1.1.1.1"

从 IP 中搜索包含 1.1.1.1 的网站。搜索要用 ip 作为名称

ip="220.181.111.1/24"

查询 IP 为 220.181.111.1 的 C 网段资产

status_code="402"

查询服务器状态为 402 的资产

protocol="quic"

查询 quic 协议资产。搜索指定协议类型(在开启端口扫描的情况下有效)

country="CN"

搜索指定国家(编码)的资产

region="HeNan"

搜索指定行政区的资产

city="HanDan"

搜索指定城市的资产

cert="baidu"

搜索证书(https 或者 imaps 等)中带有 baidu 的资产

cert.subject="Oracle Corporation"

搜索证书持有者是 Oracle Corporation 的资产

cert.issuer="DigiCert"

搜索证书颁发者为 DigiCert Inc 的资产

cert.is_valid=true

验证证书是否有效,true 有效,false 无效,仅限 FOFA 高级会员使用

banner=users && protocol=ftp

搜索 FTP 协议中带有 users 文本的资产

type=service

搜索所有协议资产,支持 subdomainservice 两种

os="centos"

搜索操作系统为 CentOS 资产

server=="Microsoft-IIS/10"

搜索 IIS 10 服务器

app="Microsoft-Exchange"

搜索 Microsoft-Exchange 设备

after="2017" && before="2017-10-01"

时间范围段搜索

asn="19551"

搜索指定 asn 的资产

org="Amazon.com, Inc."

搜索指定 org(组织)的资产

base_protocol="udp"

搜索指定 udp 协议的资产

is_fraud=false

排除仿冒/欺诈数据

is_honeypot=false

排除蜜罐数据,仅限 FOFA 高级会员使用

is_ipv6=true

搜索 ipv6 的资产,只接受 truefalse

is_domain=true

搜索域名的资产,只接受 truefalse

port_size="6"

查询开放端口数量等于 "6" 的资产,仅限 FOFA 会员使用

port_size_gt="6"

查询开放端口数量大于 "6" 的资产,仅限 FOFA 会员使用

port_size_lt="12"

查询开放端口数量小于 "12" 的资产,仅限 FOFA 会员使用

ip_ports="80,161"

搜索同时开放 80161 端口的 ip 资产(以 ip 为单位的资产数据)

ip_country="CN"

搜索中国的 ip 资产(以 ip 为单位的资产数据)

ip_region="Zhejiang"

搜索指定行政区的 ip 资产(以 ip 为单位的资产数据)

ip_city="Hangzhou"

搜索指定城市的 ip 资产(以 ip 为单位的资产数据)

ip_after="2021-03-18"

搜索 2021-03-18 以后的 ip 资产(以 ip 为单位的资产数据)

ip_before="2019-09-09"

搜索 2019-09-09 以前的 ip 资产(以 ip 为单位的资产数据)