Refactored subfinder as embeddable
parent
9209194f6a
commit
29b85aec89
|
@ -28,15 +28,18 @@ func GetHomeDir() string {
|
|||
}
|
||||
|
||||
// Exists returns whether the given file or directory exists or not
|
||||
func Exists(path string) (bool, error) {
|
||||
func Exists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
|
||||
if err == nil {
|
||||
return true, nil
|
||||
return true
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
return false
|
||||
}
|
||||
return true, err
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// CreateDirIfNotExist creates config directory if it does not exists
|
||||
|
@ -53,16 +56,14 @@ func CreateDirIfNotExist(dir string) {
|
|||
// ReadConfigFile Reads a config file from disk and returns Configuration structure
|
||||
// If not exists, create one and then return
|
||||
func ReadConfigFile() (configuration *Config, err error) {
|
||||
|
||||
var config Config
|
||||
|
||||
// Get current path
|
||||
home := GetHomeDir()
|
||||
|
||||
path := home + "/.config/subfinder/config.json"
|
||||
status, _ := Exists(path)
|
||||
|
||||
if status == true {
|
||||
if Exists(path) {
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return &config, err
|
||||
|
@ -85,5 +86,4 @@ func ReadConfigFile() (configuration *Config, err error) {
|
|||
|
||||
fmt.Printf("\n[NOTE] Edit %s with your options !", path)
|
||||
return &config, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -94,12 +94,12 @@ func InitializeSettings() (setting *Setting) {
|
|||
}
|
||||
|
||||
// InitState initializes the default state
|
||||
func InitState() (state State, err error) {
|
||||
func InitState() (state *State) {
|
||||
|
||||
// Read the configuration file and ignore errors
|
||||
config, _ := ReadConfigFile()
|
||||
|
||||
setting := InitializeSettings()
|
||||
|
||||
return State{true, 10, 180, false, "", false, "", false, false, "", false, []string{}, true, "", false, []string{}, "", "", "", "", []string{}, "", "", false, "", false, nil, *setting, *config}, nil
|
||||
return &State{true, 10, 180, false, "", false, "", false, false, "", false, []string{}, true, "", false, []string{}, "", "", "", "", []string{}, "", "", false, "", false, nil, *setting, *config}
|
||||
}
|
||||
|
|
195
main.go
195
main.go
|
@ -9,192 +9,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/subfinder/subfinder/libsubfinder/engines/passive"
|
||||
"github.com/subfinder/subfinder/libsubfinder/helper"
|
||||
"github.com/subfinder/subfinder/subf"
|
||||
)
|
||||
|
||||
// ParseCmdLine ... Parses command line arguments into a setting structure
|
||||
func ParseCmdLine() (state *helper.State, err error) {
|
||||
// ParseCmdLine ... Parses command line arguments into a setting structure
|
||||
func ParseCmdLine() (s *subf.Subfinder) {
|
||||
|
||||
// Initialize current state and read Config file
|
||||
s, err := helper.InitState()
|
||||
if err != nil {
|
||||
return &s, err
|
||||
}
|
||||
s = subf.NewSubfinder()
|
||||
|
||||
flag.BoolVar(&s.Verbose, "v", false, "Verbose output")
|
||||
flag.BoolVar(&s.Color, "no-color", true, "Don't Use colors in output")
|
||||
flag.IntVar(&s.Threads, "t", 10, "Number of concurrent threads")
|
||||
flag.IntVar(&s.Timeout, "timeout", 180, "Timeout for passive discovery services")
|
||||
flag.StringVar(&s.Domain, "d", "", "Domain to find subdomains for")
|
||||
flag.StringVar(&s.Output, "o", "", "Name of the output file (optional)")
|
||||
flag.BoolVar(&s.IsJSON, "oJ", false, "Write output in JSON Format")
|
||||
flag.BoolVar(&s.Alive, "nW", false, "Remove Wildcard Subdomains from output")
|
||||
flag.BoolVar(&s.NoPassive, "no-passive", false, "Do not perform passive subdomain enumeration")
|
||||
flag.BoolVar(&s.Silent, "silent", false, "Show only subdomains in output")
|
||||
flag.BoolVar(&s.Recursive, "recursive", false, "Use recursion to find subdomains")
|
||||
flag.StringVar(&s.Wordlist, "w", "", "Wordlist for doing subdomain bruteforcing")
|
||||
flag.StringVar(&s.Sources, "sources", "all", "Comma separated list of sources to use")
|
||||
flag.BoolVar(&s.Bruteforce, "b", false, "Use bruteforcing to find subdomains")
|
||||
flag.StringVar(&s.SetConfig, "set-config", "none", "Comma separated list of configuration details")
|
||||
flag.StringVar(&s.SetSetting, "set-settings", "none", "Comma separated list of settings")
|
||||
flag.StringVar(&s.DomainList, "dL", "", "List of domains to find subdomains for")
|
||||
flag.StringVar(&s.OutputDir, "oD", "", "Directory to output results to ")
|
||||
flag.StringVar(&s.ComResolver, "r", "", "Comma-separated list of resolvers to use")
|
||||
flag.StringVar(&s.ListResolver, "rL", "", "Text file containing list of resolvers to use")
|
||||
flag.StringVar(&s.ExcludeSource, "exclude-sources", "", "List of sources to exclude from enumeration")
|
||||
flag.BoolVar(&s.AquatoneJSON, "oT", false, "Use aquatone style json output format")
|
||||
flag.BoolVar(&s.State.Verbose, "v", false, "Verbose output")
|
||||
flag.BoolVar(&s.State.Color, "no-color", true, "Don't Use colors in output")
|
||||
flag.IntVar(&s.State.Threads, "t", 10, "Number of concurrent threads")
|
||||
flag.IntVar(&s.State.Timeout, "timeout", 180, "Timeout for passive discovery services")
|
||||
flag.StringVar(&s.State.Domain, "d", "", "Domain to find subdomains for")
|
||||
flag.StringVar(&s.State.Output, "o", "", "Name of the output file (optional)")
|
||||
flag.BoolVar(&s.State.IsJSON, "oJ", false, "Write output in JSON Format")
|
||||
flag.BoolVar(&s.State.Alive, "nW", false, "Remove Wildcard Subdomains from output")
|
||||
flag.BoolVar(&s.State.NoPassive, "no-passive", false, "Do not perform passive subdomain enumeration")
|
||||
flag.BoolVar(&s.State.Silent, "silent", false, "Show only subdomains in output")
|
||||
flag.BoolVar(&s.State.Recursive, "recursive", false, "Use recursion to find subdomains")
|
||||
flag.StringVar(&s.State.Wordlist, "w", "", "Wordlist for doing subdomain bruteforcing")
|
||||
flag.StringVar(&s.State.Sources, "sources", "all", "Comma separated list of sources to use")
|
||||
flag.BoolVar(&s.State.Bruteforce, "b", false, "Use bruteforcing to find subdomains")
|
||||
flag.StringVar(&s.State.SetConfig, "set-config", "none", "Comma separated list of configuration details")
|
||||
flag.StringVar(&s.State.SetSetting, "set-settings", "none", "Comma separated list of settings")
|
||||
flag.StringVar(&s.State.DomainList, "dL", "", "List of domains to find subdomains for")
|
||||
flag.StringVar(&s.State.OutputDir, "oD", "", "Directory to output results to ")
|
||||
flag.StringVar(&s.State.ComResolver, "r", "", "Comma-separated list of resolvers to use")
|
||||
flag.StringVar(&s.State.ListResolver, "rL", "", "Text file containing list of resolvers to use")
|
||||
flag.StringVar(&s.State.ExcludeSource, "exclude-sources", "", "List of sources to exclude from enumeration")
|
||||
flag.BoolVar(&s.State.AquatoneJSON, "oT", false, "Use aquatone style json output format")
|
||||
flag.Parse()
|
||||
|
||||
return &s, nil
|
||||
return s
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
state, err := ParseCmdLine()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
subfinder := ParseCmdLine()
|
||||
|
||||
if state.Silent != true {
|
||||
if !subfinder.State.Silent {
|
||||
fmt.Println("===============================================")
|
||||
fmt.Printf("%s%s-=Subfinder%s v1.1 github.com/subfinder/subfinder\n", helper.Info, helper.Cyan, helper.Reset)
|
||||
fmt.Println("===============================================")
|
||||
}
|
||||
|
||||
if state.SetConfig != "none" {
|
||||
setConfig := strings.Split(state.SetConfig, ",")
|
||||
subfinder.Init()
|
||||
|
||||
// Build Configuration path
|
||||
home := helper.GetHomeDir()
|
||||
path := home + "/.config/subfinder/config.json"
|
||||
_ = subfinder.PassiveEnumeration()
|
||||
|
||||
for _, config := range setConfig {
|
||||
object := strings.Split(config, "=")
|
||||
|
||||
// Change value dynamically using reflect package
|
||||
if strings.EqualFold(object[0], "virustotalapikey") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("VirustotalAPIKey").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "passivetotalusername") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("PassivetotalUsername").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "passivetotalkey") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("PassivetotalKey").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "securitytrailskey") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("SecurityTrailsKey").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "riddleremail") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("RiddlerEmail").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "riddlerpassword") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("RiddlerPassword").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "censysusername") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("CensysUsername").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "censyssecret") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("CensysSecret").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "shodankey") == true {
|
||||
reflect.ValueOf(&state.ConfigState).Elem().FieldByName("ShodanAPIKey").SetString(object[1])
|
||||
}
|
||||
|
||||
configJSON, _ := json.MarshalIndent(state.ConfigState, "", " ")
|
||||
err = ioutil.WriteFile(path, configJSON, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n\n[!] Error : %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully configured %s%s%s=>%s\n", helper.Info, object[0], helper.Reset, object[1])
|
||||
}
|
||||
}
|
||||
|
||||
if state.SetSetting != "none" {
|
||||
setSetting := strings.Split(state.SetSetting, ",")
|
||||
|
||||
for _, setting := range setSetting {
|
||||
object := strings.Split(setting, "=")
|
||||
|
||||
// Change value dynamically using reflect package
|
||||
reflect.ValueOf(&state.CurrentSettings).Elem().FieldByName(object[0]).SetString(object[1])
|
||||
if state.Silent != true {
|
||||
if state.Verbose == true {
|
||||
fmt.Printf("Successfully Set %s%s%s=>%s\n", helper.Info, object[0], helper.Reset, object[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state.ComResolver != "" {
|
||||
// Load the Resolvers from list
|
||||
setResolvers := strings.Split(state.ComResolver, ",")
|
||||
|
||||
for _, resolver := range setResolvers {
|
||||
state.LoadResolver = append(state.LoadResolver, resolver)
|
||||
}
|
||||
}
|
||||
|
||||
if state.ListResolver != "" {
|
||||
// Load the resolvers from file
|
||||
file, err := os.Open(state.ListResolver)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "\nerror: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
// Send the job to the channel
|
||||
state.LoadResolver = append(state.LoadResolver, scanner.Text())
|
||||
}
|
||||
}
|
||||
|
||||
// Use the default resolvers
|
||||
if state.ComResolver == "" && state.ListResolver == "" {
|
||||
state.LoadResolver = append(state.LoadResolver, "1.1.1.1")
|
||||
state.LoadResolver = append(state.LoadResolver, "8.8.8.8")
|
||||
state.LoadResolver = append(state.LoadResolver, "8.8.4.4")
|
||||
}
|
||||
|
||||
if state.Output != "" {
|
||||
dir := filepath.Dir(state.Output)
|
||||
exists, _ := helper.Exists(dir)
|
||||
if exists == false {
|
||||
fmt.Printf("\n%s-> The specified output directory does not exists !%s\n", helper.Yellow, helper.Reset)
|
||||
} else {
|
||||
// Get a handle to the out file if it is not json
|
||||
if state.AquatoneJSON != true && state.IsJSON != true {
|
||||
state.OutputHandle, err = os.OpenFile(state.Output, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else if state.OutputDir != "" {
|
||||
exists, _ := helper.Exists(state.OutputDir)
|
||||
if exists == false {
|
||||
fmt.Printf("\n%s-> The specified output directory does not exists !%s\n", helper.Yellow, helper.Reset)
|
||||
}
|
||||
}
|
||||
|
||||
if state.Domain == "" && state.DomainList == "" {
|
||||
if state.Silent != true {
|
||||
fmt.Printf("%s-> Missing \"domain\" argument %s\nTry %s'./subfinder -h'%s for more information\n", helper.Bad, helper.Reset, helper.Info, helper.Reset)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_ = passive.Enumerate(state)
|
||||
fmt.Printf("\n")
|
||||
//bruteforce.Bruteforce(state)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package subf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/subfinder/subfinder/libsubfinder/engines/passive"
|
||||
"github.com/subfinder/subfinder/libsubfinder/helper"
|
||||
)
|
||||
|
||||
// Subfinder represent a subdomain enumerator instance
|
||||
type Subfinder struct {
|
||||
State *helper.State
|
||||
}
|
||||
|
||||
// NewSubfinder instantiate a new subfinder
|
||||
func NewSubfinder() *Subfinder {
|
||||
return &Subfinder{
|
||||
State: helper.InitState(),
|
||||
}
|
||||
}
|
||||
|
||||
// Init setup the instance
|
||||
func (s *Subfinder) Init() {
|
||||
s.parseConfig()
|
||||
s.parseSetting()
|
||||
s.parseComResolver()
|
||||
s.parseListResolver()
|
||||
s.setCommonResolver()
|
||||
s.setOutput()
|
||||
s.setDomain()
|
||||
}
|
||||
|
||||
func (s *Subfinder) parseConfig() {
|
||||
if s.State.SetConfig == "none" {
|
||||
return
|
||||
}
|
||||
|
||||
setConfig := strings.Split(s.State.SetConfig, ",")
|
||||
|
||||
// Build Configuration path
|
||||
home := helper.GetHomeDir()
|
||||
path := home + "/.config/subfinder/config.json"
|
||||
|
||||
for _, config := range setConfig {
|
||||
object := strings.Split(config, "=")
|
||||
|
||||
// Change value dynamically using reflect package
|
||||
if strings.EqualFold(object[0], "virustotalapikey") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("VirustotalAPIKey").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "passivetotalusername") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("PassivetotalUsername").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "passivetotalkey") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("PassivetotalKey").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "securitytrailskey") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("SecurityTrailsKey").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "riddleremail") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("RiddlerEmail").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "riddlerpassword") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("RiddlerPassword").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "censysusername") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("CensysUsername").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "censyssecret") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("CensysSecret").SetString(object[1])
|
||||
} else if strings.EqualFold(object[0], "shodankey") {
|
||||
reflect.ValueOf(&s.State.ConfigState).Elem().FieldByName("ShodanAPIKey").SetString(object[1])
|
||||
}
|
||||
|
||||
configJSON, _ := json.MarshalIndent(s.State.ConfigState, "", " ")
|
||||
err := ioutil.WriteFile(path, configJSON, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n\n[!] Error : %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully configured %s%s%s=>%s\n", helper.Info, object[0], helper.Reset, object[1])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subfinder) parseSetting() {
|
||||
if s.State.SetSetting == "none" {
|
||||
return
|
||||
}
|
||||
|
||||
setSetting := strings.Split(s.State.SetSetting, ",")
|
||||
|
||||
for _, setting := range setSetting {
|
||||
object := strings.Split(setting, "=")
|
||||
|
||||
// Change value dynamically using reflect package
|
||||
reflect.ValueOf(&s.State.CurrentSettings).Elem().FieldByName(object[0]).SetString(object[1])
|
||||
if !s.State.Silent && s.State.Verbose {
|
||||
fmt.Printf("Successfully Set %s%s%s=>%s\n", helper.Info, object[0], helper.Reset, object[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subfinder) parseComResolver() {
|
||||
if s.State.ComResolver == "" {
|
||||
return
|
||||
}
|
||||
|
||||
setResolvers := strings.Split(s.State.ComResolver, ",")
|
||||
|
||||
for _, resolver := range setResolvers {
|
||||
s.State.LoadResolver = append(s.State.LoadResolver, resolver)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subfinder) parseListResolver() {
|
||||
if s.State.ListResolver == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Load the resolvers from file
|
||||
file, err := os.Open(s.State.ListResolver)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "\nerror: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
s.State.LoadResolver = append(s.State.LoadResolver, scanner.Text())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subfinder) setCommonResolver() {
|
||||
// Use the default resolvers
|
||||
if s.State.ComResolver != "" && s.State.ListResolver != "" {
|
||||
return
|
||||
}
|
||||
|
||||
s.State.LoadResolver = append(s.State.LoadResolver, "1.1.1.1")
|
||||
s.State.LoadResolver = append(s.State.LoadResolver, "8.8.8.8")
|
||||
s.State.LoadResolver = append(s.State.LoadResolver, "8.8.4.4")
|
||||
}
|
||||
|
||||
func (s *Subfinder) setOutput() {
|
||||
if s.State.Output != "" {
|
||||
dir := filepath.Dir(s.State.Output)
|
||||
if !helper.Exists(dir) {
|
||||
fmt.Printf("\n%s-> The specified output directory does not exists !%s\n", helper.Yellow, helper.Reset)
|
||||
} else {
|
||||
// Get a handle to the out file if it is not json
|
||||
if !s.State.AquatoneJSON && !s.State.IsJSON {
|
||||
var err error
|
||||
s.State.OutputHandle, err = os.OpenFile(s.State.Output, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if s.State.OutputDir != "" {
|
||||
if !helper.Exists(s.State.OutputDir) {
|
||||
fmt.Printf("\n%s-> The specified output directory does not exists !%s\n", helper.Yellow, helper.Reset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subfinder) setDomain() {
|
||||
if s.State.Domain == "" && s.State.DomainList == "" {
|
||||
if !s.State.Silent {
|
||||
fmt.Printf("%s-> Missing \"domain\" argument %s\nTry %s'./subfinder -h'%s for more information\n", helper.Bad, helper.Reset, helper.Info, helper.Reset)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// PassiveEnumeration execute a passive enumeration
|
||||
func (s *Subfinder) PassiveEnumeration() []string {
|
||||
return passive.Enumerate(s.State)
|
||||
}
|
Loading…
Reference in New Issue