uncover logic refactor to v0.0.4 (#3663)

* uncover logic refactor to v0.0.4

* remove deprecated import: stringsutil
dev
Tarun Koyalwar 2023-05-09 03:57:56 +05:30 committed by GitHub
parent abc1d595ac
commit c62dc01f9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 235 deletions

View File

@ -230,7 +230,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.UncoverEngine, "uncover-engine", "ue", nil, fmt.Sprintf("uncover search engine (%s) (default shodan)", uncover.GetUncoverSupportedAgents()), goflags.FileStringSliceOptions), flagSet.StringSliceVarP(&options.UncoverEngine, "uncover-engine", "ue", nil, fmt.Sprintf("uncover search engine (%s) (default shodan)", uncover.GetUncoverSupportedAgents()), goflags.FileStringSliceOptions),
flagSet.StringVarP(&options.UncoverField, "uncover-field", "uf", "ip:port", "uncover fields to return (ip,port,host)"), flagSet.StringVarP(&options.UncoverField, "uncover-field", "uf", "ip:port", "uncover fields to return (ip,port,host)"),
flagSet.IntVarP(&options.UncoverLimit, "uncover-limit", "ul", 100, "uncover results to return"), flagSet.IntVarP(&options.UncoverLimit, "uncover-limit", "ul", 100, "uncover results to return"),
flagSet.IntVarP(&options.UncoverDelay, "uncover-delay", "ucd", 1, "delay between uncover query requests in seconds (0 to disable)"), flagSet.IntVarP(&options.UncoverRateLimit, "uncover-ratelimit", "ur", 60, "override ratelimit of engines with unknown ratelimit (default 60 req/min)"),
) )
flagSet.CreateGroup("rate-limit", "Rate-Limit", flagSet.CreateGroup("rate-limit", "Rate-Limit",

View File

@ -26,8 +26,7 @@ require (
github.com/projectdiscovery/interactsh v1.1.3 github.com/projectdiscovery/interactsh v1.1.3
github.com/projectdiscovery/rawhttp v0.1.11 github.com/projectdiscovery/rawhttp v0.1.11
github.com/projectdiscovery/retryabledns v1.0.24 github.com/projectdiscovery/retryabledns v1.0.24
github.com/projectdiscovery/retryablehttp-go v1.0.15 github.com/projectdiscovery/retryablehttp-go v1.0.16
github.com/projectdiscovery/stringsutil v0.0.2 // indirect
github.com/projectdiscovery/yamldoc-go v1.0.4 github.com/projectdiscovery/yamldoc-go v1.0.4
github.com/remeh/sizedwaitgroup v1.0.0 github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.5.0 github.com/rs/xid v1.5.0
@ -78,8 +77,8 @@ require (
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
github.com/projectdiscovery/sarif v0.0.1 github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.0.9 github.com/projectdiscovery/tlsx v1.0.9
github.com/projectdiscovery/uncover v1.0.2 github.com/projectdiscovery/uncover v1.0.4
github.com/projectdiscovery/utils v0.0.27 github.com/projectdiscovery/utils v0.0.28
github.com/projectdiscovery/wappalyzergo v0.0.92 github.com/projectdiscovery/wappalyzergo v0.0.92
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.2
gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/src-d/go-git.v4 v4.13.1
@ -241,7 +240,6 @@ require (
github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/imdario/mergo v0.3.13 // indirect github.com/imdario/mergo v0.3.13 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect

View File

@ -255,8 +255,6 @@ github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUD
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4= github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4=
github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6457fz1+xXYIWDxdGc7HdkLS9aJ1skk= github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6457fz1+xXYIWDxdGc7HdkLS9aJ1skk=
@ -440,19 +438,18 @@ github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gB
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg= github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
github.com/projectdiscovery/retryabledns v1.0.24 h1:CbC0a1EcyRDBcGFHZDGfW5orkWkOCfa0mAMF060XJpI= github.com/projectdiscovery/retryabledns v1.0.24 h1:CbC0a1EcyRDBcGFHZDGfW5orkWkOCfa0mAMF060XJpI=
github.com/projectdiscovery/retryabledns v1.0.24/go.mod h1:bCmv0neiqgemgmFChevfX2BgCxIp8sn5OnbwL1Gov9M= github.com/projectdiscovery/retryabledns v1.0.24/go.mod h1:bCmv0neiqgemgmFChevfX2BgCxIp8sn5OnbwL1Gov9M=
github.com/projectdiscovery/retryablehttp-go v1.0.15 h1:kP9x9f++QimRwb8ABqnI1dhEymvnZXS2Wp2Zs4rWk/c= github.com/projectdiscovery/retryablehttp-go v1.0.16 h1:xrEK9VVkLf0eN4bYOTc2Pg0qRqz47g8T823vqpCIsl8=
github.com/projectdiscovery/retryablehttp-go v1.0.15/go.mod h1:+OzSFUv3sQcPt+MgbNx6X/Q3ESxqPUQSphqG5kxoIgI= github.com/projectdiscovery/retryablehttp-go v1.0.16/go.mod h1:9m76To4lNgBtVfqADzLxZg1wWajv6y/uYMWCOs1Olo8=
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us= github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ= github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA= github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
github.com/projectdiscovery/stringsutil v0.0.2/go.mod h1:EJ3w6bC5fBYjVou6ryzodQq37D5c6qbAYQpGmAy+DC0=
github.com/projectdiscovery/tlsx v1.0.9 h1:StUwVpPG0lrXq6FvxbFarPM+fu9Vke1sOPoyJcBVOFA= github.com/projectdiscovery/tlsx v1.0.9 h1:StUwVpPG0lrXq6FvxbFarPM+fu9Vke1sOPoyJcBVOFA=
github.com/projectdiscovery/tlsx v1.0.9/go.mod h1:4vGhl8lxUWjXuyoVvnL2ObMY/FSrb9Mpx5U2KaTV05A= github.com/projectdiscovery/tlsx v1.0.9/go.mod h1:4vGhl8lxUWjXuyoVvnL2ObMY/FSrb9Mpx5U2KaTV05A=
github.com/projectdiscovery/uncover v1.0.2 h1:mRFzflYyvwKkHd3XKufMlDRrb6p1mjFZTSHoNAUpFwo= github.com/projectdiscovery/uncover v1.0.4 h1:d0lUNcnqDMfG4gR/WP2+UoQKLVmLE7opBiwnmI7ir/0=
github.com/projectdiscovery/uncover v1.0.2/go.mod h1:lz4QYfArSA6jJkXyB71kN2/Pc7IW7nJB8c95n7xtwqY= github.com/projectdiscovery/uncover v1.0.4/go.mod h1:fvSHBhj8zZFEXGOhQIpPe5j5LtDXI7adOns1iFJ5TTY=
github.com/projectdiscovery/utils v0.0.3/go.mod h1:ne3eSlZlUKuhjHr8FfsfGcGteCzxcbJvFBx4VDBCxK0= github.com/projectdiscovery/utils v0.0.3/go.mod h1:ne3eSlZlUKuhjHr8FfsfGcGteCzxcbJvFBx4VDBCxK0=
github.com/projectdiscovery/utils v0.0.27 h1:HfLjy1ZuWWtGfLW5ixHcgWPqybuJhPltpHnHeBID2QQ= github.com/projectdiscovery/utils v0.0.28 h1:lFTXbW/SZX3vjmCjReCdvbi5Fj46gCU3egdp098tHzo=
github.com/projectdiscovery/utils v0.0.27/go.mod h1:RpMyTA/KACEBK+Bo9mk9MgLH0Hfc+BZtSlZ4T9bjLBE= github.com/projectdiscovery/utils v0.0.28/go.mod h1:RpMyTA/KACEBK+Bo9mk9MgLH0Hfc+BZtSlZ4T9bjLBE=
github.com/projectdiscovery/wappalyzergo v0.0.92 h1:IQgYS3xN6J9KKq1FjMVjso+gVchhPBqi/wzChYrr1JA= github.com/projectdiscovery/wappalyzergo v0.0.92 h1:IQgYS3xN6J9KKq1FjMVjso+gVchhPBqi/wzChYrr1JA=
github.com/projectdiscovery/wappalyzergo v0.0.92/go.mod h1:HvYuW0Be4JCjVds/+XAEaMSqRG9yrI97UmZq0TPk6A0= github.com/projectdiscovery/wappalyzergo v0.0.92/go.mod h1:HvYuW0Be4JCjVds/+XAEaMSqRG9yrI97UmZq0TPk6A0=
github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE= github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE=

View File

@ -14,6 +14,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/internal/installer" "github.com/projectdiscovery/nuclei/v2/internal/installer"
"github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud" "github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud"
uncoverlib "github.com/projectdiscovery/uncover"
updateutils "github.com/projectdiscovery/utils/update" updateutils "github.com/projectdiscovery/utils/update"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
@ -489,7 +490,14 @@ func (r *Runner) RunEnumeration() error {
// add the hosts from the metadata queries of loaded templates into input provider // add the hosts from the metadata queries of loaded templates into input provider
if r.options.Uncover && len(r.options.UncoverQuery) == 0 { if r.options.Uncover && len(r.options.UncoverQuery) == 0 {
ret := uncover.GetUncoverTargetsFromMetadata(store.Templates(), r.options.UncoverDelay, r.options.UncoverLimit, r.options.UncoverField) uncoverOpts := &uncoverlib.Options{
Limit: r.options.UncoverLimit,
MaxRetry: r.options.Retries,
Timeout: r.options.Timeout,
RateLimit: uint(r.options.UncoverRateLimit),
RateLimitUnit: time.Minute, // default unit is minute
}
ret := uncover.GetUncoverTargetsFromMetadata(context.TODO(), store.Templates(), r.options.UncoverField, uncoverOpts)
for host := range ret { for host := range ret {
r.hmapInputProvider.Set(host) r.hmapInputProvider.Set(host)
} }

View File

@ -4,6 +4,7 @@ package hybrid
import ( import (
"bufio" "bufio"
"context"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -22,6 +23,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/uncover" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/uncover"
"github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/nuclei/v2/pkg/types"
uncoverlib "github.com/projectdiscovery/uncover"
fileutil "github.com/projectdiscovery/utils/file" fileutil "github.com/projectdiscovery/utils/file"
iputil "github.com/projectdiscovery/utils/ip" iputil "github.com/projectdiscovery/utils/ip"
readerutil "github.com/projectdiscovery/utils/reader" readerutil "github.com/projectdiscovery/utils/reader"
@ -137,7 +139,16 @@ func (i *Input) initializeInputSources(opts *Options) error {
} }
if options.Uncover && options.UncoverQuery != nil { if options.Uncover && options.UncoverQuery != nil {
gologger.Info().Msgf("Running uncover query against: %s", strings.Join(options.UncoverEngine, ",")) gologger.Info().Msgf("Running uncover query against: %s", strings.Join(options.UncoverEngine, ","))
ch, err := uncover.GetTargetsFromUncover(options.UncoverDelay, options.UncoverLimit, options.UncoverField, options.UncoverEngine, options.UncoverQuery) uncoverOpts := &uncoverlib.Options{
Agents: options.UncoverEngine,
Queries: options.UncoverQuery,
Limit: options.UncoverLimit,
MaxRetry: options.Retries,
Timeout: options.Timeout,
RateLimit: uint(options.UncoverRateLimit),
RateLimitUnit: time.Minute, // default unit is minute
}
ch, err := uncover.GetTargetsFromUncover(context.TODO(), options.UncoverField, uncoverOpts)
if err != nil { if err != nil {
return err return err
} }

View File

@ -3,247 +3,133 @@ package uncover
import ( import (
"context" "context"
"fmt" "fmt"
"os" "runtime"
"strings" "strings"
"sync"
"time"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/templates" "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/ratelimit" "github.com/projectdiscovery/uncover"
ucRunner "github.com/projectdiscovery/uncover/runner" "github.com/projectdiscovery/uncover/sources"
"github.com/projectdiscovery/uncover/uncover"
"github.com/projectdiscovery/uncover/uncover/agent/censys"
"github.com/projectdiscovery/uncover/uncover/agent/criminalip"
"github.com/projectdiscovery/uncover/uncover/agent/fofa"
"github.com/projectdiscovery/uncover/uncover/agent/hunter"
"github.com/projectdiscovery/uncover/uncover/agent/netlas"
"github.com/projectdiscovery/uncover/uncover/agent/quake"
"github.com/projectdiscovery/uncover/uncover/agent/shodan"
"github.com/projectdiscovery/uncover/uncover/agent/shodanidb"
"github.com/projectdiscovery/uncover/uncover/agent/zoomeye"
mapsutil "github.com/projectdiscovery/utils/maps" mapsutil "github.com/projectdiscovery/utils/maps"
"github.com/remeh/sizedwaitgroup" stringsutil "github.com/projectdiscovery/utils/strings"
) )
const maxConcurrentAgents = 50 // returns csv string of uncover supported agents
func GetUncoverSupportedAgents() string { func GetUncoverSupportedAgents() string {
uncoverSupportedAgents := []string{"shodan", "shodan-idb", "fofa", "censys", "quake", "hunter", "zoomeye", "netlas", "criminalip"} u, _ := uncover.New(&uncover.Options{})
return strings.Join(uncoverSupportedAgents, ",") return strings.Join(u.AllAgents(), ",")
} }
func GetTargetsFromUncover(delay, limit int, field string, engine, query []string) (chan string, error) { // GetTargetsFromUncover returns targets from uncover
uncoverOptions := &ucRunner.Options{ func GetTargetsFromUncover(ctx context.Context, outputFormat string, opts *uncover.Options) (chan string, error) {
Provider: &ucRunner.Provider{}, u, err := uncover.New(opts)
Delay: delay, if err != nil {
Limit: limit, return nil, err
Query: query,
Engine: engine,
} }
for _, eng := range engine { resChan, err := u.Execute(ctx)
err := loadKeys(eng, uncoverOptions) if err != nil {
if err != nil { return nil, err
gologger.Error().Label("WRN").Msgf(err.Error())
continue
}
} }
return getTargets(uncoverOptions, field) outputChan := make(chan string) // buffered channel
}
func GetUncoverTargetsFromMetadata(templates []*templates.Template, delay, limit int, field string) chan string {
ret := make(chan string)
var uqMap = make(map[string][]string)
var eng, query string
for _, template := range templates {
for k, v := range template.Info.Metadata {
switch k {
case "shodan-query":
eng = "shodan"
case "fofa-query":
eng = "fofa"
case "censys-query":
eng = "censys"
case "quake-query":
eng = "quake"
case "hunter-query":
eng = "hunter"
case "zoomeye-query":
eng = "zoomeye"
case "netlas-query":
eng = "netlas"
case "criminalip-query":
eng = "criminalip"
default:
continue
}
query = fmt.Sprintf("%v", v)
uqMap[eng] = append(uqMap[eng], query)
}
}
keys := mapsutil.GetKeys(uqMap)
gologger.Info().Msgf("Running uncover query against: %s", strings.Join(keys, ","))
var wg sync.WaitGroup
go func() { go func() {
for k, v := range uqMap { defer close(outputChan)
wg.Add(1) for {
go func(engine, query []string) { select {
ch, _ := GetTargetsFromUncover(delay, limit, field, engine, query) case <-ctx.Done():
for c := range ch { return
ret <- c case res, ok := <-resChan:
if !ok {
return
} }
wg.Done() if res.Error != nil {
}([]string{k}, v) // only log in verbose mode
gologger.Verbose().Msgf("uncover: %v", res.Error)
continue
}
outputChan <- processUncoverOutput(res, outputFormat)
}
} }
wg.Wait()
close(ret)
}() }()
return ret return outputChan, nil
} }
func getTargets(uncoverOptions *ucRunner.Options, field string) (chan string, error) { // processUncoverOutput returns output strign depending on uncover field
var rateLimiter *ratelimit.Limiter func processUncoverOutput(result sources.Result, outputFormat string) string {
// create rateLimiter for uncover delay if (result.IP == "" || result.Port == 0) && stringsutil.ContainsAny(outputFormat, "ip", "port") {
if uncoverOptions.Delay > 0 { // if ip or port is not present, fallback to using host
rateLimiter = ratelimit.New(context.Background(), 1, time.Duration(uncoverOptions.Delay)) outputFormat = "host"
} else {
rateLimiter = ratelimit.NewUnlimited(context.Background())
} }
var agents []uncover.Agent replacer := strings.NewReplacer(
// declare clients "ip", result.IP,
for _, engine := range uncoverOptions.Engine { "host", result.Host,
var ( "port", fmt.Sprint(result.Port),
agent uncover.Agent "url", result.Url,
err error )
) return replacer.Replace(outputFormat)
switch engine { }
case "shodan":
agent, err = shodan.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter}) // GetUncoverTargetsFromMetadata returns targets from uncover metadata
case "censys": func GetUncoverTargetsFromMetadata(ctx context.Context, templates []*templates.Template, outputFormat string, opts *uncover.Options) chan string {
agent, err = censys.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter}) // contains map[engine]queries
case "fofa": queriesMap := make(map[string][]string)
agent, err = fofa.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter}) for _, template := range templates {
case "shodan-idb": innerLoop:
agent, err = shodanidb.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter}) for k, v := range template.Info.Metadata {
case "quake": if !strings.HasSuffix(k, "-query") {
agent, err = quake.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter}) // this is not a query
case "hunter": // query keys are like shodan-query, fofa-query, etc
agent, err = hunter.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter}) continue innerLoop
case "zoomeye":
agent, err = zoomeye.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "netlas":
agent, err = netlas.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "criminalip":
agent, err = criminalip.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
default:
err = errors.Errorf("%s unknown uncover agent type", engine)
}
if err != nil {
return nil, err
}
agents = append(agents, agent)
}
// enumerate
swg := sizedwaitgroup.New(maxConcurrentAgents)
ret := make(chan string)
go func() {
for _, q := range uncoverOptions.Query {
uncoverQuery := &uncover.Query{
Query: q,
Limit: uncoverOptions.Limit,
} }
for _, agent := range agents { engine := strings.TrimSuffix(k, "-query")
swg.Add() if queriesMap[engine] == nil {
go func(agent uncover.Agent, uncoverQuery *uncover.Query) { queriesMap[engine] = []string{}
defer swg.Done() }
keys := uncoverOptions.Provider.GetKeys() queriesMap[engine] = append(queriesMap[engine], fmt.Sprint(v))
session, err := uncover.NewSession(&keys, uncoverOptions.Retries, uncoverOptions.Timeout) }
if err != nil { }
gologger.Error().Label(agent.Name()).Msgf("couldn't create uncover new session: %s", err) keys := mapsutil.GetKeys(queriesMap)
} gologger.Info().Msgf("Running uncover queries from template against: %s", strings.Join(keys, ","))
ch, err := agent.Query(session, uncoverQuery) result := make(chan string, runtime.NumCPU())
if err != nil { go func() {
gologger.Warning().Msgf("%s", err) defer close(result)
// unfortunately uncover doesn't support execution of map[engine]queries
// if queries are given they are executed against all engines which is not what we want
// TODO: add support for map[engine]queries in uncover
// Note below implementation is intentionally sequential to avoid burning all the API keys
counter := 0
for eng, queries := range queriesMap {
// create new uncover options for each engine
uncoverOpts := &uncover.Options{
Agents: []string{eng},
Queries: queries,
Limit: opts.Limit,
MaxRetry: opts.MaxRetry,
Timeout: opts.Timeout,
RateLimit: opts.RateLimit,
RateLimitUnit: opts.RateLimitUnit,
}
ch, err := GetTargetsFromUncover(ctx, outputFormat, uncoverOpts)
if err != nil {
gologger.Error().Msgf("Could not get targets using %v engine from uncover: %s", eng, err)
return
}
for {
select {
case <-ctx.Done():
return
case res, ok := <-ch:
if !ok {
return return
} }
for result := range ch { result <- res
replacer := strings.NewReplacer( counter++
"ip", result.IP, if opts.Limit > 0 && counter >= opts.Limit {
"host", result.Host, return
"port", fmt.Sprint(result.Port),
)
ret <- replacer.Replace(field)
} }
}(agent, uncoverQuery) }
} }
} }
swg.Wait()
close(ret)
}() }()
return ret, nil return result
}
func loadKeys(engine string, options *ucRunner.Options) error {
switch engine {
case "fofa":
if email, exists := os.LookupEnv("FOFA_EMAIL"); exists {
if key, exists := os.LookupEnv("FOFA_KEY"); exists {
options.Provider.Fofa = append(options.Provider.Fofa, fmt.Sprintf("%s:%s", email, key))
} else {
return errors.New("missing FOFA_KEY env variable")
}
} else {
return errors.Errorf("FOFA_EMAIL & FOFA_KEY env variables are not configured")
}
case "shodan":
if key, exists := os.LookupEnv("SHODAN_API_KEY"); exists {
options.Provider.Shodan = append(options.Provider.Shodan, key)
} else {
return errors.Errorf("SHODAN_API_KEY env variable is not configured")
}
case "censys":
if id, exists := os.LookupEnv("CENSYS_API_ID"); exists {
if secret, exists := os.LookupEnv("CENSYS_API_SECRET"); exists {
options.Provider.Censys = append(options.Provider.Censys, fmt.Sprintf("%s:%s", id, secret))
} else {
return errors.New("missing CENSYS_API_SECRET env variable")
}
} else {
return errors.Errorf("CENSYS_API_ID & CENSYS_API_SECRET env variable is not configured")
}
case "hunter":
if key, exists := os.LookupEnv("HUNTER_API_KEY"); exists {
options.Provider.Hunter = append(options.Provider.Hunter, key)
} else {
return errors.Errorf("HUNTER_API_KEY env variable is not configured")
}
case "zoomeye":
if key, exists := os.LookupEnv("ZOOMEYE_API_KEY"); exists {
options.Provider.ZoomEye = append(options.Provider.ZoomEye, key)
} else {
return errors.Errorf("ZOOMEYE_API_KEY env variable is not configured")
}
case "quake":
if key, exists := os.LookupEnv("QUAKE_TOKEN"); exists {
options.Provider.Quake = append(options.Provider.Quake, key)
} else {
return errors.Errorf("QUAKE_TOKEN env variable is not configured")
}
case "netlas":
if key, exists := os.LookupEnv("NETLAS_API_KEY"); exists {
options.Provider.Netlas = append(options.Provider.Netlas, key)
} else {
return errors.Errorf("NETLAS_API_KEY env variable is not configured")
}
case "criminalip":
if key, exists := os.LookupEnv("CRIMINALIP_API_KEY"); exists {
options.Provider.CriminalIP = append(options.Provider.CriminalIP, key)
} else {
return errors.Errorf("CRIMINALIP_API_KEY env variable is not configured")
}
default:
return errors.Errorf("unknown uncover agent")
}
return nil
} }

View File

@ -321,7 +321,7 @@ type Options struct {
// Uncover search limit // Uncover search limit
UncoverLimit int UncoverLimit int
// Uncover search delay // Uncover search delay
UncoverDelay int UncoverRateLimit int
// ScanAllIPs associated to a dns record // ScanAllIPs associated to a dns record
ScanAllIPs bool ScanAllIPs bool
// IPVersion to scan (4,6) // IPVersion to scan (4,6)