2018-04-16 09:46:54 +00:00
// subfinder : Subdomain discovery tool in golang
2018-04-04 11:33:16 +00:00
// Written By : @codingo
// @ice3man
//
// Distributed Under MIT License
// Copyrights (C) 2018 Ice3man
2018-04-16 09:46:54 +00:00
// Contains main driver classes for the tool
2018-04-04 11:33:16 +00:00
package main
import (
2018-05-10 16:39:04 +00:00
"bufio"
2018-04-22 16:32:23 +00:00
"encoding/json"
2018-04-04 11:33:16 +00:00
"flag"
2018-04-17 10:15:36 +00:00
"fmt"
2018-04-22 16:32:23 +00:00
"io/ioutil"
2018-04-04 11:33:16 +00:00
"os"
2018-05-09 09:18:48 +00:00
"path/filepath"
2018-04-22 16:32:23 +00:00
"reflect"
"strings"
2018-04-04 11:33:16 +00:00
2018-04-24 13:52:58 +00:00
"github.com/Ice3man543/subfinder/libsubfinder/engines/passive"
"github.com/Ice3man543/subfinder/libsubfinder/helper"
//"github.com/Ice3man543/subfinder/libsubfinder/engines/bruteforce"
2018-04-04 11:33:16 +00:00
)
var banner = `
2018-05-14 10:44:25 +00:00
__ _____ __
_______ __ / / _ / __ ( _ ) ___ ____ / / __ _____
/ ___ / / / / __ \ / / _ / / __ \ / __ / _ \ / ___ /
( __ ) / _ / / / _ / / __ / / / / / / _ / / __ / /
/ ____ / \ __ , _ / _ . ___ / _ / / _ / _ / / _ / \ __ , _ / \ ___ / _ /
2018-05-28 02:23:19 +00:00
v0 .2 - by @ ice3man `
2018-04-04 11:33:16 +00:00
// Parses command line arguments into a setting structure
func ParseCmdLine ( ) ( state * helper . State , err error ) {
// Initialize current state and read Config file
s , err := helper . InitState ( )
if err != nil {
return & s , err
}
flag . BoolVar ( & s . Verbose , "v" , false , "Verbose output" )
2018-05-15 03:56:19 +00:00
flag . BoolVar ( & s . Color , "no-color" , true , "Don't Use colors in output" )
2018-04-04 11:33:16 +00:00
flag . IntVar ( & s . Threads , "t" , 10 , "Number of concurrent threads" )
2018-04-05 10:11:46 +00:00
flag . IntVar ( & s . Timeout , "timeout" , 180 , "Timeout for passive discovery services" )
2018-04-04 11:33:16 +00:00
flag . StringVar ( & s . Domain , "d" , "" , "Domain to find subdomains for" )
2018-04-08 08:20:16 +00:00
flag . StringVar ( & s . Output , "o" , "" , "Name of the output file (optional)" )
flag . BoolVar ( & s . IsJSON , "oJ" , false , "Write output in JSON Format" )
2018-05-10 16:39:04 +00:00
flag . BoolVar ( & s . Alive , "nW" , false , "Remove Wildcard Subdomains from output" )
2018-04-17 10:15:36 +00:00
flag . BoolVar ( & s . Silent , "silent" , false , "Show only subdomains in output" )
2018-05-10 16:39:04 +00:00
flag . BoolVar ( & s . Recursive , "recursive" , false , "Use recursion to find subdomains" )
2018-04-06 13:01:36 +00:00
flag . StringVar ( & s . Wordlist , "w" , "" , "Wordlist for doing subdomain bruteforcing" )
2018-04-17 10:15:36 +00:00
flag . StringVar ( & s . Sources , "sources" , "all" , "Comma separated list of sources to use" )
2018-04-06 13:01:36 +00:00
flag . BoolVar ( & s . Bruteforce , "b" , false , "Use bruteforcing to find subdomains" )
2018-04-22 16:32:23 +00:00
flag . StringVar ( & s . SetConfig , "set-config" , "none" , "Comma separated list of configuration details" )
2018-04-26 15:36:58 +00:00
flag . StringVar ( & s . SetSetting , "set-settings" , "none" , "Comma separated list of settings" )
2018-05-10 16:39:04 +00:00
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" )
2018-06-16 13:39:28 +00:00
flag . StringVar ( & s . ExcludeSource , "exclude-sources" , "" , "List of sources to exclude from enumeration" )
2018-05-15 04:09:36 +00:00
flag . BoolVar ( & s . AquatoneJSON , "oT" , false , "Use aquatone style json output format" )
2018-04-04 11:33:16 +00:00
flag . Parse ( )
return & s , nil
}
func main ( ) {
state , err := ParseCmdLine ( )
if err != nil {
fmt . Println ( err )
os . Exit ( 1 )
}
2018-04-17 10:15:36 +00:00
if state . Silent != true {
fmt . Println ( banner )
2018-04-22 16:32:23 +00:00
}
if state . SetConfig != "none" {
setConfig := strings . Split ( 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
2018-05-05 09:20:03 +00:00
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 ] )
}
2018-04-22 16:32:23 +00:00
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 )
}
2018-05-14 10:44:25 +00:00
fmt . Printf ( "Successfully configured %s%s%s=>%s\n" , helper . Info , object [ 0 ] , helper . Reset , object [ 1 ] )
2018-04-22 16:32:23 +00:00
}
os . Exit ( 0 )
2018-04-17 10:15:36 +00:00
}
2018-04-26 15:36:58 +00:00
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 {
2018-05-14 10:44:25 +00:00
fmt . Printf ( "Successfully Set %s%s%s=>%s\n" , helper . Info , object [ 0 ] , helper . Reset , object [ 1 ] )
2018-04-26 15:36:58 +00:00
}
}
}
}
2018-05-10 16:39:04 +00:00
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" )
}
2018-05-09 09:18:48 +00:00
if state . Output != "" {
dir := filepath . Dir ( state . Output )
exists , _ := helper . Exists ( dir )
if exists == false {
2018-05-14 10:44:25 +00:00
fmt . Printf ( "\n%s-> The specified output directory does not exists !%s\n" , helper . Yellow , helper . Reset )
2018-05-25 14:19:27 +00:00
} 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
}
}
2018-05-09 09:18:48 +00:00
}
} else if state . OutputDir != "" {
exists , _ := helper . Exists ( state . OutputDir )
if exists == false {
2018-05-14 10:44:25 +00:00
fmt . Printf ( "\n%s-> The specified output directory does not exists !%s\n" , helper . Yellow , helper . Reset )
2018-05-09 09:18:48 +00:00
}
}
2018-05-05 15:50:43 +00:00
if state . Domain == "" && state . DomainList == "" {
2018-04-17 10:15:36 +00:00
if state . Silent != true {
2018-05-14 10:44:25 +00:00
fmt . Printf ( "\n\n%s-> Missing \"domain\" argument %s\nTry %s'./subfinder -h'%s for more information\n" , helper . Bad , helper . Reset , helper . Info , helper . Reset )
2018-04-17 10:15:36 +00:00
}
2018-04-04 11:33:16 +00:00
os . Exit ( 1 )
2018-05-05 15:50:43 +00:00
}
2018-04-04 11:33:16 +00:00
2018-05-15 19:26:49 +00:00
_ = passive . Enumerate ( state )
fmt . Printf ( "\n" )
2018-04-06 13:01:36 +00:00
//bruteforce.Bruteforce(state)
2018-04-04 11:52:46 +00:00
}