From f0fe8c4fb3c8afab3bd30055372e1a7c0da12654 Mon Sep 17 00:00:00 2001 From: shelld3v <59408894+shelld3v@users.noreply.github.com> Date: Sun, 8 May 2022 15:32:46 +0700 Subject: [PATCH] Ported FOFA to lua script implementation --- datasrcs/fofa.go | 107 --------------------------------- datasrcs/sources.go | 1 - examples/config.ini | 2 +- resources/scripts/api/fofa.ads | 98 ++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 109 deletions(-) delete mode 100644 datasrcs/fofa.go create mode 100644 resources/scripts/api/fofa.ads diff --git a/datasrcs/fofa.go b/datasrcs/fofa.go deleted file mode 100644 index 9366d45ff..000000000 --- a/datasrcs/fofa.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright © by Jeff Foley 2021-2022. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. -// SPDX-License-Identifier: Apache-2.0 - -package datasrcs - -import ( - "context" - "errors" - "fmt" - - "github.com/OWASP/Amass/v3/config" - "github.com/OWASP/Amass/v3/requests" - "github.com/OWASP/Amass/v3/systems" - "github.com/caffix/service" - "github.com/fofapro/fofa-go/fofa" -) - -// FOFA is the Service that handles access to the FOFA data source. -type FOFA struct { - service.BaseService - - SourceType string - sys systems.System - creds *config.Credentials -} - -// NewFOFA returns he object initialized, but not yet started. -func NewFOFA(sys systems.System) *FOFA { - f := &FOFA{ - SourceType: requests.SCRAPE, - sys: sys, - } - - go f.requests() - f.BaseService = *service.NewBaseService(f, "FOFA") - return f -} - -// Description implements the Service interface. -func (f *FOFA) Description() string { - return f.SourceType -} - -// OnStart implements the Service interface. -func (f *FOFA) OnStart() error { - f.creds = f.sys.Config().GetDataSourceConfig(f.String()).GetCredentials() - - if f.creds == nil || f.creds.Username == "" || f.creds.Key == "" { - estr := fmt.Sprintf("%s: Email address or API key data was not provided", f.String()) - - f.sys.Config().Log.Print(estr) - return errors.New(estr) - } - - f.SetRateLimit(1) - return nil -} - -func (f *FOFA) requests() { - for { - select { - case <-f.Done(): - return - case in := <-f.Input(): - switch req := in.(type) { - case *requests.DNSRequest: - f.CheckRateLimit() - f.dnsRequest(context.TODO(), req) - } - } - } -} - -func (f *FOFA) dnsRequest(ctx context.Context, req *requests.DNSRequest) { - if f.creds == nil || f.creds.Username == "" || f.creds.Key == "" { - return - } - - if !f.sys.Config().IsDomainInScope(req.Domain) { - return - } - - f.sys.Config().Log.Printf("Querying %s for %s subdomains", f.String(), req.Domain) - - client := fofa.NewFofaClient([]byte(f.creds.Username), []byte(f.creds.Key)) - if client == nil { - f.sys.Config().Log.Printf("%s: Failed to create FOFA client", f.String()) - return - } - - for i := 1; i <= 10; i++ { - results, err := client.QueryAsArray(uint(i), []byte(fmt.Sprintf("domain=\"%s\"", req.Domain)), []byte("domain")) - if err != nil { - f.sys.Config().Log.Printf("%s: %v", f.String(), err) - return - } - if len(results) == 0 { - break - } - - for _, res := range results { - genNewNameEvent(ctx, f.sys, f, res.Domain) - } - f.CheckRateLimit() - } -} diff --git a/datasrcs/sources.go b/datasrcs/sources.go index 04b48e7cd..1da6a95ca 100644 --- a/datasrcs/sources.go +++ b/datasrcs/sources.go @@ -22,7 +22,6 @@ func GetAllSources(sys systems.System) []service.Service { NewAlienVault(sys), NewCloudflare(sys), NewDNSDB(sys), - NewFOFA(sys), NewNetworksDB(sys), NewRADb(sys), NewTwitter(sys), diff --git a/examples/config.ini b/examples/config.ini index 56063d975..ec0db6361 100644 --- a/examples/config.ini +++ b/examples/config.ini @@ -210,7 +210,7 @@ minimum_ttl = 1440 ; One day #apikey = #secret = -# https://fofa.so (Paid) +# https://fofa.info (Paid) #[data_sources.FOFA] #ttl = 10080 #[data_sources.FOFA.Credentials] diff --git a/resources/scripts/api/fofa.ads b/resources/scripts/api/fofa.ads new file mode 100644 index 000000000..c4919f493 --- /dev/null +++ b/resources/scripts/api/fofa.ads @@ -0,0 +1,98 @@ +-- Copyright 2022 Jeff Foley. All rights reserved. +-- Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +local json = require("json") +local url = require("url") + +name = "FOFA" +type = "api" + +function start() + set_rate_limit(1) +end + +function check() + local c + local cfg = datasrc_config() + if cfg ~= nil then + c = cfg.credentials + end + + if (c ~= nil and c.username ~= nil and + c.key ~= nil and c.username ~= "" and c.key ~= "") then + return true + end + return false +end + +function vertical(ctx, domain) + local c + local cfg = datasrc_config() + if cfg ~= nil then + c = cfg.credentials + end + + if (c == nil or c.username == nil or + c.username == "" or c.key == nil or c.key == "") then + return + end + + local p = 1 + while(true) do + local resp, err = request(ctx, { + ['url']=build_url(domain, c.username, c.key, p) + }) + if (err ~= nil and err ~= "") then + log(ctx, "vertical request to service failed: " .. err) + return + end + + local j = json.decode(resp) + if (j == nil or j.error == true or j.size == 0) then + if (j.errmsg ~= nil and j.errmsg ~= "") then + log(ctx, "vertical request to service failed: " .. j.errmsg) + end + + return + end + + for _, result in pairs(j.results) do + send_names(ctx, result) + end + + if j.size < 10000 then + return + end + i = i + 1 + end +end + +function build_url(domain, username, key, pagenum) + local query = base64_encode("domain=\"" .. domain .. "\"") + local params = { + ['full']="true", + ['fields']="host", + ['size']="10000", + ['page']=pagenum, + ['email']=username, + ['key']=key, + ['qbase64']=query, + } + + return "https://fofa.info/api/v1/search/all?" .. url.build_query_string(params) +end + +function base64_encode(data) + local b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + + return ((data:gsub('.', function(x) + local r,b='',x:byte() + for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end + return r; + end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) + if (#x < 6) then return '' end + local c=0 + for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end + return b:sub(c+1,c+1) + end)..({ '', '==', '=' })[#data%3+1]) +end