From 10546b589f641249ca49aea3e0805548434f2faf Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 11:15:02 +0200 Subject: [PATCH 01/25] BufferOverRun not working --- cmd/scilla/main.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/scilla/main.go b/cmd/scilla/main.go index e5e72b6..71aa9d6 100644 --- a/cmd/scilla/main.go +++ b/cmd/scilla/main.go @@ -178,8 +178,10 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, strings1 = opendb.AppendDBSubdomains(threatcrowd, strings1) hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target)) strings1 = opendb.AppendDBSubdomains(hackerTarget, strings1) - bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(bufferOverrun, strings1) + + // Seems Not Working + //bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target)) + //strings1 = opendb.AppendDBSubdomains(bufferOverrun, strings1) if userInput.ReportVirusTotal { vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey()) @@ -343,8 +345,10 @@ func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, strings1 = opendb.AppendDBSubdomains(threatcrowd, strings1) hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target)) strings1 = opendb.AppendDBSubdomains(hackerTarget, strings1) - bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(bufferOverrun, strings1) + + // Seems Not Working + //bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target)) + //strings1 = opendb.AppendDBSubdomains(bufferOverrun, strings1) if userInput.SubdomainVirusTotal { vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey()) From 491934674325d7cf27461f86e4886f3a83b5c3f7 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 11:45:28 +0200 Subject: [PATCH 02/25] Update OpenDBs --- cmd/scilla/main.go | 76 ++++++++++++++++++------------------- pkg/opendb/bufferoverrun.go | 7 +++- pkg/opendb/crtsh.go | 7 +++- pkg/opendb/hackertarget.go | 7 +++- pkg/opendb/sonar.go | 7 +++- pkg/opendb/threatcrowd.go | 7 +++- pkg/opendb/utils.go | 8 +++- pkg/opendb/virustotal.go | 6 ++- 8 files changed, 79 insertions(+), 46 deletions(-) diff --git a/cmd/scilla/main.go b/cmd/scilla/main.go index 71aa9d6..8d89323 100644 --- a/cmd/scilla/main.go +++ b/cmd/scilla/main.go @@ -144,7 +144,7 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, fmt.Println("================ SCANNING SUBDOMAINS ================") - var strings1 []string + var subdomains []string // change from ip to Hostname if ipUtils.IsIP(target) { targetIP = target @@ -163,35 +163,33 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, outputFileTXT, mutex, "sub", false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) } - strings1 = input.CreateSubdomains(userInput.ReportWordSub, protocolTemp, urlUtils.CleanProtocol(target)) + subdomains = input.CreateSubdomains(userInput.ReportWordSub, protocolTemp, urlUtils.CleanProtocol(target)) if userInput.ReportSubdomainDB { - if userInput.ReportVirusTotal { - _ = input.GetVirusTotalKey() - } - - sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(sonar, strings1) - crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(crtsh, strings1) - threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(threatcrowd, strings1) - hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(hackerTarget, strings1) + sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(sonar, subdomains) + crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(crtsh, subdomains) + threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) + hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) // Seems Not Working - //bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target)) - //strings1 = opendb.AppendDBSubdomains(bufferOverrun, strings1) + // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), false) + // subdomains = opendb.AppendDBSubdomains(bufferOverrun, subdomains) if userInput.ReportVirusTotal { - vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey()) - strings1 = opendb.AppendDBSubdomains(vtSubs, strings1) + vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey(), false) + subdomains = opendb.AppendDBSubdomains(vtSubs, subdomains) } + + subdomains = opendb.ShuffleSubdomains(subdomains) } // be sure to not scan duplicate values - strings1 = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), strings1)) - enumeration.AsyncGet(protocolTemp, strings1, userInput.ReportIgnoreSub, outputFileJSON, + subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) + enumeration.AsyncGet(protocolTemp, subdomains, userInput.ReportIgnoreSub, outputFileJSON, outputFileHTML, outputFileTXT, subs, mutex, false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) if outputFileHTML != "" { @@ -331,28 +329,29 @@ func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, outputFileTXT = output.CreateOutputFile(userInput.SubdomainOutputTXT) } - var strings1 []string + var subdomains []string if !userInput.SubdomainNoCheck { - strings1 = input.CreateSubdomains(userInput.SubdomainWord, protocolTemp, urlUtils.CleanProtocol(target)) + subdomains = input.CreateSubdomains(userInput.SubdomainWord, protocolTemp, urlUtils.CleanProtocol(target)) } if userInput.SubdomainDB { - sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(sonar, strings1) - crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(crtsh, strings1) - threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(threatcrowd, strings1) - hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target)) - strings1 = opendb.AppendDBSubdomains(hackerTarget, strings1) + sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(sonar, subdomains) + crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(crtsh, subdomains) + threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) + hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) // Seems Not Working - //bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target)) - //strings1 = opendb.AppendDBSubdomains(bufferOverrun, strings1) + // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + // subdomains = opendb.AppendDBSubdomains(bufferOverrun, subdomains) if userInput.SubdomainVirusTotal { - vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey()) - strings1 = opendb.AppendDBSubdomains(vtSubs, strings1) + vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey(), + userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(vtSubs, subdomains) } } @@ -367,12 +366,13 @@ func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, } // be sure to not scan duplicate values - strings1 = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), strings1)) + subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) if !userInput.SubdomainNoCheck { - enumeration.AsyncGet(protocolTemp, strings1, userInput.SubdomainIgnore, outputFileJSON, outputFileHTML, outputFileTXT, - subs, mutex, userInput.SubdomainPlain, userInput.SubdomainUserAgent, userInput.SubdomainRandomUserAgent) + enumeration.AsyncGet(protocolTemp, subdomains, userInput.SubdomainIgnore, outputFileJSON, outputFileHTML, + outputFileTXT, subs, mutex, userInput.SubdomainPlain, userInput.SubdomainUserAgent, + userInput.SubdomainRandomUserAgent) } else { - for _, elem := range strings1 { + for _, elem := range subdomains { fmt.Println(elem) if outputFileJSON != "" { output.AppendOutputToJSON(elem, "SUB", "", outputFileJSON) diff --git a/pkg/opendb/bufferoverrun.go b/pkg/opendb/bufferoverrun.go index d139a1f..a0680ce 100644 --- a/pkg/opendb/bufferoverrun.go +++ b/pkg/opendb/bufferoverrun.go @@ -29,6 +29,7 @@ package opendb import ( "encoding/json" + "fmt" "net/http" "strings" @@ -36,7 +37,11 @@ import ( ) // BufferOverrunSubdomains retrieves from the url below some known subdomains. -func BufferOverrunSubdomains(domain string) []string { +func BufferOverrunSubdomains(domain string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from dns.bufferover.run") + } + client := http.Client{ Timeout: httpUtils.Seconds30, } diff --git a/pkg/opendb/crtsh.go b/pkg/opendb/crtsh.go index 060272a..ea33bf0 100644 --- a/pkg/opendb/crtsh.go +++ b/pkg/opendb/crtsh.go @@ -29,6 +29,7 @@ package opendb import ( "encoding/json" + "fmt" "io/ioutil" "net/http" "strings" @@ -42,7 +43,11 @@ type CrtShResult struct { } // CrtshSubdomains retrieves from the url below some known subdomains. -func CrtshSubdomains(domain string) []string { +func CrtshSubdomains(domain string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from crt.sh") + } + client := http.Client{ Timeout: httpUtils.Seconds30, } diff --git a/pkg/opendb/hackertarget.go b/pkg/opendb/hackertarget.go index f276f63..aae32b7 100644 --- a/pkg/opendb/hackertarget.go +++ b/pkg/opendb/hackertarget.go @@ -30,6 +30,7 @@ package opendb import ( "bufio" "bytes" + "fmt" "io/ioutil" "net/http" "strings" @@ -38,7 +39,11 @@ import ( ) // HackerTargetSubdomains retrieves from the url below some known subdomains. -func HackerTargetSubdomains(domain string) []string { +func HackerTargetSubdomains(domain string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from HackerTarget") + } + client := http.Client{ Timeout: httpUtils.Seconds30, } diff --git a/pkg/opendb/sonar.go b/pkg/opendb/sonar.go index bce3cce..ac10abe 100644 --- a/pkg/opendb/sonar.go +++ b/pkg/opendb/sonar.go @@ -29,6 +29,7 @@ package opendb import ( "encoding/json" + "fmt" "io/ioutil" "net/http" @@ -36,7 +37,11 @@ import ( ) // SonarSubdomains retrieves from the url below some known subdomains. -func SonarSubdomains(target string) []string { +func SonarSubdomains(target string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from SonarDB") + } + client := http.Client{ Timeout: httpUtils.Seconds30, } diff --git a/pkg/opendb/threatcrowd.go b/pkg/opendb/threatcrowd.go index 819291d..71b70fa 100644 --- a/pkg/opendb/threatcrowd.go +++ b/pkg/opendb/threatcrowd.go @@ -29,13 +29,18 @@ package opendb import ( "encoding/json" + "fmt" "net/http" httpUtils "github.com/edoardottt/scilla/internal/http" ) // ThreatcrowdSubdomains retrieves from the url below some known subdomains. -func ThreatcrowdSubdomains(domain string) []string { +func ThreatcrowdSubdomains(domain string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from ThreatCrowd") + } + client := http.Client{ Timeout: httpUtils.Seconds30, } diff --git a/pkg/opendb/utils.go b/pkg/opendb/utils.go index 9881269..20db46f 100644 --- a/pkg/opendb/utils.go +++ b/pkg/opendb/utils.go @@ -49,10 +49,14 @@ func AppendDBSubdomains(dbsubs []string, urls []string) []string { dbsubs = sliceUtils.RemoveDuplicateValues(dbsubs) dbsubs = append(dbsubs, urls...) + return dbsubs +} + +func ShuffleSubdomains(input []string) []string { rand.Seed(time.Now().UnixNano()) - rand.Shuffle(len(dbsubs), func(i, j int) { dbsubs[i], dbsubs[j] = dbsubs[j], dbsubs[i] }) + rand.Shuffle(len(input), func(i, j int) { input[i], input[j] = input[j], input[i] }) - return dbsubs + return input } // CleanSubdomainsOk checks if the subdomains found are well formatted: diff --git a/pkg/opendb/virustotal.go b/pkg/opendb/virustotal.go index fa1fc5a..69c8896 100644 --- a/pkg/opendb/virustotal.go +++ b/pkg/opendb/virustotal.go @@ -36,9 +36,13 @@ import ( ) // VirusTotalSubdomains retrieves from the url below some known subdomains. -func VirusTotalSubdomains(target string, apikey string) []string { +func VirusTotalSubdomains(target, apikey string, plain bool) []string { var result []string + if !plain { + fmt.Println("Pulling data from VirusTotal") + } + client := http.Client{ Timeout: httpUtils.Seconds30, } From 09f0acfc6628dda23ea44056189ec00d398d619a Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 12:31:32 +0200 Subject: [PATCH 03/25] Add new Subdomain sources --- cmd/scilla/main.go | 10 +++++ internal/slice/slice.go | 2 +- pkg/opendb/anubis.go | 77 +++++++++++++++++++++++++++++++++++++++ pkg/opendb/sonar.go | 4 -- pkg/opendb/threatminer.go | 77 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 pkg/opendb/anubis.go create mode 100644 pkg/opendb/threatminer.go diff --git a/cmd/scilla/main.go b/cmd/scilla/main.go index 8d89323..703bbc2 100644 --- a/cmd/scilla/main.go +++ b/cmd/scilla/main.go @@ -174,6 +174,10 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), false) subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) + anubis := opendb.AnubisSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(anubis, subdomains) + threatminer := opendb.ThreatMinerSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(threatminer, subdomains) // Seems Not Working // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), false) @@ -189,6 +193,7 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, // be sure to not scan duplicate values subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) + enumeration.AsyncGet(protocolTemp, subdomains, userInput.ReportIgnoreSub, outputFileJSON, outputFileHTML, outputFileTXT, subs, mutex, false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) @@ -343,6 +348,10 @@ func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) + anubis := opendb.AnubisSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(anubis, subdomains) + threatminer := opendb.ThreatMinerSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(threatminer, subdomains) // Seems Not Working // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) @@ -367,6 +376,7 @@ func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, // be sure to not scan duplicate values subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) + if !userInput.SubdomainNoCheck { enumeration.AsyncGet(protocolTemp, subdomains, userInput.SubdomainIgnore, outputFileJSON, outputFileHTML, outputFileTXT, subs, mutex, userInput.SubdomainPlain, userInput.SubdomainUserAgent, diff --git a/internal/slice/slice.go b/internal/slice/slice.go index da2cb19..358af0f 100644 --- a/internal/slice/slice.go +++ b/internal/slice/slice.go @@ -34,7 +34,7 @@ func RemoveDuplicateValues(strSlice []string) []string { list := []string{} for _, entry := range strSlice { - if _, value := keys[entry]; !value { + if ok := keys[entry]; !ok { keys[entry] = true list = append(list, entry) } diff --git a/pkg/opendb/anubis.go b/pkg/opendb/anubis.go new file mode 100644 index 0000000..de289df --- /dev/null +++ b/pkg/opendb/anubis.go @@ -0,0 +1,77 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package opendb + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + httpUtils "github.com/edoardottt/scilla/internal/http" +) + +// AnubisSubdomains retrieves from the url below some known subdomains. +func AnubisSubdomains(target string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from AnubisDB") + } + + client := http.Client{ + Timeout: httpUtils.Seconds30, + } + + var arr []string + + resp, err := client.Get("https://jonlu.ca/anubis/subdomains/" + target) + if err != nil { + return arr + } + + defer resp.Body.Close() + + if resp.StatusCode == http.StatusOK { + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return arr + } + + bodyString := string(bodyBytes) + err = json.Unmarshal([]byte(bodyString), &arr) + + if err != nil { + return arr + } + } + + for index, elem := range arr { + arr[index] = "http://" + elem + } + + return arr +} diff --git a/pkg/opendb/sonar.go b/pkg/opendb/sonar.go index ac10abe..c86c436 100644 --- a/pkg/opendb/sonar.go +++ b/pkg/opendb/sonar.go @@ -69,9 +69,5 @@ func SonarSubdomains(target string, plain bool) []string { } } - for index, elem := range arr { - arr[index] = "http://" + elem - } - return arr } diff --git a/pkg/opendb/threatminer.go b/pkg/opendb/threatminer.go new file mode 100644 index 0000000..977eeda --- /dev/null +++ b/pkg/opendb/threatminer.go @@ -0,0 +1,77 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package opendb + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + httpUtils "github.com/edoardottt/scilla/internal/http" +) + +// ThreatMinerResult is the struct containing ThreatMiner results. +type ThreatMinerResult struct { + StatusCode string `json:"status_code"` + StatusMessage string `json:"status_message"` + Results []string `json:"results"` +} + +// ThreatMinerSubdomains retrieves from the url below some known subdomains. +func ThreatMinerSubdomains(domain string, plain bool) []string { + if !plain { + fmt.Println("Pulling data from ThreatMiner.org") + } + + client := http.Client{ + Timeout: httpUtils.Seconds30, + } + + var result ThreatMinerResult + + url := "https://api.threatminer.org/v2/domain.php?q=" + domain + "&rt=5" + + resp, err := client.Get(url) + + if err != nil { + return []string{} + } + defer resp.Body.Close() + + output := make([]string, 0) + body, _ := ioutil.ReadAll(resp.Body) + + if err := json.Unmarshal(body, &result); err != nil { + return []string{} + } + + output = append(output, result.Results...) + + return output +} From 2a56e6244f5ed8465390ad9bdded251581dc343c Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 15:46:09 +0200 Subject: [PATCH 04/25] Sub enum using DNS + alive option --- cmd/scilla/main.go | 5 +-- internal/dns/dns.go | 57 +++++++++++++++++++++++++++++++++ pkg/enumeration/subs.go | 70 ++++++++++++++++++++++++----------------- pkg/input/check.go | 17 +++++++++- pkg/input/flags.go | 22 ++++++++++++- pkg/output/subs.go | 4 +-- 6 files changed, 141 insertions(+), 34 deletions(-) create mode 100644 internal/dns/dns.go diff --git a/cmd/scilla/main.go b/cmd/scilla/main.go index 703bbc2..c7e693d 100644 --- a/cmd/scilla/main.go +++ b/cmd/scilla/main.go @@ -195,7 +195,8 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) enumeration.AsyncGet(protocolTemp, subdomains, userInput.ReportIgnoreSub, outputFileJSON, - outputFileHTML, outputFileTXT, subs, mutex, false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) + outputFileHTML, outputFileTXT, subs, mutex, false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent, + userInput.ReportAlive, userInput.ReportDNS) if outputFileHTML != "" { output.FooterHTML(outputFileHTML) @@ -380,7 +381,7 @@ func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, if !userInput.SubdomainNoCheck { enumeration.AsyncGet(protocolTemp, subdomains, userInput.SubdomainIgnore, outputFileJSON, outputFileHTML, outputFileTXT, subs, mutex, userInput.SubdomainPlain, userInput.SubdomainUserAgent, - userInput.SubdomainRandomUserAgent) + userInput.SubdomainRandomUserAgent, userInput.SubdomainAlive, userInput.SubdomainDNS) } else { for _, elem := range subdomains { fmt.Println(elem) diff --git a/internal/dns/dns.go b/internal/dns/dns.go new file mode 100644 index 0000000..bf06c93 --- /dev/null +++ b/internal/dns/dns.go @@ -0,0 +1,57 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils + +import ( + "context" + "net" + "time" +) + +func SimpleDNSLookup(domain string) bool { + ips, err := net.LookupIP(domain) + return err == nil && len(ips) != 0 && !ips[0].IsLoopback() +} + +func CustomDNSLookup(r *net.Resolver, domain string) bool { + ips, err := r.LookupHost(context.Background(), domain) + return err == nil && len(ips) != 0 && !net.ParseIP(ips[0]).IsLoopback() +} + +func NewCustomResolver(customDNS string) *net.Resolver { + r := &net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { + d := net.Dialer{ + Timeout: time.Millisecond * time.Duration(10000), + } + return d.DialContext(ctx, network, customDNS+":53") + }, + } + return r +} diff --git a/pkg/enumeration/subs.go b/pkg/enumeration/subs.go index c34eaa9..da5a299 100644 --- a/pkg/enumeration/subs.go +++ b/pkg/enumeration/subs.go @@ -29,10 +29,12 @@ package enumeration import ( "fmt" + "net" "net/http" "os" "sync" + dnsUtils "github.com/edoardottt/scilla/internal/dns" httpUtils "github.com/edoardottt/scilla/internal/http" ignoreUtils "github.com/edoardottt/scilla/internal/ignore" mathUtils "github.com/edoardottt/scilla/internal/math" @@ -42,7 +44,7 @@ import ( // AsyncGet performs concurrent requests to the specified // urls and prints the results. func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, outputFileHTML, outputFileTXT string, - subs map[string]output.Asset, mutex *sync.Mutex, plain bool, ua string, rua bool) { + subs map[string]output.Asset, mutex *sync.Mutex, plain bool, ua string, rua bool, alive bool, custom string) { ignoreBool := len(ignore) != 0 var count int @@ -53,6 +55,11 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o Timeout: httpUtils.Seconds10, } + var r *net.Resolver + if custom != "" { + r = dnsUtils.NewCustomResolver(custom) + } + channels := 10 limiter := make(chan string, channels) // Limits simultaneous requests waitgroup := sync.WaitGroup{} // Needed to not prematurely exit before all requests have been finished @@ -70,7 +77,7 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o output.PrintSubs(subs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) } - if !plain && count%100 == 0 { // update counter + if !plain && count%10 == 0 { // update counter fmt.Fprint(os.Stdout, "\r \r") fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) } @@ -79,42 +86,49 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o defer waitgroup.Done() defer func() { <-limiter }() - req, err := http.NewRequest("GET", protocol+"://"+domain, nil) - if err != nil { - return - } - - if ua != "Go http/Client" { - req.Header.Set("User-Agent", ua) - } - - if rua { - req.Header.Set("User-Agent", httpUtils.GenerateRandomUserAgent()) - } - - resp, err := client.Do(req) - if err != nil { - return - } - count++ + if !alive { + found := false + if custom != "" { + found = dnsUtils.CustomDNSLookup(r, domain) + } else { + found = dnsUtils.SimpleDNSLookup(domain) + } + if found { + output.AddSubs(domain, "", subs, mutex) + } + } else { + req, err := http.NewRequest("GET", protocol+"://"+domain, nil) + if err != nil { + return + } - if err != nil { - return - } + if ua != "Go http/Client" { + req.Header.Set("User-Agent", ua) + } - if ignoreBool { - if ignoreUtils.IgnoreResponse(resp.StatusCode, ignore) { + if rua { + req.Header.Set("User-Agent", httpUtils.GenerateRandomUserAgent()) + } + + resp, err := client.Do(req) + if err != nil { return } + + if ignoreBool { + if ignoreUtils.IgnoreResponse(resp.StatusCode, ignore) { + return + } + } + + output.AddSubs(domain, resp.Status, subs, mutex) + resp.Body.Close() } - output.AddSubs(domain, resp.Status, subs, mutex) - resp.Body.Close() }(domain) } - output.PrintSubs(subs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) waitgroup.Wait() output.PrintSubs(subs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) diff --git a/pkg/input/check.go b/pkg/input/check.go index e5f5628..071cb97 100644 --- a/pkg/input/check.go +++ b/pkg/input/check.go @@ -193,7 +193,7 @@ func SubdomainSubcommandCheckFlags(subdomainCommand flag.FlagSet, subdomainTarge subdomainNoCheckPtr *bool, subdomainDBPtr *bool, subdomainWordlistPtr *string, subdomainIgnorePtr *string, subdomainCrawlerPtr *bool, subdomainVirusTotalPtr *bool, subdomainOutputJSON, subdomainOutputHTML, subdomainOutputTXT, subdomainUserAgentPtr *string, - subdomainRandomUserAgentPtr *bool) []string { + subdomainRandomUserAgentPtr *bool, subdomainDNSPtr *string, subdomainAlivePtr *bool) []string { // Required Flags if *subdomainTargetPtr == "" { subdomainCommand.PrintDefaults() @@ -267,6 +267,21 @@ func SubdomainSubcommandCheckFlags(subdomainCommand flag.FlagSet, subdomainTarge os.Exit(1) } + if *subdomainNoCheckPtr && *subdomainDNSPtr != "" { + fmt.Println("You can't use no-check with DNS option.") + os.Exit(1) + } + + if *subdomainNoCheckPtr && *subdomainAlivePtr { + fmt.Println("You can't use no-check with alive option.") + os.Exit(1) + } + + if *subdomainDNSPtr != "" && *subdomainAlivePtr { + fmt.Println("You can't use DNS with alive option.") + os.Exit(1) + } + return subdomainIgnore } diff --git a/pkg/input/flags.go b/pkg/input/flags.go index 1b4d788..bd591d9 100644 --- a/pkg/input/flags.go +++ b/pkg/input/flags.go @@ -60,6 +60,8 @@ type Input struct { ReportTimeoutPort int ReportUserAgent string ReportRandomUserAgent bool + ReportDNS string + ReportAlive bool DNSTarget string DNSOutputJSON string DNSOutputHTML string @@ -78,6 +80,8 @@ type Input struct { SubdomainVirusTotal bool SubdomainUserAgent string SubdomainRandomUserAgent bool + SubdomainDNS string + SubdomainAlive bool DirTarget string DirWord string DirOutputJSON string @@ -173,6 +177,12 @@ func ReadArgs() Input { // report subcommand flag pointers reportUserAgentPtr := reportCommand.String("ua", DefaultUserAgent, "Set the User Agent") + // report subcommand flag pointers + reportDNSPtr := reportCommand.String("dns", "", "Set DNS IP to resolve the subdomains") + + // report subcommand flag pointers + reportAlivePtr := reportCommand.Bool("alive", false, "Check also if the subdomains are alive") + // report subcommand flag pointers reportRandomUserAgentPtr := reportCommand.Bool("rua", false, "Generate a random user agent for each request") @@ -231,6 +241,12 @@ func ReadArgs() Input { // subdomains subcommand flag pointers subdomainRandomUserAgentPtr := subdomainCommand.Bool("rua", false, "Generate a random user agent for each request") + // subdomains subcommand flag pointers + subdomainDNSPtr := subdomainCommand.String("dns", "", "Set DNS IP to resolve the subdomains") + + // subdomains subcommand flag pointers + subdomainAlivePtr := subdomainCommand.Bool("alive", false, "Check also if the subdomains are alive") + // dir subcommand flag pointers dirTargetPtr := dirCommand.String("target", "", "Target {URL/IP} (Required)") @@ -411,7 +427,7 @@ func ReadArgs() Input { subdomainNoCheckPtr, subdomainDBPtr, subdomainWordlistPtr, subdomainIgnorePtr, subdomainCrawlerPtr, subdomainVirusTotalPtr, subdomainOutputJSONPtr, subdomainOutputHTMLPtr, subdomainOutputTXTPtr, - subdomainUserAgentPtr, subdomainRandomUserAgentPtr) + subdomainUserAgentPtr, subdomainRandomUserAgentPtr, subdomainDNSPtr, subdomainAlivePtr) } // PORT subcommand @@ -482,6 +498,8 @@ func ReadArgs() Input { *reportTimeoutPortPtr, *reportUserAgentPtr, *reportRandomUserAgentPtr, + *reportDNSPtr, + *reportAlivePtr, *dnsTargetPtr, *dnsOutputJSONPtr, *dnsOutputHTMLPtr, @@ -500,6 +518,8 @@ func ReadArgs() Input { *subdomainVirusTotalPtr, *subdomainUserAgentPtr, *subdomainRandomUserAgentPtr, + *subdomainDNSPtr, + *subdomainAlivePtr, *dirTargetPtr, *dirWordlistPtr, *dirOutputJSONPtr, diff --git a/pkg/output/subs.go b/pkg/output/subs.go index bc926b8..1d82e5c 100644 --- a/pkg/output/subs.go +++ b/pkg/output/subs.go @@ -55,11 +55,11 @@ func PrintSubs(subs map[string]Asset, ignore []string, outputFileJSON, outputFil if !plain { fmt.Fprint(os.Stdout, "\r \r") - if resp[:3] != "404" { + if resp == "" || resp[:3] != "404" { subDomainFound := urlUtils.CleanProtocol(domain) fmt.Printf("[+]FOUND: %s ", subDomainFound) - if string(resp[0]) == "2" { + if resp == "" || string(resp[0]) == "2" { if outputFileJSON != "" { AppendWhere(domain, fmt.Sprint(resp), "SUB", "", "json", outputFileJSON) } From b3b238acfb3dc3baf0d2f2d31b7328a6ccafd05b Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 15:48:26 +0200 Subject: [PATCH 05/25] Add comments - DNS --- internal/dns/dns.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/dns/dns.go b/internal/dns/dns.go index bf06c93..3a30c29 100644 --- a/internal/dns/dns.go +++ b/internal/dns/dns.go @@ -33,16 +33,19 @@ import ( "time" ) +// SimpleDNSLookup performs a DNS lookup using the default system DNS. func SimpleDNSLookup(domain string) bool { ips, err := net.LookupIP(domain) return err == nil && len(ips) != 0 && !ips[0].IsLoopback() } +// CustomDNSLookup performs a DNS lookup using the provided custom DNS. func CustomDNSLookup(r *net.Resolver, domain string) bool { ips, err := r.LookupHost(context.Background(), domain) return err == nil && len(ips) != 0 && !net.ParseIP(ips[0]).IsLoopback() } +// NewCustomResolver returns a DNS resolver using the provided DNS IP. func NewCustomResolver(customDNS string) *net.Resolver { r := &net.Resolver{ PreferGo: true, From 281bdae2702b08be9cf78b4a64d1b76e031d73bc Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 15:49:36 +0200 Subject: [PATCH 06/25] Add comments - DNS --- internal/dns/dns.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/dns/dns.go b/internal/dns/dns.go index 3a30c29..b32442a 100644 --- a/internal/dns/dns.go +++ b/internal/dns/dns.go @@ -33,6 +33,10 @@ import ( "time" ) +const ( + DNSTimeout = 10000 +) + // SimpleDNSLookup performs a DNS lookup using the default system DNS. func SimpleDNSLookup(domain string) bool { ips, err := net.LookupIP(domain) @@ -51,10 +55,11 @@ func NewCustomResolver(customDNS string) *net.Resolver { PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ - Timeout: time.Millisecond * time.Duration(10000), + Timeout: time.Millisecond * time.Duration(DNSTimeout), } return d.DialContext(ctx, network, customDNS+":53") }, } + return r } From 535223429883170adc59a6a9b672602f5b18e079 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:04:00 +0200 Subject: [PATCH 07/25] Add runner --- cmd/scilla/main.go | 486 +------------------------------------ pkg/enumeration/subs.go | 3 +- pkg/runner/runner.go | 521 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 526 insertions(+), 484 deletions(-) create mode 100644 pkg/runner/runner.go diff --git a/cmd/scilla/main.go b/cmd/scilla/main.go index c7e693d..17c3bb2 100644 --- a/cmd/scilla/main.go +++ b/cmd/scilla/main.go @@ -28,494 +28,14 @@ along with this program. If not, see http://www.gnu.org/licenses/. package main import ( - "fmt" - "sync" - - ipUtils "github.com/edoardottt/scilla/internal/ip" - sliceUtils "github.com/edoardottt/scilla/internal/slice" - urlUtils "github.com/edoardottt/scilla/internal/url" - "github.com/edoardottt/scilla/pkg/crawler" - "github.com/edoardottt/scilla/pkg/enumeration" - "github.com/edoardottt/scilla/pkg/input" - "github.com/edoardottt/scilla/pkg/opendb" "github.com/edoardottt/scilla/pkg/output" -) - -const ( - httpProtocol = "http" + "github.com/edoardottt/scilla/pkg/runner" ) // main function. func main() { - input := input.ReadArgs() - // common assets found (only subdomain and dir) + r := runner.New() subs := make(map[string]output.Asset) dirs := make(map[string]output.Asset) - execute(input, subs, dirs, enumeration.CommonPorts()) -} - -// execute reads inputs and starts the correct procedure. -func execute(userInput input.Input, subs map[string]output.Asset, dirs map[string]output.Asset, common []int) { - var mutex = &sync.Mutex{} - - var commandProvided = false - - // :::::::: REPORT SUBCOMMAND HANDLER :::::::: - if userInput.ReportTarget != "" { - commandProvided = true - - ReportSubcommandHandler(userInput, mutex, dirs, subs) - } - - // :::::::: DNS SUBCOMMAND HANDLER :::::::: - if userInput.DNSTarget != "" { - commandProvided = true - - DNSSubcommandHandler(userInput) - } - - // :::::::: SUBDOMAIN SUBCOMMAND HANDLER :::::::: - if userInput.SubdomainTarget != "" { - commandProvided = true - - SubdomainSubcommandHandler(userInput, mutex, dirs, subs) - } - - // :::::::: DIRECTORIES SUBCOMMAND HANDLER :::::::: - if userInput.DirTarget != "" { - commandProvided = true - - DirSubcommandHandler(userInput, mutex, dirs, subs) - } - - // :::::::: PORT SUBCOMMAND HANDLER :::::::: - if userInput.PortTarget != "" { - commandProvided = true - - PortSubcommandHandler(userInput, common) - } - - if !commandProvided { - output.Help() - } -} - -// ReportSubcommandHandler. -func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, - dirs map[string]output.Asset, subs map[string]output.Asset) { - output.Intro() - - target := userInput.ReportTarget - if target[len(target)-1] == byte('/') { - target = target[:len(target)-1] - } - - var protocolTemp string - // if there isn't a scheme use http. - if !urlUtils.ProtocolExists(target) { - protocolTemp = httpProtocol - } else { - protocolTemp = urlUtils.RetrieveProtocol(target) - } - - var targetIP string - - fmt.Printf("target: %s\n", target) - fmt.Println("================ FULL REPORT ========================") - - // - json output - - var outputFileJSON string - if userInput.ReportOutputJSON != "" { - outputFileJSON = output.CreateOutputFile(userInput.ReportOutputJSON) - } - - // - html output - - var outputFileHTML string - if userInput.ReportOutputHTML != "" { - outputFileHTML = output.CreateOutputFile(userInput.ReportOutputHTML) - output.BannerHTML(userInput.ReportTarget, outputFileHTML) - } - - // - txt output - - var outputFileTXT string - if userInput.ReportOutputTXT != "" { - outputFileTXT = output.CreateOutputFile(userInput.ReportOutputTXT) - } - - fmt.Println("================ SCANNING SUBDOMAINS ================") - - var subdomains []string - // change from ip to Hostname - if ipUtils.IsIP(target) { - targetIP = target - target = ipUtils.IPToHostname(targetIP) - } - - target = urlUtils.CleanProtocol(target) - - if outputFileHTML != "" { - output.HeaderHTML("SUBDOMAINS ENUMERATION", outputFileHTML) - } - - if userInput.ReportCrawlerSub { - go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, - userInput.ReportIgnoreSub, dirs, subs, outputFileJSON, outputFileHTML, - outputFileTXT, mutex, "sub", false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) - } - - subdomains = input.CreateSubdomains(userInput.ReportWordSub, protocolTemp, urlUtils.CleanProtocol(target)) - - if userInput.ReportSubdomainDB { - sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(sonar, subdomains) - crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(crtsh, subdomains) - threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) - hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) - anubis := opendb.AnubisSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(anubis, subdomains) - threatminer := opendb.ThreatMinerSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(threatminer, subdomains) - - // Seems Not Working - // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), false) - // subdomains = opendb.AppendDBSubdomains(bufferOverrun, subdomains) - - if userInput.ReportVirusTotal { - vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey(), false) - subdomains = opendb.AppendDBSubdomains(vtSubs, subdomains) - } - - subdomains = opendb.ShuffleSubdomains(subdomains) - } - - // be sure to not scan duplicate values - subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) - - enumeration.AsyncGet(protocolTemp, subdomains, userInput.ReportIgnoreSub, outputFileJSON, - outputFileHTML, outputFileTXT, subs, mutex, false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent, - userInput.ReportAlive, userInput.ReportDNS) - - if outputFileHTML != "" { - output.FooterHTML(outputFileHTML) - } - - if targetIP != "" { - target = targetIP - } - - fmt.Println("================ SCANNING PORTS =====================") - - enumeration.AsyncPort(userInput.PortsArray, userInput.PortArrayBool, userInput.StartPort, userInput.EndPort, - urlUtils.CleanProtocol(target), outputFileJSON, outputFileHTML, outputFileTXT, - userInput.ReportCommon, enumeration.CommonPorts(), false, userInput.ReportTimeoutPort) - - fmt.Println("================ SCANNING DNS =======================") - enumeration.LookupDNS(urlUtils.CleanProtocol(target), outputFileJSON, outputFileHTML, outputFileTXT, false) - - fmt.Println("================ SCANNING DIRECTORIES ===============") - - var strings2 = input.CreateUrls(userInput.ReportWordDir, protocolTemp, urlUtils.CleanProtocol(target)) - - if outputFileHTML != "" { - output.HeaderHTML("DIRECTORIES ENUMERATION", outputFileHTML) - } - - if userInput.ReportCrawlerDir { - go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, - userInput.ReportIgnoreDir, dirs, subs, outputFileJSON, outputFileHTML, outputFileTXT, - mutex, "dir", false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) - } - - enumeration.AsyncDir(strings2, userInput.ReportIgnoreDir, outputFileJSON, outputFileHTML, outputFileTXT, - dirs, mutex, false, userInput.ReportRedirect, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) - - if outputFileHTML != "" { - output.FooterHTML(outputFileHTML) - output.BannerFooterHTML(outputFileHTML) - } -} - -// DNSSubcommandHandler. -func DNSSubcommandHandler(userInput input.Input) { - if !userInput.DNSPlain { - output.Intro() - } - - target := urlUtils.CleanProtocol(userInput.DNSTarget) - // change from ip to Hostname - if ipUtils.IsIP(target) { - target = ipUtils.IPToHostname(target) - } - - if target[len(target)-1] == byte('/') { - target = target[:len(target)-1] - } - - if !userInput.DNSPlain { - fmt.Printf("target: %s\n", target) - fmt.Println("================ SCANNING DNS =======================") - } - - // - json output - - var outputFileJSON string - if userInput.DNSOutputJSON != "" { - outputFileJSON = output.CreateOutputFile(userInput.DNSOutputJSON) - } - - // - html output - - var outputFileHTML string - if userInput.DNSOutputHTML != "" { - outputFileHTML = output.CreateOutputFile(userInput.DNSOutputHTML) - output.BannerHTML(userInput.DNSTarget, outputFileHTML) - } - - // - txt output - - var outputFileTXT string - if userInput.DNSOutputTXT != "" { - outputFileTXT = output.CreateOutputFile(userInput.DNSOutputTXT) - } - - enumeration.LookupDNS(target, outputFileJSON, outputFileHTML, outputFileTXT, userInput.DNSPlain) - - if userInput.DNSOutputHTML != "" { - output.BannerFooterHTML(outputFileHTML) - } -} - -// SubdomainSubcommandHandler. -func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, - dirs map[string]output.Asset, subs map[string]output.Asset) { - if !userInput.SubdomainPlain { - output.Intro() - } - - target := userInput.SubdomainTarget - - var protocolTemp string - // if there isn't a scheme use http. - if !urlUtils.ProtocolExists(target) { - protocolTemp = httpProtocol - } else { - protocolTemp = urlUtils.RetrieveProtocol(target) - } - - // change from ip to Hostname - if ipUtils.IsIP(target) { - target = ipUtils.IPToHostname(target) - } - - if target[len(target)-1] == byte('/') { - target = target[:len(target)-1] - } - - if !userInput.SubdomainPlain { - fmt.Printf("target: %s\n", target) - fmt.Println("================ SCANNING SUBDOMAINS ================") - } - - // - json output - - var outputFileJSON string - if userInput.SubdomainOutputJSON != "" { - outputFileJSON = output.CreateOutputFile(userInput.SubdomainOutputJSON) - } - - // - html output - - var outputFileHTML string - if userInput.SubdomainOutputHTML != "" { - outputFileHTML = output.CreateOutputFile(userInput.SubdomainOutputHTML) - output.BannerHTML(userInput.SubdomainTarget, outputFileHTML) - } - - // - txt output - - var outputFileTXT string - if userInput.SubdomainOutputTXT != "" { - outputFileTXT = output.CreateOutputFile(userInput.SubdomainOutputTXT) - } - - var subdomains []string - if !userInput.SubdomainNoCheck { - subdomains = input.CreateSubdomains(userInput.SubdomainWord, protocolTemp, urlUtils.CleanProtocol(target)) - } - - if userInput.SubdomainDB { - sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) - subdomains = opendb.AppendDBSubdomains(sonar, subdomains) - crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) - subdomains = opendb.AppendDBSubdomains(crtsh, subdomains) - threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) - subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) - hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) - subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) - anubis := opendb.AnubisSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(anubis, subdomains) - threatminer := opendb.ThreatMinerSubdomains(urlUtils.CleanProtocol(target), false) - subdomains = opendb.AppendDBSubdomains(threatminer, subdomains) - - // Seems Not Working - // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) - // subdomains = opendb.AppendDBSubdomains(bufferOverrun, subdomains) - - if userInput.SubdomainVirusTotal { - vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey(), - userInput.SubdomainPlain) - subdomains = opendb.AppendDBSubdomains(vtSubs, subdomains) - } - } - - if outputFileHTML != "" { - output.HeaderHTML("SUBDOMAINS ENUMERATION", outputFileHTML) - } - - if userInput.SubdomainCrawler && !userInput.SubdomainNoCheck { - go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, - userInput.SubdomainIgnore, dirs, subs, outputFileJSON, outputFileHTML, outputFileTXT, - mutex, "sub", userInput.SubdomainPlain, userInput.SubdomainUserAgent, userInput.SubdomainRandomUserAgent) - } - - // be sure to not scan duplicate values - subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) - - if !userInput.SubdomainNoCheck { - enumeration.AsyncGet(protocolTemp, subdomains, userInput.SubdomainIgnore, outputFileJSON, outputFileHTML, - outputFileTXT, subs, mutex, userInput.SubdomainPlain, userInput.SubdomainUserAgent, - userInput.SubdomainRandomUserAgent, userInput.SubdomainAlive, userInput.SubdomainDNS) - } else { - for _, elem := range subdomains { - fmt.Println(elem) - if outputFileJSON != "" { - output.AppendOutputToJSON(elem, "SUB", "", outputFileJSON) - } - if outputFileHTML != "" { - output.AppendOutputToHTML(elem, "", outputFileHTML) - } - if outputFileTXT != "" { - output.AppendOutputToTxt(elem, outputFileTXT) - } - } - } - - if outputFileHTML != "" { - output.FooterHTML(outputFileHTML) - output.BannerFooterHTML(outputFileHTML) - } -} - -// DirSubcommandHandler. -func DirSubcommandHandler(userInput input.Input, mutex *sync.Mutex, - dirs map[string]output.Asset, subs map[string]output.Asset) { - if !userInput.DirPlain { - output.Intro() - } - - target := userInput.DirTarget - - var protocolTemp string - - // if there isn't a scheme use http. - if !urlUtils.ProtocolExists(target) { - protocolTemp = httpProtocol - } else { - protocolTemp = urlUtils.RetrieveProtocol(target) - } - - if target[len(target)-1] == byte('/') { - target = target[:len(target)-1] - } - - if !userInput.DirPlain { - fmt.Printf("target: %s\n", target) - fmt.Println("================ SCANNING DIRECTORIES ===============") - } - - target = urlUtils.CleanProtocol(target) - - // - json output - - var outputFileJSON string - if userInput.DirOutputJSON != "" { - outputFileJSON = output.CreateOutputFile(userInput.DirOutputJSON) - } - - // - html output - - var outputFileHTML string - if userInput.DirOutputHTML != "" { - outputFileHTML = output.CreateOutputFile(userInput.DirOutputHTML) - output.BannerHTML(userInput.DirTarget, outputFileHTML) - } - - // - txt output - - var outputFileTXT string - if userInput.DirOutputTXT != "" { - outputFileTXT = output.CreateOutputFile(userInput.DirOutputTXT) - } - - var strings2 = input.CreateUrls(userInput.DirWord, protocolTemp, target) - - if outputFileHTML != "" { - output.HeaderHTML("DIRECTORIES ENUMERATION", outputFileHTML) - } - - if userInput.DirCrawler { - go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, - userInput.DirIgnore, dirs, subs, outputFileJSON, outputFileHTML, outputFileTXT, - mutex, "dir", userInput.DirPlain, userInput.DirUserAgent, userInput.DirRandomUserAgent) - } - - enumeration.AsyncDir(strings2, userInput.DirIgnore, outputFileJSON, outputFileHTML, outputFileTXT, - dirs, mutex, userInput.DirPlain, userInput.DirRedirect, userInput.DirUserAgent, userInput.DirRandomUserAgent) - - if outputFileHTML != "" { - output.FooterHTML(outputFileHTML) - output.BannerFooterHTML(outputFileHTML) - } -} - -// PortSubcommandHandler. -func PortSubcommandHandler(userInput input.Input, common []int) { - if !userInput.PortPlain { - output.Intro() - } - - target := userInput.PortTarget - if urlUtils.IsURL(target) { - target = urlUtils.CleanProtocol(userInput.PortTarget) - } - - if target[len(target)-1] == byte('/') { - target = target[:len(target)-1] - } - - // - json output - - var outputFileJSON string - if userInput.PortOutputJSON != "" { - outputFileJSON = output.CreateOutputFile(userInput.PortOutputJSON) - } - - // - html output - - var outputFileHTML string - if userInput.PortOutputHTML != "" { - outputFileHTML = output.CreateOutputFile(userInput.PortOutputHTML) - output.BannerHTML(userInput.PortTarget, outputFileHTML) - } - - // - txt output - - var outputFileTXT string - if userInput.PortOutputTXT != "" { - outputFileTXT = output.CreateOutputFile(userInput.PortOutputTXT) - } - - if !userInput.PortPlain { - fmt.Printf("target: %s\n", target) - fmt.Println("================ SCANNING PORTS =====================") - } - - enumeration.AsyncPort(userInput.PortsArray, userInput.PortArrayBool, userInput.StartPort, userInput.EndPort, - target, outputFileJSON, outputFileHTML, outputFileTXT, - userInput.PortCommon, common, userInput.PortPlain, userInput.PortTimeout) - - if userInput.PortOutputHTML != "" { - output.BannerFooterHTML(outputFileHTML) - } + r.Execute(subs, dirs) } diff --git a/pkg/enumeration/subs.go b/pkg/enumeration/subs.go index da5a299..7a28037 100644 --- a/pkg/enumeration/subs.go +++ b/pkg/enumeration/subs.go @@ -87,6 +87,7 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o defer func() { <-limiter }() count++ + if !alive { found := false if custom != "" { @@ -94,6 +95,7 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o } else { found = dnsUtils.SimpleDNSLookup(domain) } + if found { output.AddSubs(domain, "", subs, mutex) } @@ -125,7 +127,6 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o output.AddSubs(domain, resp.Status, subs, mutex) resp.Body.Close() } - }(domain) } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go new file mode 100644 index 0000000..210df15 --- /dev/null +++ b/pkg/runner/runner.go @@ -0,0 +1,521 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package runner + +import ( + "fmt" + "sync" + + ipUtils "github.com/edoardottt/scilla/internal/ip" + sliceUtils "github.com/edoardottt/scilla/internal/slice" + urlUtils "github.com/edoardottt/scilla/internal/url" + "github.com/edoardottt/scilla/pkg/crawler" + "github.com/edoardottt/scilla/pkg/enumeration" + "github.com/edoardottt/scilla/pkg/input" + "github.com/edoardottt/scilla/pkg/opendb" + "github.com/edoardottt/scilla/pkg/output" +) + +const ( + httpProtocol = "http" +) + +// Runner. +type Runner struct { + Input input.Input +} + +// New returns a new Runner with the provided input. +func New() *Runner { + input := input.ReadArgs() + return &Runner{Input: input} +} + +// Execute reads the input and starts the correct procedure. +func (r *Runner) Execute(dirs, subs map[string]output.Asset) { + var mutex = &sync.Mutex{} + var commandProvided = false + // :::::::: REPORT SUBCOMMAND HANDLER :::::::: + if r.Input.ReportTarget != "" { + commandProvided = true + + ReportSubcommandHandler(r.Input, mutex, dirs, subs) + } + + // :::::::: DNS SUBCOMMAND HANDLER :::::::: + if r.Input.DNSTarget != "" { + commandProvided = true + + DNSSubcommandHandler(r.Input) + } + + // :::::::: SUBDOMAIN SUBCOMMAND HANDLER :::::::: + if r.Input.SubdomainTarget != "" { + commandProvided = true + + SubdomainSubcommandHandler(r.Input, mutex, dirs, subs) + } + + // :::::::: DIRECTORIES SUBCOMMAND HANDLER :::::::: + if r.Input.DirTarget != "" { + commandProvided = true + + DirSubcommandHandler(r.Input, mutex, dirs, subs) + } + + // :::::::: PORT SUBCOMMAND HANDLER :::::::: + if r.Input.PortTarget != "" { + commandProvided = true + + PortSubcommandHandler(r.Input, enumeration.CommonPorts()) + } + + if !commandProvided { + output.Help() + } +} + +// ReportSubcommandHandler. +func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, + dirs map[string]output.Asset, subs map[string]output.Asset) { + output.Intro() + + target := userInput.ReportTarget + if target[len(target)-1] == byte('/') { + target = target[:len(target)-1] + } + + var protocolTemp string + // if there isn't a scheme use http. + if !urlUtils.ProtocolExists(target) { + protocolTemp = httpProtocol + } else { + protocolTemp = urlUtils.RetrieveProtocol(target) + } + + var targetIP string + + fmt.Printf("target: %s\n", target) + fmt.Println("================ FULL REPORT ========================") + + // - json output - + var outputFileJSON string + if userInput.ReportOutputJSON != "" { + outputFileJSON = output.CreateOutputFile(userInput.ReportOutputJSON) + } + + // - html output - + var outputFileHTML string + if userInput.ReportOutputHTML != "" { + outputFileHTML = output.CreateOutputFile(userInput.ReportOutputHTML) + output.BannerHTML(userInput.ReportTarget, outputFileHTML) + } + + // - txt output - + var outputFileTXT string + if userInput.ReportOutputTXT != "" { + outputFileTXT = output.CreateOutputFile(userInput.ReportOutputTXT) + } + + fmt.Println("================ SCANNING SUBDOMAINS ================") + + var subdomains []string + // change from ip to Hostname + if ipUtils.IsIP(target) { + targetIP = target + target = ipUtils.IPToHostname(targetIP) + } + + target = urlUtils.CleanProtocol(target) + + if outputFileHTML != "" { + output.HeaderHTML("SUBDOMAINS ENUMERATION", outputFileHTML) + } + + if userInput.ReportCrawlerSub { + go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, + userInput.ReportIgnoreSub, dirs, subs, outputFileJSON, outputFileHTML, + outputFileTXT, mutex, "sub", false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) + } + + subdomains = input.CreateSubdomains(userInput.ReportWordSub, protocolTemp, urlUtils.CleanProtocol(target)) + + if userInput.ReportSubdomainDB { + sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(sonar, subdomains) + crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(crtsh, subdomains) + threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) + hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) + anubis := opendb.AnubisSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(anubis, subdomains) + threatminer := opendb.ThreatMinerSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(threatminer, subdomains) + + // Seems Not Working + // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), false) + // subdomains = opendb.AppendDBSubdomains(bufferOverrun, subdomains) + + if userInput.ReportVirusTotal { + vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey(), false) + subdomains = opendb.AppendDBSubdomains(vtSubs, subdomains) + } + + subdomains = opendb.ShuffleSubdomains(subdomains) + } + + // be sure to not scan duplicate values + subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) + + enumeration.AsyncGet(protocolTemp, subdomains, userInput.ReportIgnoreSub, outputFileJSON, + outputFileHTML, outputFileTXT, subs, mutex, false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent, + userInput.ReportAlive, userInput.ReportDNS) + + if outputFileHTML != "" { + output.FooterHTML(outputFileHTML) + } + + if targetIP != "" { + target = targetIP + } + + fmt.Println("================ SCANNING PORTS =====================") + + enumeration.AsyncPort(userInput.PortsArray, userInput.PortArrayBool, userInput.StartPort, userInput.EndPort, + urlUtils.CleanProtocol(target), outputFileJSON, outputFileHTML, outputFileTXT, + userInput.ReportCommon, enumeration.CommonPorts(), false, userInput.ReportTimeoutPort) + + fmt.Println("================ SCANNING DNS =======================") + enumeration.LookupDNS(urlUtils.CleanProtocol(target), outputFileJSON, outputFileHTML, outputFileTXT, false) + + fmt.Println("================ SCANNING DIRECTORIES ===============") + + var strings2 = input.CreateUrls(userInput.ReportWordDir, protocolTemp, urlUtils.CleanProtocol(target)) + + if outputFileHTML != "" { + output.HeaderHTML("DIRECTORIES ENUMERATION", outputFileHTML) + } + + if userInput.ReportCrawlerDir { + go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, + userInput.ReportIgnoreDir, dirs, subs, outputFileJSON, outputFileHTML, outputFileTXT, + mutex, "dir", false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) + } + + enumeration.AsyncDir(strings2, userInput.ReportIgnoreDir, outputFileJSON, outputFileHTML, outputFileTXT, + dirs, mutex, false, userInput.ReportRedirect, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) + + if outputFileHTML != "" { + output.FooterHTML(outputFileHTML) + output.BannerFooterHTML(outputFileHTML) + } +} + +// DNSSubcommandHandler. +func DNSSubcommandHandler(userInput input.Input) { + if !userInput.DNSPlain { + output.Intro() + } + + target := urlUtils.CleanProtocol(userInput.DNSTarget) + // change from ip to Hostname + if ipUtils.IsIP(target) { + target = ipUtils.IPToHostname(target) + } + + if target[len(target)-1] == byte('/') { + target = target[:len(target)-1] + } + + if !userInput.DNSPlain { + fmt.Printf("target: %s\n", target) + fmt.Println("================ SCANNING DNS =======================") + } + + // - json output - + var outputFileJSON string + if userInput.DNSOutputJSON != "" { + outputFileJSON = output.CreateOutputFile(userInput.DNSOutputJSON) + } + + // - html output - + var outputFileHTML string + if userInput.DNSOutputHTML != "" { + outputFileHTML = output.CreateOutputFile(userInput.DNSOutputHTML) + output.BannerHTML(userInput.DNSTarget, outputFileHTML) + } + + // - txt output - + var outputFileTXT string + if userInput.DNSOutputTXT != "" { + outputFileTXT = output.CreateOutputFile(userInput.DNSOutputTXT) + } + + enumeration.LookupDNS(target, outputFileJSON, outputFileHTML, outputFileTXT, userInput.DNSPlain) + + if userInput.DNSOutputHTML != "" { + output.BannerFooterHTML(outputFileHTML) + } +} + +// SubdomainSubcommandHandler. +func SubdomainSubcommandHandler(userInput input.Input, mutex *sync.Mutex, + dirs map[string]output.Asset, subs map[string]output.Asset) { + if !userInput.SubdomainPlain { + output.Intro() + } + + target := userInput.SubdomainTarget + + var protocolTemp string + // if there isn't a scheme use http. + if !urlUtils.ProtocolExists(target) { + protocolTemp = httpProtocol + } else { + protocolTemp = urlUtils.RetrieveProtocol(target) + } + + // change from ip to Hostname + if ipUtils.IsIP(target) { + target = ipUtils.IPToHostname(target) + } + + if target[len(target)-1] == byte('/') { + target = target[:len(target)-1] + } + + if !userInput.SubdomainPlain { + fmt.Printf("target: %s\n", target) + fmt.Println("================ SCANNING SUBDOMAINS ================") + } + + // - json output - + var outputFileJSON string + if userInput.SubdomainOutputJSON != "" { + outputFileJSON = output.CreateOutputFile(userInput.SubdomainOutputJSON) + } + + // - html output - + var outputFileHTML string + if userInput.SubdomainOutputHTML != "" { + outputFileHTML = output.CreateOutputFile(userInput.SubdomainOutputHTML) + output.BannerHTML(userInput.SubdomainTarget, outputFileHTML) + } + + // - txt output - + var outputFileTXT string + if userInput.SubdomainOutputTXT != "" { + outputFileTXT = output.CreateOutputFile(userInput.SubdomainOutputTXT) + } + + var subdomains []string + if !userInput.SubdomainNoCheck { + subdomains = input.CreateSubdomains(userInput.SubdomainWord, protocolTemp, urlUtils.CleanProtocol(target)) + } + + if userInput.SubdomainDB { + sonar := opendb.SonarSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(sonar, subdomains) + crtsh := opendb.CrtshSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(crtsh, subdomains) + threatcrowd := opendb.ThreatcrowdSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(threatcrowd, subdomains) + hackerTarget := opendb.HackerTargetSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(hackerTarget, subdomains) + anubis := opendb.AnubisSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(anubis, subdomains) + threatminer := opendb.ThreatMinerSubdomains(urlUtils.CleanProtocol(target), false) + subdomains = opendb.AppendDBSubdomains(threatminer, subdomains) + + // Seems Not Working + // bufferOverrun := opendb.BufferOverrunSubdomains(urlUtils.CleanProtocol(target), userInput.SubdomainPlain) + // subdomains = opendb.AppendDBSubdomains(bufferOverrun, subdomains) + + if userInput.SubdomainVirusTotal { + vtSubs := opendb.VirusTotalSubdomains(urlUtils.CleanProtocol(target), input.GetVirusTotalKey(), + userInput.SubdomainPlain) + subdomains = opendb.AppendDBSubdomains(vtSubs, subdomains) + } + } + + if outputFileHTML != "" { + output.HeaderHTML("SUBDOMAINS ENUMERATION", outputFileHTML) + } + + if userInput.SubdomainCrawler && !userInput.SubdomainNoCheck { + go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, + userInput.SubdomainIgnore, dirs, subs, outputFileJSON, outputFileHTML, outputFileTXT, + mutex, "sub", userInput.SubdomainPlain, userInput.SubdomainUserAgent, userInput.SubdomainRandomUserAgent) + } + + // be sure to not scan duplicate values + subdomains = sliceUtils.RemoveDuplicateValues(urlUtils.CleanSubdomainsOk(urlUtils.CleanProtocol(target), subdomains)) + + if !userInput.SubdomainNoCheck { + enumeration.AsyncGet(protocolTemp, subdomains, userInput.SubdomainIgnore, outputFileJSON, outputFileHTML, + outputFileTXT, subs, mutex, userInput.SubdomainPlain, userInput.SubdomainUserAgent, + userInput.SubdomainRandomUserAgent, userInput.SubdomainAlive, userInput.SubdomainDNS) + } else { + for _, elem := range subdomains { + fmt.Println(elem) + if outputFileJSON != "" { + output.AppendOutputToJSON(elem, "SUB", "", outputFileJSON) + } + if outputFileHTML != "" { + output.AppendOutputToHTML(elem, "", outputFileHTML) + } + if outputFileTXT != "" { + output.AppendOutputToTxt(elem, outputFileTXT) + } + } + } + + if outputFileHTML != "" { + output.FooterHTML(outputFileHTML) + output.BannerFooterHTML(outputFileHTML) + } +} + +// DirSubcommandHandler. +func DirSubcommandHandler(userInput input.Input, mutex *sync.Mutex, + dirs map[string]output.Asset, subs map[string]output.Asset) { + if !userInput.DirPlain { + output.Intro() + } + + target := userInput.DirTarget + + var protocolTemp string + + // if there isn't a scheme use http. + if !urlUtils.ProtocolExists(target) { + protocolTemp = httpProtocol + } else { + protocolTemp = urlUtils.RetrieveProtocol(target) + } + + if target[len(target)-1] == byte('/') { + target = target[:len(target)-1] + } + + if !userInput.DirPlain { + fmt.Printf("target: %s\n", target) + fmt.Println("================ SCANNING DIRECTORIES ===============") + } + + target = urlUtils.CleanProtocol(target) + + // - json output - + var outputFileJSON string + if userInput.DirOutputJSON != "" { + outputFileJSON = output.CreateOutputFile(userInput.DirOutputJSON) + } + + // - html output - + var outputFileHTML string + if userInput.DirOutputHTML != "" { + outputFileHTML = output.CreateOutputFile(userInput.DirOutputHTML) + output.BannerHTML(userInput.DirTarget, outputFileHTML) + } + + // - txt output - + var outputFileTXT string + if userInput.DirOutputTXT != "" { + outputFileTXT = output.CreateOutputFile(userInput.DirOutputTXT) + } + + var strings2 = input.CreateUrls(userInput.DirWord, protocolTemp, target) + + if outputFileHTML != "" { + output.HeaderHTML("DIRECTORIES ENUMERATION", outputFileHTML) + } + + if userInput.DirCrawler { + go crawler.SpawnCrawler(urlUtils.CleanProtocol(target), protocolTemp, + userInput.DirIgnore, dirs, subs, outputFileJSON, outputFileHTML, outputFileTXT, + mutex, "dir", userInput.DirPlain, userInput.DirUserAgent, userInput.DirRandomUserAgent) + } + + enumeration.AsyncDir(strings2, userInput.DirIgnore, outputFileJSON, outputFileHTML, outputFileTXT, + dirs, mutex, userInput.DirPlain, userInput.DirRedirect, userInput.DirUserAgent, userInput.DirRandomUserAgent) + + if outputFileHTML != "" { + output.FooterHTML(outputFileHTML) + output.BannerFooterHTML(outputFileHTML) + } +} + +// PortSubcommandHandler. +func PortSubcommandHandler(userInput input.Input, common []int) { + if !userInput.PortPlain { + output.Intro() + } + + target := userInput.PortTarget + if urlUtils.IsURL(target) { + target = urlUtils.CleanProtocol(userInput.PortTarget) + } + + if target[len(target)-1] == byte('/') { + target = target[:len(target)-1] + } + + // - json output - + var outputFileJSON string + if userInput.PortOutputJSON != "" { + outputFileJSON = output.CreateOutputFile(userInput.PortOutputJSON) + } + + // - html output - + var outputFileHTML string + if userInput.PortOutputHTML != "" { + outputFileHTML = output.CreateOutputFile(userInput.PortOutputHTML) + output.BannerHTML(userInput.PortTarget, outputFileHTML) + } + + // - txt output - + var outputFileTXT string + if userInput.PortOutputTXT != "" { + outputFileTXT = output.CreateOutputFile(userInput.PortOutputTXT) + } + + if !userInput.PortPlain { + fmt.Printf("target: %s\n", target) + fmt.Println("================ SCANNING PORTS =====================") + } + + enumeration.AsyncPort(userInput.PortsArray, userInput.PortArrayBool, userInput.StartPort, userInput.EndPort, + target, outputFileJSON, outputFileHTML, outputFileTXT, + userInput.PortCommon, common, userInput.PortPlain, userInput.PortTimeout) + + if userInput.PortOutputHTML != "" { + output.BannerFooterHTML(outputFileHTML) + } +} From a60048afd0611291c65e79b7032f6292b2d97cf7 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:04:36 +0200 Subject: [PATCH 08/25] Add runner --- pkg/runner/runner.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 210df15..e2ad2be 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -58,8 +58,11 @@ func New() *Runner { // Execute reads the input and starts the correct procedure. func (r *Runner) Execute(dirs, subs map[string]output.Asset) { - var mutex = &sync.Mutex{} - var commandProvided = false + var ( + mutex = &sync.Mutex{} + commandProvided = false + ) + // :::::::: REPORT SUBCOMMAND HANDLER :::::::: if r.Input.ReportTarget != "" { commandProvided = true From 962f79f813973856c80e5916766d34560dc57af9 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:09:06 +0200 Subject: [PATCH 09/25] minor code change --- pkg/runner/runner.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index e2ad2be..cccd4b9 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -220,7 +220,7 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, fmt.Println("================ SCANNING DIRECTORIES ===============") - var strings2 = input.CreateUrls(userInput.ReportWordDir, protocolTemp, urlUtils.CleanProtocol(target)) + var urls = input.CreateUrls(userInput.ReportWordDir, protocolTemp, urlUtils.CleanProtocol(target)) if outputFileHTML != "" { output.HeaderHTML("DIRECTORIES ENUMERATION", outputFileHTML) @@ -232,7 +232,7 @@ func ReportSubcommandHandler(userInput input.Input, mutex *sync.Mutex, mutex, "dir", false, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) } - enumeration.AsyncDir(strings2, userInput.ReportIgnoreDir, outputFileJSON, outputFileHTML, outputFileTXT, + enumeration.AsyncDir(urls, userInput.ReportIgnoreDir, outputFileJSON, outputFileHTML, outputFileTXT, dirs, mutex, false, userInput.ReportRedirect, userInput.ReportUserAgent, userInput.ReportRandomUserAgent) if outputFileHTML != "" { @@ -454,7 +454,7 @@ func DirSubcommandHandler(userInput input.Input, mutex *sync.Mutex, outputFileTXT = output.CreateOutputFile(userInput.DirOutputTXT) } - var strings2 = input.CreateUrls(userInput.DirWord, protocolTemp, target) + var urls = input.CreateUrls(userInput.DirWord, protocolTemp, target) if outputFileHTML != "" { output.HeaderHTML("DIRECTORIES ENUMERATION", outputFileHTML) @@ -466,7 +466,7 @@ func DirSubcommandHandler(userInput input.Input, mutex *sync.Mutex, mutex, "dir", userInput.DirPlain, userInput.DirUserAgent, userInput.DirRandomUserAgent) } - enumeration.AsyncDir(strings2, userInput.DirIgnore, outputFileJSON, outputFileHTML, outputFileTXT, + enumeration.AsyncDir(urls, userInput.DirIgnore, outputFileJSON, outputFileHTML, outputFileTXT, dirs, mutex, userInput.DirPlain, userInput.DirRedirect, userInput.DirUserAgent, userInput.DirRandomUserAgent) if outputFileHTML != "" { From c0aa19146b26a13ad791ec50c3740d466bac0255 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:09:36 +0200 Subject: [PATCH 10/25] minor code change --- cmd/scilla/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/scilla/main.go b/cmd/scilla/main.go index 17c3bb2..347ebf8 100644 --- a/cmd/scilla/main.go +++ b/cmd/scilla/main.go @@ -32,7 +32,6 @@ import ( "github.com/edoardottt/scilla/pkg/runner" ) -// main function. func main() { r := runner.New() subs := make(map[string]output.Asset) From ed6bed9f839a905963b8641435d087d49d216373 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:29:49 +0200 Subject: [PATCH 11/25] Update subs --- lists/subdomains.txt | 158 ++----------------------------------------- 1 file changed, 6 insertions(+), 152 deletions(-) diff --git a/lists/subdomains.txt b/lists/subdomains.txt index f2d98c3..8b31bba 100644 --- a/lists/subdomains.txt +++ b/lists/subdomains.txt @@ -460,7 +460,6 @@ ticket js ns9 outlook -MAIL foto www.en pro @@ -887,6 +886,7 @@ hydra usa digital wireless +windowsts banners md mysite @@ -898,8 +898,10 @@ hrm database mysql1 inside +tsweb debian pc +terminalservices ask backend cz @@ -1102,7 +1104,6 @@ www.us msk widget study -11290521402560 posta ee realestate @@ -1150,7 +1151,6 @@ z securemail www-test wmail -123 sonic netflow enterprise @@ -1182,7 +1182,6 @@ simple e-learning fire cb -WWW edi rsc yellow @@ -1433,6 +1432,7 @@ libra rose cloud1 album +ahwp 3 antares www.a @@ -1832,6 +1832,7 @@ quit proxy3 email2 b2 +charger servicios novo new2 @@ -2504,7 +2505,6 @@ zt daniel roundcube paper -24 sus splash zzz @@ -2955,7 +2955,6 @@ sympa dv webdisk.games coop -50 blackhole 3d cma @@ -3533,7 +3532,6 @@ alerts dvd bsc mec -20 m.test eye www.monitor @@ -3617,7 +3615,6 @@ srv6 ig frodo afisha -25 factory winter harmony @@ -3657,7 +3654,6 @@ russia vc1 chemie h4 -15 dvr tunnel 5 @@ -3890,7 +3886,6 @@ graduate webdisk.videos adrian mic -13 firma www.dubious.users windu @@ -4271,7 +4266,6 @@ ecs beta3 www.proxy zsb -44 ww6 nautilus angels @@ -4435,7 +4429,6 @@ golden travian www.cat www.biz -54 demo10 bambi ivanovo @@ -4556,7 +4549,6 @@ estadisticas blast phys rsm -70 vvv kris agro @@ -4671,7 +4663,6 @@ vologda arcadia www.cc util -16 tyumen desire perl @@ -4770,7 +4761,6 @@ www.acc zmail statics ns102 -39 idb h5 connect2 @@ -5017,7 +5007,6 @@ privacy promos prov2 c.ns -88 oyun alexandria second @@ -5161,13 +5150,11 @@ bilbo coupang4 fb12 wlan-switch -21 offsite fluffy joker arcade cielo -17 server16 mss wonder @@ -5238,8 +5225,6 @@ alpha1 tablet grad tony -14 -18 memory jeu anuncios @@ -5256,7 +5241,6 @@ est goat sg1 etherpad -37 aplicaciones www.webinar thai @@ -5265,7 +5249,6 @@ mass hqjt region itech -1234 demo11 www.ic orenburg @@ -5477,14 +5460,12 @@ salem linda tamil armstrong -79 norman quartz scheduler socrates regist server24 -MX campusvirtual ip4 alien @@ -5565,7 +5546,6 @@ economy www.moto www.corp nirvana -35 iklan commercial rooster @@ -5594,7 +5574,6 @@ ted usuarios relaunch ismtp -49 israel www.click s110 @@ -5694,7 +5673,6 @@ smtp8 voipA02D voipA02C iec -114 voipA037 quest mail30 @@ -5946,7 +5924,6 @@ voipA013 vault fisheye tron -29 chevrolet square srvc42 @@ -6100,7 +6077,6 @@ ltx voipA07F lj jwxt -19 klm voipA05F cie @@ -6142,7 +6118,6 @@ razor infinite lucifer w9 -48 bgs tzb dennis @@ -6335,7 +6310,6 @@ api3 taxi frontier yuyu -34 reading vm02 venture @@ -6382,7 +6356,6 @@ educ piter crow zenith -46 sabrina voip2 jet @@ -6396,7 +6369,6 @@ gimli bara treehouse solid -51 valiant vm5 michigan @@ -6560,8 +6532,6 @@ helsinki cheese test19 www.as -s203 -27 autodiscover.radio ne financeiro @@ -6575,21 +6545,17 @@ cluster2 dev6 xs bliss -60 tatiana mature babel -26 xinli pustaka mydesktop www.n carter -22 kobe testing2 my2 -90 explorer wy ftp9 @@ -6608,13 +6574,10 @@ ftp8 wz www-c nws -s202 -80 bgr01SWD voltage-pp-0000 itm im.rtpete -23 assets1 johnny street @@ -6691,7 +6654,6 @@ lucas ganesh mik member1 -31 mali noel ero @@ -6708,7 +6670,6 @@ designs CAR40.net elc lp3 -TS sta CSR21.arch pallas @@ -6743,7 +6704,6 @@ mami mybook topsites statistic -66 gomez pamela listings @@ -6865,7 +6825,6 @@ stb consulta dingo cmail -67 saba fairy bluemoon @@ -6902,7 +6861,6 @@ demoshop horoscope puck egroupware -40 sup sv7 three @@ -6912,7 +6870,6 @@ mail06 mhs pasca wps -53 postit wii smf @@ -6922,7 +6879,6 @@ utopia vm01 vi dms1 -52 citrix2 mxbackup vm6 @@ -7320,7 +7276,6 @@ blade3 www.pic unreal b13 -112 acp haru mailservice @@ -7396,7 +7351,6 @@ profil arg freemail ns57 -42 shara opal www.css @@ -7420,7 +7374,6 @@ barry amadeus www.yaroslavl bluebell -45 smtp13 www.tutorial drop @@ -7445,7 +7398,6 @@ deli mq www.todo adel -47 drake info2 mktg @@ -7524,7 +7476,6 @@ sklad eform devdb www.test4 -61 www.like s224 andres @@ -7557,7 +7508,6 @@ titus uran led webdisk.us -69 juniper shams repos @@ -7606,7 +7556,6 @@ knight papercut timothy rns1 -77 shin primrose dep @@ -7718,7 +7667,6 @@ ftp.demo www.pomoc qm eddy -32 absolute kan espresso @@ -7781,10 +7729,8 @@ autodiscover.download itadmin ultra1 yamaha -57 must newman -63 mail-gw autodiscover.client bbs2 @@ -7809,7 +7755,6 @@ labo oriflame www.noticias devwww -30 www.festival tpc net-xb.ohx @@ -7828,7 +7773,6 @@ hiroshima zend www.sites carrie -76 olap dc4 binary @@ -7842,12 +7786,10 @@ gravity webdisk.design aviation rst -94 boxer hilbert herbalife carrier -64 nexgen intranet1 willie @@ -7897,7 +7839,6 @@ writers cmdb muenchen oldforum -111 libweb esx5 benefits @@ -7905,7 +7846,6 @@ www.asia scl pws esx6 -28 gutenberg django caldav @@ -7914,7 +7854,6 @@ tracker2 mov lumiere tracker1 -33 manhattan kaku maga @@ -7944,7 +7883,6 @@ regina nantes wm1 ns47 -41 citrix1 citron zw @@ -7963,7 +7901,6 @@ www.sm resolver2 ns120 wwb -101 patriot portugal porsche @@ -8030,7 +7967,6 @@ maximus heritage smoke lo.vip -163 santa popeye prefs.vip @@ -8038,7 +7974,6 @@ asc s04 lingua amc -203 dnsadmin jsj s66 @@ -8771,7 +8706,6 @@ dickson livemediamanager newdigitaldm kostroma -777 jpk ldap-test megadigitaldm @@ -8889,7 +8823,6 @@ jesse enjoymediafiles limited sgw -12345 worldwide aga getlivecodecs @@ -9048,7 +8981,6 @@ prod.new www.newyork rejestracja enjoycodecs -132 searchthiscodecs ferry findcodecs @@ -9324,7 +9256,6 @@ edo cobbler newdemo morningstar -43 sava ulysse ns73 @@ -9340,7 +9271,6 @@ his dns22 nida moms -120 nu ming dns21 @@ -9422,7 +9352,6 @@ downloader supply mj secure5 -65 pythagoras jr soulmate @@ -9471,7 +9400,6 @@ ricardo complaints lark www.manual -87 cc2 exchange01 avg @@ -9479,9 +9407,7 @@ osprey backup01 daa serg -89 bor -91 www.fotografia diesel lynch @@ -9492,7 +9418,6 @@ rafael webdev1 tunisie xvideos -71 fuck lens dominus @@ -9502,16 +9427,13 @@ iw mywebsite ukraina pyatigorsk -58 remoto ssl-vpn -56 screenshot worldmusic test18 domaincontrol test16 -55 www.16 aras giovanni @@ -9665,7 +9587,6 @@ porthos z1 paginasamarillas h14 -204 handmade charts h12 @@ -9692,7 +9613,6 @@ ooo zhaosheng nagi baki -CHARGER seer www.arm stan @@ -9766,7 +9686,6 @@ transparencia pdi i20 murakami -WINDOWSTS hagrid juice hosts @@ -9779,7 +9698,6 @@ fotki audrey i23 marx -TERMINALSERVICES petrozavodsk plone www.fl @@ -9791,7 +9709,6 @@ i27 nomad b8 b9 -TSWEB eservice i28 webdisk.movil @@ -9825,7 +9742,6 @@ s228 mail-1 shampoo rss2 -WINDOWS courier asterisk2 zarzadzanie @@ -9870,7 +9786,6 @@ devmail www.tyumen www.10 www.ml -103 scrap mailex www-uat @@ -9916,7 +9831,6 @@ saturne gum gerard crypton -110 rsvp ans realestate2 @@ -10130,7 +10044,6 @@ www.pms edc www.plan serve -125 jean temp1 filer1 @@ -10166,7 +10079,6 @@ vivian lynn gundam goodtimes -123456 sword escape placement @@ -10428,14 +10340,12 @@ nowa conrad webdisk.free indesign -86 sbe curtis myforum infra1 univ rune -81 duplo mail35 wam @@ -10457,7 +10367,6 @@ pony stranger hilda advisor -75 win15 kaizen ns150 @@ -10467,7 +10376,6 @@ zakaria pay2 www.reports cpanel1 -74 patricia i80 Server @@ -10479,7 +10387,6 @@ securelogin www.l insane inti -68 www.barnaul tomtom jedi @@ -10492,7 +10399,6 @@ elan kingkong akash www.irkutsk -62 seeker keyword log1 @@ -10505,7 +10411,6 @@ wan ipv4.demo bca test23 -96 moments amp www.12 @@ -10532,10 +10437,8 @@ amjad smtp.mail www.smolensk canopus -www.9 tsgateway colt -02 cpt www.mama redsun @@ -10744,7 +10647,6 @@ sobek asta prep sogox -8591 alcatraz waffle idiots @@ -10774,7 +10676,6 @@ cme gcm www.firmy workstation -5278 gadgets mail.5278 tapety @@ -10790,7 +10691,6 @@ spectro lister os2 hcp -228 gos s46 amar @@ -10929,7 +10829,6 @@ groove srv23 pearson www.ebook -109 rtc handbook vitrin @@ -10957,7 +10856,6 @@ ebusiness www.vitrin concursos merry -129 cso nsp www.profile @@ -11081,7 +10979,6 @@ termin mota kamel newtech -128 tttt red5 inews @@ -11267,7 +11164,6 @@ nate blade9 lifeline paf -105 saman b18 b17 @@ -11654,7 +11550,6 @@ mkc derecho anil games2 -119 teamo hts mail.newsletter @@ -11866,7 +11761,6 @@ junk cupcake pixie test.shop -212 abdo b26 automail @@ -11874,7 +11768,6 @@ ewa hunters b20 imagini -121 palermo frink b23 @@ -12014,7 +11907,6 @@ i34 hood shop3 www.dr -SIP chester hora i96 @@ -12028,12 +11920,10 @@ canopy dop host20 i98 -static-mal-g-in-g01-s sisko eol wahlen i99 -126 issa pig auth3 @@ -12211,7 +12101,6 @@ faperta ts.fef lebanon grapher -000 vestnik lip myrtle @@ -12229,7 +12118,6 @@ www.o egcdn www.author discuz -106 www.hobby statystyki contrib @@ -12247,7 +12135,6 @@ vz1 gibbs doll via -11091521400593 observatorio spice sokol @@ -12308,7 +12195,6 @@ eucalyptus bmc fps vivo -230 www.ops abba ringtones @@ -12387,7 +12273,6 @@ qwe ip3 www.ava rev -234 pinger resort bdog @@ -12436,7 +12321,6 @@ marek chilli testuser miko -080 lys mobile-test kaito @@ -12464,7 +12348,6 @@ autoconfig.my s39 ftp.shop foxy -233 www.moscow lv121101224239 emilia @@ -12485,7 +12368,6 @@ madagascar sportal hank placeholder -170 www.k ing amt @@ -12805,7 +12687,6 @@ Sooreh fraise sgp nstri -AHWP freeforall servicenet vicky @@ -12820,11 +12701,9 @@ r0 dingorio peppermint mon3 -GIO www.threads itcenter hermes1 -YCG www.mir turism star3 @@ -12865,7 +12744,6 @@ dingdong www.25 www.logo web151 -93 s200 postgre ftp14 @@ -12894,7 +12772,6 @@ joinus intermapper indi-web130 nk -97 contract walk coke @@ -12912,7 +12789,6 @@ dns-2 blacky internetmarketing ecomm1 -59 oneman platypus akita @@ -12923,7 +12799,6 @@ suspended qms amigos dharma -95 tachibana beautiful barton @@ -12944,9 +12819,7 @@ temp01 cweb i95 www.president -72 charmed -36 blog3 alina www.clasificados @@ -13049,8 +12922,6 @@ silent supersonic judy cakes -73 -92 mh2 hinata casas @@ -13180,11 +13051,9 @@ xmlrpc www.dictionary www.campaign spr -38 joomla25 gt2 fcc -VPN ns124 ns118 others @@ -13289,7 +13158,6 @@ h21 scd kir www.malaysia -205 adadmin mae freebooks @@ -13317,7 +13185,6 @@ slpda frm mail.666av aic -1111 mail.080 pizzahut jpadult @@ -13335,7 +13202,6 @@ volterra www.s4 virt sgt -235 antigo arsenic gallium @@ -13888,7 +13754,6 @@ ftp02 radikal lori raymond -211 lizard forum-test kari @@ -14063,7 +13928,6 @@ oldadmin site3 shaka hecate -192 hptest mystyle www.cod @@ -14271,7 +14135,6 @@ prove hangout darkman refresh -209 satan angie annex @@ -14538,7 +14401,6 @@ join2 memoria sigam arkansas -117 advocate www.washington hassan @@ -14556,7 +14418,6 @@ beam kawaji optics midgard -130 bayside.cit diamant ceramics @@ -14623,7 +14484,6 @@ iina www.tibia backlink thegallery -007 st6 nlb iview @@ -14714,7 +14574,6 @@ darkknight answer mail.pics ver2 -137 sysadmin akasaka groupon @@ -14780,8 +14639,6 @@ www.14 youssef cuckoo xink -169 -237 ohyes timemachine resimler @@ -14793,16 +14650,13 @@ momen autoconfig.design fsc guideline -131 reef -134 h2media funnyman b.i83 afshin choose www.ffm -162 eforce storm2 openvz @@ -15049,4 +14903,4 @@ windows1 fap baikal driss -juridico +juridico \ No newline at end of file From 1b46cdcabbab6fd66ab7ce5dde94b78db37b3917 Mon Sep 17 00:00:00 2001 From: vrenzolaverace Date: Sat, 15 Oct 2022 16:33:18 +0200 Subject: [PATCH 12/25] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 17210dc..24eb2cd 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,8 @@ usage: scilla subcommand { options } [-db -vt Use VirusTotal as subdomains source] [-ua Set the User Agent] [-rua Generate a random user agent for each request] + [-dns Set DNS IP to resolve the subdomains] + [-alive Check also if the subdomains are alive] -target REQUIRED - dir [-w wordlist] [-oj JSON output file] @@ -152,6 +154,8 @@ usage: scilla subcommand { options } [-db -vt Use VirusTotal as subdomains source] [-ua Set the User Agent] [-rua Generate a random user agent for each request] + [-dns Set DNS IP to resolve the subdomains] + [-alive Check also if the subdomains are alive] -target REQUIRED - help - examples @@ -185,6 +189,8 @@ Examples 💡 - `scilla subdomain -db -vt -target target.domain` - `scilla subdomain -ua "CustomUA" -target target.domain` - `scilla subdomain -rua -target target.domain` + - `scilla subdomain -dns 8.8.8.8 -target target.domain` + - `scilla subdomain -alive -target target.domain` - Directories enumeration: @@ -239,6 +245,8 @@ Examples 💡 - No follow redirects `scilla report -nr -target target.domain` - Use VirusTotal as subdomains source `scilla report -db -vt -target target.domain` - Set the User Agent `scilla report -ua "CustomUA" -target target.domain` + - Set DNS IP to resolve the subdomains `scilla report -dns 8.8.8.8 -target target.domain` + - Check also if the subdomains are alive `scilla report -alive -target target.domain` - Generate a random user agent for each request `scilla report -rua -target target.domain` Changelog 📌 From bb66b3edd86636a71b57925ab3fb70f8b856d9bb Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:34:44 +0200 Subject: [PATCH 13/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24eb2cd..9112cb1 100644 --- a/README.md +++ b/README.md @@ -245,9 +245,9 @@ Examples 💡 - No follow redirects `scilla report -nr -target target.domain` - Use VirusTotal as subdomains source `scilla report -db -vt -target target.domain` - Set the User Agent `scilla report -ua "CustomUA" -target target.domain` + - Generate a random user agent for each request `scilla report -rua -target target.domain` - Set DNS IP to resolve the subdomains `scilla report -dns 8.8.8.8 -target target.domain` - Check also if the subdomains are alive `scilla report -alive -target target.domain` - - Generate a random user agent for each request `scilla report -rua -target target.domain` Changelog 📌 ------- From c4d283fad985d1045883a72a7a27b9208b627452 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 16:39:12 +0200 Subject: [PATCH 14/25] Update help and examples --- README.md | 4 ++-- pkg/output/examples.go | 4 ++++ pkg/output/help.go | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9112cb1..9ba4b2f 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ usage: scilla subcommand { options } [-nr No follow redirects] [-ua Set the User Agent] [-rua Generate a random user agent for each request] - -target REQUIRED + -target REQUIRED - report [-p or ports divided by comma] [-ws subdomains wordlist] [-wd directories wordlist] @@ -156,7 +156,7 @@ usage: scilla subcommand { options } [-rua Generate a random user agent for each request] [-dns Set DNS IP to resolve the subdomains] [-alive Check also if the subdomains are alive] - -target REQUIRED + -target REQUIRED - help - examples ``` diff --git a/pkg/output/examples.go b/pkg/output/examples.go index 72b6377..3653dfa 100644 --- a/pkg/output/examples.go +++ b/pkg/output/examples.go @@ -52,6 +52,8 @@ func Examples() { fmt.Println(" - scilla subdomain -db -vt -target target.domain") fmt.Println(" - scilla subdomain -ua \"CustomUA\" -target target.domain") fmt.Println(" - scilla subdomain -rua -target target.domain") + fmt.Println(" - scilla subdomain -dns 8.8.8.8 -target target.domain") + fmt.Println(" - scilla subdomain -alive -target target.domain") fmt.Println() fmt.Println(" - scilla port -p -450 -target target.domain") fmt.Println(" - scilla port -p 90- -target target.domain") @@ -98,5 +100,7 @@ func Examples() { fmt.Println(" - scilla report -tp 2 -target target.domain") fmt.Println(" - scilla report -ua \"CustomUA\" -target target.domain") fmt.Println(" - scilla report -rua -target target.domain") + fmt.Println(" - scilla report -dns 8.8.8.8 -target target.domain") + fmt.Println(" - scilla report -alive -target target.domain") fmt.Println("") } diff --git a/pkg/output/help.go b/pkg/output/help.go index 2684fa0..bff3684 100644 --- a/pkg/output/help.go +++ b/pkg/output/help.go @@ -61,6 +61,8 @@ func Help() { fmt.Println(" [-db -vt Use VirusTotal as subdomains source]") fmt.Println(" [-ua Set the User Agent]") fmt.Println(" [-rua Generate a random user agent for each request]") + fmt.Println(" [-dns Set DNS IP to resolve the subdomains]") + fmt.Println(" [-alive Check also if the subdomains are alive]") fmt.Println(" -target REQUIRED") fmt.Println(" - dir [-w wordlist]") fmt.Println(" [-oj JSON output file]") @@ -90,6 +92,8 @@ func Help() { fmt.Println(" [-tp Port scan timeout]") fmt.Println(" [-ua Set the User Agent]") fmt.Println(" [-rua Generate a random user agent for each request]") + fmt.Println(" [-dns Set DNS IP to resolve the subdomains]") + fmt.Println(" [-alive Check also if the subdomains are alive]") fmt.Println(" -target REQUIRED") fmt.Println(" - help") fmt.Println(" - examples") From e9c7c03dd326fba60869703af008fb1db21d6053 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 19:11:38 +0200 Subject: [PATCH 15/25] Add Tests --- go.mod | 3 + internal/dns/dns_test.go | 49 +++++++++ internal/http/http_test.go | 39 +++++++ internal/ignore/ignore.go | 26 +++-- internal/ignore/ignore_test.go | 183 +++++++++++++++++++++++++++++++++ internal/ip/ip_test.go | 41 ++++++++ internal/math/math_test.go | 41 ++++++++ internal/slice/slice_test.go | 127 +++++++++++++++++++++++ pkg/input/check.go | 40 +++++-- 9 files changed, 528 insertions(+), 21 deletions(-) create mode 100644 internal/dns/dns_test.go create mode 100644 internal/http/http_test.go create mode 100644 internal/ignore/ignore_test.go create mode 100644 internal/ip/ip_test.go create mode 100644 internal/math/math_test.go create mode 100644 internal/slice/slice_test.go diff --git a/go.mod b/go.mod index 1a3a7b3..7a47b7b 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/bobesa/go-domain-util v0.0.0-20190911083921-4033b5f7dd89 github.com/fatih/color v1.13.0 github.com/gocolly/colly v1.2.0 + github.com/stretchr/testify v1.3.0 gopkg.in/yaml.v3 v3.0.0 ) @@ -15,12 +16,14 @@ require ( github.com/antchfx/htmlquery v1.2.5 // indirect github.com/antchfx/xmlquery v1.3.11 // indirect github.com/antchfx/xpath v1.2.1 // indirect + github.com/davecgh/go-spew v1.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/kennygrant/sanitize v1.2.4 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/temoto/robotstxt v1.1.2 // indirect golang.org/x/net v0.0.0-20220524220425-1d687d428aca // indirect diff --git a/internal/dns/dns_test.go b/internal/dns/dns_test.go new file mode 100644 index 0000000..f58a399 --- /dev/null +++ b/internal/dns/dns_test.go @@ -0,0 +1,49 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "testing" + + dnsUtils "github.com/edoardottt/scilla/internal/dns" + "github.com/stretchr/testify/require" +) + +func TestSimpleDNSLookup(t *testing.T) { + require.Equal(t, false, dnsUtils.SimpleDNSLookup("whtbiwvuwivtytyiethiubwixfniqf.wefbywf.com")) +} + +func TestNewCustomResolver(t *testing.T) { + r := dnsUtils.NewCustomResolver("8.8.8.8") + require.NotNil(t, dnsUtils.CustomDNSLookup(r, "whtbiwvuwivtytyiethiubwixfniqf.wefbywf.com")) +} + +func TestCustomDNSLookup(t *testing.T) { + r := dnsUtils.NewCustomResolver("8.8.8.8") + require.Equal(t, false, dnsUtils.CustomDNSLookup(r, "whtbiwvuwivtytyiethiubwixfniqf.wefbywf.com")) +} diff --git a/internal/http/http_test.go b/internal/http/http_test.go new file mode 100644 index 0000000..5d8e705 --- /dev/null +++ b/internal/http/http_test.go @@ -0,0 +1,39 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "testing" + + httpUtils "github.com/edoardottt/scilla/internal/http" + "github.com/stretchr/testify/assert" +) + +func TestGenerateRandomUserAgent(t *testing.T) { + assert.NotNil(t, httpUtils.GenerateRandomUserAgent()) +} diff --git a/internal/ignore/ignore.go b/internal/ignore/ignore.go index 4b3210a..cbaf3a4 100644 --- a/internal/ignore/ignore.go +++ b/internal/ignore/ignore.go @@ -28,6 +28,7 @@ along with this program. If not, see http://www.gnu.org/licenses/. package utils import ( + "errors" "fmt" "os" "strconv" @@ -43,7 +44,7 @@ const ( // CheckIgnore checks the inputted status code(s) to be ignored. // It can be a list e.g. 301,302,400,404,500 // It can be a 'class' of codes e.g. 3**. -func CheckIgnore(input string) []string { +func CheckIgnore(input string) ([]string, error) { result := []string{} temp := strings.Split(input, ",") temp = sliceUtils.RemoveDuplicateValues(temp) @@ -51,8 +52,7 @@ func CheckIgnore(input string) []string { for _, elem := range temp { elem := strings.TrimSpace(elem) if len(elem) != statusCodeLength { - fmt.Println("The status code you entered is invalid (It should consist of three digits).") - os.Exit(1) + return nil, errors.New("The status code you entered is invalid (It should consist of three digits).") } if ignoreInt, err := strconv.Atoi(elem); err == nil { @@ -60,29 +60,27 @@ func CheckIgnore(input string) []string { if 100 <= ignoreInt && ignoreInt <= 599 { result = append(result, elem) } else { - fmt.Println("The status code you entered is invalid (100 <= code <= 599).") - os.Exit(1) + return nil, errors.New("The status code you entered is invalid (100 <= code <= 599).") } } else if strings.Contains(elem, "*") { // if it is a valid status code without * (e.g. 4**) - if IgnoreClassOk(elem) { + if ignoreClassOk(elem) { result = append(result, elem) } else { - fmt.Println("The status code you entered is invalid. You can enter * only as 1**,2**,3**,4**,5**.") - os.Exit(1) + return nil, errors.New("The status code you entered is invalid. You can enter * only as 1**,2**,3**,4**,5**.") } } } result = sliceUtils.RemoveDuplicateValues(result) - result = DeleteUnusefulIgnoreresponses(result) + result = deleteUnusefulIgnoreresponses(result) - return result + return result, nil } -// DeleteUnusefulIgnoreresponses removes from to-be-ignored arrays +// deleteUnusefulIgnoreresponses removes from to-be-ignored arrays // the responses already included with * as classes. -func DeleteUnusefulIgnoreresponses(input []string) []string { +func deleteUnusefulIgnoreresponses(input []string) []string { var result []string toberemoved := []string{} @@ -107,9 +105,9 @@ func DeleteUnusefulIgnoreresponses(input []string) []string { return result } -// IgnoreClassOk states if the class of ignored status codes +// ignoreClassOk states if the class of ignored status codes // is correct or not (4**,2**...) -func IgnoreClassOk(input string) bool { +func ignoreClassOk(input string) bool { if strings.Contains(input, "*") { if _, err := strconv.Atoi(string(input[0])); err == nil { i, err := strconv.Atoi(string(input[0])) diff --git a/internal/ignore/ignore_test.go b/internal/ignore/ignore_test.go new file mode 100644 index 0000000..19727c9 --- /dev/null +++ b/internal/ignore/ignore_test.go @@ -0,0 +1,183 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "errors" + "testing" + + ignoreUtils "github.com/edoardottt/scilla/internal/ignore" + "github.com/stretchr/testify/require" +) + +func TestCheckIgnore(t *testing.T) { + tests := []struct { + name string + input string + want []string + erro error + }{ + { + name: "single value", + input: "301", + want: []string{"301"}, + erro: nil, + }, + { + name: "empty value", + input: "", + want: nil, + erro: errors.New("The status code you entered is invalid (It should consist of three digits)."), + }, + { + name: "withous duplicates", + input: "301,302,400", + want: []string{"301", "302", "400"}, + erro: nil, + }, + { + name: "has duplicates", + input: "301,301,302,301", + want: []string{"301", "302"}, + erro: nil, + }, + { + name: "class", + input: "3**", + want: []string{"3**"}, + erro: nil, + }, + { + name: "multiple classes", + input: "3**,4**", + want: []string{"3**", "4**"}, + erro: nil, + }, + { + name: "mixed", + input: "301,4**", + want: []string{"301", "4**"}, + erro: nil, + }, + { + name: "mixed with duplicates", + input: "301,4**,4**", + want: []string{"301", "4**"}, + erro: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ignoreUtils.CheckIgnore(tt.input) + require.Equal(t, tt.erro, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestIgnoreResponse(t *testing.T) { + tests := []struct { + name string + response int + ignore []string + want bool + }{ + { + name: "single value", + response: 200, + ignore: []string{"301"}, + want: false, + }, + { + name: "empty value", + response: 0, + ignore: []string{"301"}, + want: false, + }, + { + name: "empty ignore", + response: 200, + ignore: []string{}, + want: false, + }, + { + name: "invalid response", + response: 44545345, + ignore: []string{}, + want: false, + }, + { + name: "withous duplicates", + response: 301, + ignore: []string{"301", "302", "400"}, + want: true, + }, + { + name: "has duplicates", + response: 301, + ignore: []string{"301", "301", "302"}, + want: true, + }, + { + name: "class", + response: 301, + ignore: []string{"3**"}, + want: true, + }, + { + name: "multiple classes", + response: 401, + ignore: []string{"3**", "4**"}, + want: true, + }, + { + name: "mixed", + response: 401, + ignore: []string{"301", "4**"}, + want: true, + }, + { + name: "mixed with duplicates", + response: 500, + ignore: []string{"301", "4**", "5**", "5**"}, + want: true, + }, + { + name: "don't ignore", + response: 500, + ignore: []string{"301", "4**", "302", "429"}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ignoreUtils.IgnoreResponse(tt.response, tt.ignore) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/ip/ip_test.go b/internal/ip/ip_test.go new file mode 100644 index 0000000..9dd529e --- /dev/null +++ b/internal/ip/ip_test.go @@ -0,0 +1,41 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "testing" + + ipUtils "github.com/edoardottt/scilla/internal/ip" + "github.com/stretchr/testify/assert" +) + +func TestIPToHostname(t *testing.T) { + hostname := ipUtils.IPToHostname("8.8.8.8") + assert.NotNil(t, hostname) + assert.Equal(t, hostname, "dns.google") +} diff --git a/internal/math/math_test.go b/internal/math/math_test.go new file mode 100644 index 0000000..339bf2c --- /dev/null +++ b/internal/math/math_test.go @@ -0,0 +1,41 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "testing" + + mathUtils "github.com/edoardottt/scilla/internal/math" + "github.com/stretchr/testify/assert" +) + +func TestPercentage(t *testing.T) { + result := mathUtils.Percentage(50, 1000) + assert.NotNil(t, result) + assert.Equal(t, result, float64(5)) +} diff --git a/internal/slice/slice_test.go b/internal/slice/slice_test.go new file mode 100644 index 0000000..980e846 --- /dev/null +++ b/internal/slice/slice_test.go @@ -0,0 +1,127 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "testing" + + sliceUtils "github.com/edoardottt/scilla/internal/slice" + "github.com/stretchr/testify/require" +) + +func TestRemoveDuplicateValues(t *testing.T) { + tests := []struct { + name string + input []string + want []string + }{ + { + name: "single value", + input: []string{"301"}, + want: []string{"301"}, + }, + { + name: "empty value", + input: []string{""}, + want: []string{""}, + }, + { + name: "empty slice", + input: []string{}, + want: []string{}, + }, + { + name: "no duplicates", + input: []string{"1", "2", "3", "4"}, + want: []string{"1", "2", "3", "4"}, + }, + { + name: "with duplicates", + input: []string{"1", "2", "3", "4", "4", "3", "2", "1"}, + want: []string{"1", "2", "3", "4"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := sliceUtils.RemoveDuplicateValues(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestDifference(t *testing.T) { + tests := []struct { + name string + inputA []string + inputB []string + want []string + }{ + { + name: "single value", + inputA: []string{"301"}, + inputB: []string{}, + want: []string{"301"}, + }, + { + name: "empty value", + inputA: []string{""}, + inputB: []string{""}, + want: []string{}, + }, + { + name: "empty slice", + inputA: []string{}, + inputB: []string{}, + want: []string{}, + }, + { + name: "no duplicates", + inputA: []string{"1", "2", "3", "4"}, + inputB: []string{"30"}, + want: []string{"1", "2", "3", "4"}, + }, + { + name: "with duplicates", + inputA: []string{"1", "2", "3", "4", "4", "3", "2", "1"}, + inputB: []string{"301"}, + want: []string{"1", "2", "3", "4", "4", "3", "2", "1"}, + }, + { + name: "difference", + inputA: []string{"1", "2", "3", "4"}, + inputB: []string{"1", "2"}, + want: []string{"3", "4"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := sliceUtils.Difference(tt.inputA, tt.inputB) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/input/check.go b/pkg/input/check.go index 071cb97..3560036 100644 --- a/pkg/input/check.go +++ b/pkg/input/check.go @@ -123,16 +123,28 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str } } - var reportIgnoreDir, reportIgnoreSub []string + var ( + reportIgnoreDir []string + reportIgnoreSub []string + err error + ) if *reportIgnoreDirPtr != "" { toBeIgnored := *reportIgnoreDirPtr - reportIgnoreDir = ignoreUtils.CheckIgnore(toBeIgnored) + reportIgnoreDir, err = ignoreUtils.CheckIgnore(toBeIgnored) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } } if *reportIgnoreSubPtr != "" { toBeIgnored := *reportIgnoreSubPtr - reportIgnoreSub = ignoreUtils.CheckIgnore(toBeIgnored) + reportIgnoreSub, err = ignoreUtils.CheckIgnore(toBeIgnored) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } } if *reportTimeoutPort < 1 || *reportTimeoutPort > 100 { @@ -255,11 +267,18 @@ func SubdomainSubcommandCheckFlags(subdomainCommand flag.FlagSet, subdomainTarge os.Exit(1) } - var subdomainIgnore []string + var ( + subdomainIgnore []string + err error + ) if *subdomainIgnorePtr != "" { toBeIgnored := *subdomainIgnorePtr - subdomainIgnore = ignoreUtils.CheckIgnore(toBeIgnored) + subdomainIgnore, err = ignoreUtils.CheckIgnore(toBeIgnored) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } } if *subdomainUserAgentPtr != DefaultUserAgent && *subdomainRandomUserAgentPtr { @@ -408,11 +427,18 @@ func DirSubcommandCheckFlags(dirCommand flag.FlagSet, dirTargetPtr *string, } } - var dirIgnore []string + var ( + dirIgnore []string + err error + ) if *dirIgnorePtr != "" { toBeIgnored := *dirIgnorePtr - dirIgnore = ignoreUtils.CheckIgnore(toBeIgnored) + dirIgnore, err = ignoreUtils.CheckIgnore(toBeIgnored) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } } if *dirUserAgentPtr != DefaultUserAgent && *dirRandomUserAgentPtr { From 40d9edbf1d10e41f46419f22f902323ecd1d0e09 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 19:19:19 +0200 Subject: [PATCH 16/25] Lint --- internal/ignore/ignore.go | 12 +++++++++--- internal/ignore/ignore_test.go | 3 +-- pkg/input/check.go | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/internal/ignore/ignore.go b/internal/ignore/ignore.go index cbaf3a4..6a0726c 100644 --- a/internal/ignore/ignore.go +++ b/internal/ignore/ignore.go @@ -41,6 +41,12 @@ const ( statusCodeLength = 3 ) +var ( + ErrWrongStatusCodeLength = errors.New("invalid status code: It should consist of three digits") + ErrInvalidStatusCode = errors.New("invalid status code: 100 <= code <= 599") + ErrInvalidStatusCodeClass = errors.New("invalid status code: You can use * only in 1**,2**,3**,4**,5**") +) + // CheckIgnore checks the inputted status code(s) to be ignored. // It can be a list e.g. 301,302,400,404,500 // It can be a 'class' of codes e.g. 3**. @@ -52,7 +58,7 @@ func CheckIgnore(input string) ([]string, error) { for _, elem := range temp { elem := strings.TrimSpace(elem) if len(elem) != statusCodeLength { - return nil, errors.New("The status code you entered is invalid (It should consist of three digits).") + return nil, fmt.Errorf("%w", ErrWrongStatusCodeLength) } if ignoreInt, err := strconv.Atoi(elem); err == nil { @@ -60,14 +66,14 @@ func CheckIgnore(input string) ([]string, error) { if 100 <= ignoreInt && ignoreInt <= 599 { result = append(result, elem) } else { - return nil, errors.New("The status code you entered is invalid (100 <= code <= 599).") + return nil, fmt.Errorf("%w", ErrInvalidStatusCode) } } else if strings.Contains(elem, "*") { // if it is a valid status code without * (e.g. 4**) if ignoreClassOk(elem) { result = append(result, elem) } else { - return nil, errors.New("The status code you entered is invalid. You can enter * only as 1**,2**,3**,4**,5**.") + return nil, fmt.Errorf("%w", ErrInvalidStatusCodeClass) } } } diff --git a/internal/ignore/ignore_test.go b/internal/ignore/ignore_test.go index 19727c9..d3356b4 100644 --- a/internal/ignore/ignore_test.go +++ b/internal/ignore/ignore_test.go @@ -28,7 +28,6 @@ along with this program. If not, see http://www.gnu.org/licenses/. package utils_test import ( - "errors" "testing" ignoreUtils "github.com/edoardottt/scilla/internal/ignore" @@ -52,7 +51,7 @@ func TestCheckIgnore(t *testing.T) { name: "empty value", input: "", want: nil, - erro: errors.New("The status code you entered is invalid (It should consist of three digits)."), + erro: ignoreUtils.ErrWrongStatusCodeLength, }, { name: "withous duplicates", diff --git a/pkg/input/check.go b/pkg/input/check.go index 3560036..8e1e48d 100644 --- a/pkg/input/check.go +++ b/pkg/input/check.go @@ -131,6 +131,7 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str if *reportIgnoreDirPtr != "" { toBeIgnored := *reportIgnoreDirPtr + reportIgnoreDir, err = ignoreUtils.CheckIgnore(toBeIgnored) if err != nil { fmt.Println(err.Error()) @@ -140,6 +141,7 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str if *reportIgnoreSubPtr != "" { toBeIgnored := *reportIgnoreSubPtr + reportIgnoreSub, err = ignoreUtils.CheckIgnore(toBeIgnored) if err != nil { fmt.Println(err.Error()) @@ -274,6 +276,7 @@ func SubdomainSubcommandCheckFlags(subdomainCommand flag.FlagSet, subdomainTarge if *subdomainIgnorePtr != "" { toBeIgnored := *subdomainIgnorePtr + subdomainIgnore, err = ignoreUtils.CheckIgnore(toBeIgnored) if err != nil { fmt.Println(err.Error()) @@ -434,6 +437,7 @@ func DirSubcommandCheckFlags(dirCommand flag.FlagSet, dirTargetPtr *string, if *dirIgnorePtr != "" { toBeIgnored := *dirIgnorePtr + dirIgnore, err = ignoreUtils.CheckIgnore(toBeIgnored) if err != nil { fmt.Println(err.Error()) From 2febbf5ef65594a75ce204fec7b710c0a7d582bb Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 19:21:49 +0200 Subject: [PATCH 17/25] update tests --- internal/ignore/ignore_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/ignore/ignore_test.go b/internal/ignore/ignore_test.go index d3356b4..8dd2a43 100644 --- a/internal/ignore/ignore_test.go +++ b/internal/ignore/ignore_test.go @@ -28,6 +28,7 @@ along with this program. If not, see http://www.gnu.org/licenses/. package utils_test import ( + "fmt" "testing" ignoreUtils "github.com/edoardottt/scilla/internal/ignore" @@ -51,7 +52,7 @@ func TestCheckIgnore(t *testing.T) { name: "empty value", input: "", want: nil, - erro: ignoreUtils.ErrWrongStatusCodeLength, + erro: fmt.Errorf("%w", ignoreUtils.ErrWrongStatusCodeLength), }, { name: "withous duplicates", From cdffc4985fb519c37a2070b78610e5af5987bae7 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 21:28:07 +0200 Subject: [PATCH 18/25] update tests --- internal/transport/transport.go | 39 ++++--- internal/transport/transport_test.go | 151 +++++++++++++++++++++++++++ pkg/input/check.go | 59 ++++++++--- 3 files changed, 215 insertions(+), 34 deletions(-) create mode 100644 internal/transport/transport_test.go diff --git a/internal/transport/transport.go b/internal/transport/transport.go index 5caf1c5..8bdb34e 100644 --- a/internal/transport/transport.go +++ b/internal/transport/transport.go @@ -28,20 +28,25 @@ along with this program. If not, see http://www.gnu.org/licenses/. package utils import ( + "errors" "fmt" - "os" "strconv" "strings" sliceUtils "github.com/edoardottt/scilla/internal/slice" ) +var ( + ErrInvalidArray = errors.New("the inputted ports array is not valid") + ErrInvalidRange = errors.New("the inputted ports range is not valid") +) + // CheckPortsArray checks the basic rules to // be valid and then returns the ports array to scan. // - remove duplicates. // - check if they can be converted to integers. // - check if they are in the port array (1 - 65535). -func CheckPortsArray(input string) []int { +func CheckPortsArray(input string) ([]int, error) { delimiter := byte(',') sliceOfPorts := strings.Split(input, string(delimiter)) sliceOfPorts = sliceUtils.RemoveDuplicateValues(sliceOfPorts) @@ -50,8 +55,7 @@ func CheckPortsArray(input string) []int { for _, elem := range sliceOfPorts { try, err := strconv.Atoi(elem) if err != nil { - fmt.Println("The inputted ports array is not valid.") - os.Exit(1) + return nil, fmt.Errorf("%w", ErrInvalidArray) } if try > 0 && try < 65536 { @@ -59,12 +63,12 @@ func CheckPortsArray(input string) []int { } } - return result + return result, nil } // CheckPortsRange checks the basic rules to // be valid and then returns the starting port and the ending port. -func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int) { +func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int, error) { // If there's ports range, define it as inputs for the struct delimiter := byte('-') // If there is only one number @@ -75,8 +79,7 @@ func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int) { { maybeEnd, err := strconv.Atoi(portsRange[1:]) if err != nil { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } if maybeEnd >= 1 && maybeEnd <= endPort { endPort = maybeEnd @@ -90,8 +93,7 @@ func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int) { // If ending port isn't specified maybeStart, err := strconv.Atoi(portsRange[:len(portsRange)-1]) if err != nil { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } if maybeStart > 0 && maybeStart < endPort { startPort = maybeStart @@ -105,8 +107,7 @@ func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int) { // If a single port is specified maybePort, err := strconv.Atoi(portsRange) if err != nil { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } if maybePort > 0 && maybePort < endPort { startPort = maybePort @@ -121,27 +122,23 @@ func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int) { // If a range is specified sliceOfPorts := strings.Split(portsRange, string(delimiter)) if len(sliceOfPorts) != 2 { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } maybeStart, err := strconv.Atoi(sliceOfPorts[0]) if err != nil { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } maybeEnd, err := strconv.Atoi(sliceOfPorts[1]) if err != nil { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } if maybeStart > maybeEnd || maybeStart < 1 || maybeEnd > endPort { - fmt.Println("The inputted port range is not valid.") - os.Exit(1) + return 0, 0, fmt.Errorf("%w", ErrInvalidRange) } startPort = maybeStart endPort = maybeEnd } } - return startPort, endPort + return startPort, endPort, nil } diff --git a/internal/transport/transport_test.go b/internal/transport/transport_test.go new file mode 100644 index 0000000..d509ee7 --- /dev/null +++ b/internal/transport/transport_test.go @@ -0,0 +1,151 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "fmt" + "testing" + + transportUtils "github.com/edoardottt/scilla/internal/transport" + "github.com/stretchr/testify/require" +) + +func TestCheckPortsArray(t *testing.T) { + tests := []struct { + name string + input string + want []int + erro error + }{ + { + name: "single value", + input: "1", + want: []int{1}, + erro: nil, + }, + { + name: "invalid value1", + input: "1,123456", + want: []int{1}, + erro: nil, + }, + { + name: "invalid value2", + input: ",,", + want: nil, + erro: fmt.Errorf("%w", transportUtils.ErrInvalidArray), + }, + { + name: "good array", + input: "1,10", + want: []int{1, 10}, + erro: nil, + }, + { + name: "with duplicates", + input: "1,1,10", + want: []int{1, 10}, + erro: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := transportUtils.CheckPortsArray(tt.input) + require.Equal(t, tt.erro, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestCheckPortsRange(t *testing.T) { + tests := []struct { + name string + input string + start int + end int + erro error + }{ + { + name: "single value", + input: "1", + start: 1, + end: 1, + erro: nil, + }, + { + name: "invalid value", + input: "1-123456", + start: 0, + end: 0, + erro: fmt.Errorf("%w", transportUtils.ErrInvalidRange), + }, + { + name: "good array", + input: "1-10", + start: 1, + end: 10, + erro: nil, + }, + { + name: "end array", + input: "-10", + start: 1, + end: 10, + erro: nil, + }, + { + name: "start array", + input: "1-", + start: 1, + end: 65535, + erro: nil, + }, + { + name: "bad array1", + input: "1--", + start: 0, + end: 0, + erro: fmt.Errorf("%w", transportUtils.ErrInvalidRange), + }, + { + name: "bad array2", + input: "-1-", + start: 0, + end: 0, + erro: fmt.Errorf("%w", transportUtils.ErrInvalidRange), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + start, end, err := transportUtils.CheckPortsRange(tt.input, 1, 65535) + require.Equal(t, tt.erro, err) + require.Equal(t, tt.start, start) + require.Equal(t, tt.end, end) + }) + } +} diff --git a/pkg/input/check.go b/pkg/input/check.go index 8e1e48d..731c289 100644 --- a/pkg/input/check.go +++ b/pkg/input/check.go @@ -92,9 +92,11 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str os.Exit(1) } - var portsArray []int - - var portArrayBool bool + var ( + portsArray []int + portArrayBool bool + err error + ) if *reportPortsPtr != "" { if strings.Contains(*reportPortsPtr, "-") && strings.Contains(*reportPortsPtr, ",") { @@ -106,18 +108,33 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str case strings.Contains(*reportPortsPtr, "-"): { portsRange := *reportPortsPtr - startPort, endPort = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + portArrayBool = false } case strings.Contains(*reportPortsPtr, ","): { - portsArray = transportUtils.CheckPortsArray(*reportPortsPtr) + portsArray, err = transportUtils.CheckPortsArray(*reportPortsPtr) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + portArrayBool = true } default: { portsRange := *reportPortsPtr - startPort, endPort = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + portArrayBool = false } } @@ -126,7 +143,6 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str var ( reportIgnoreDir []string reportIgnoreSub []string - err error ) if *reportIgnoreDirPtr != "" { @@ -324,9 +340,11 @@ func PortSubcommandCheckFlags(portCommand flag.FlagSet, portTargetPtr *string, p os.Exit(1) } - var portArrayBool bool - - var portsArray []int + var ( + portArrayBool bool + portsArray []int + err error + ) if *portsPtr != "" { if strings.Contains(*portsPtr, "-") && strings.Contains(*portsPtr, ",") { @@ -338,18 +356,33 @@ func PortSubcommandCheckFlags(portCommand flag.FlagSet, portTargetPtr *string, p case strings.Contains(*portsPtr, "-"): { portsRange := *portsPtr - startPort, endPort = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + portArrayBool = false } case strings.Contains(*portsPtr, ","): { - portsArray = transportUtils.CheckPortsArray(*portsPtr) + portsArray, err = transportUtils.CheckPortsArray(*portsPtr) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + portArrayBool = true } default: { portsRange := *portsPtr - startPort, endPort = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + portArrayBool = false } } From 1be11e0f00fd254732538cc970451dbc3b8483c0 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sat, 15 Oct 2022 21:40:28 +0200 Subject: [PATCH 19/25] update tests --- internal/transport/transport.go | 50 +++++++++++++++++++ pkg/input/check.go | 88 ++------------------------------- 2 files changed, 54 insertions(+), 84 deletions(-) diff --git a/internal/transport/transport.go b/internal/transport/transport.go index 8bdb34e..e108473 100644 --- a/internal/transport/transport.go +++ b/internal/transport/transport.go @@ -30,6 +30,7 @@ package utils import ( "errors" "fmt" + "os" "strconv" "strings" @@ -142,3 +143,52 @@ func CheckPortsRange(portsRange string, startPort int, endPort int) (int, int, e return startPort, endPort, nil } + +func PortsInputHelper(portsPtr *string, startPort, endPort int, portsArray []int, + portArrayBool bool) (int, int, []int, bool) { + var err error + + if *portsPtr != "" { + if strings.Contains(*portsPtr, "-") && strings.Contains(*portsPtr, ",") { + fmt.Println("you can specify a ports range or an array, not both") + os.Exit(1) + } + + switch { + case strings.Contains(*portsPtr, "-"): + { + portsRange := *portsPtr + startPort, endPort, err = CheckPortsRange(portsRange, startPort, endPort) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + portArrayBool = false + } + case strings.Contains(*portsPtr, ","): + { + portsArray, err = CheckPortsArray(*portsPtr) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + portArrayBool = true + } + default: + { + portsRange := *portsPtr + startPort, endPort, err = CheckPortsRange(portsRange, startPort, endPort) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + portArrayBool = false + } + } + } + + return startPort, endPort, portsArray, portArrayBool +} diff --git a/pkg/input/check.go b/pkg/input/check.go index 731c289..37837b7 100644 --- a/pkg/input/check.go +++ b/pkg/input/check.go @@ -31,7 +31,6 @@ import ( "flag" "fmt" "os" - "strings" ignoreUtils "github.com/edoardottt/scilla/internal/ignore" transportUtils "github.com/edoardottt/scilla/internal/transport" @@ -98,47 +97,8 @@ func ReportSubcommandCheckFlags(reportCommand flag.FlagSet, reportTargetPtr *str err error ) - if *reportPortsPtr != "" { - if strings.Contains(*reportPortsPtr, "-") && strings.Contains(*reportPortsPtr, ",") { - fmt.Println("You can specify a ports range or an array, not both.") - os.Exit(1) - } - - switch { - case strings.Contains(*reportPortsPtr, "-"): - { - portsRange := *reportPortsPtr - startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - portArrayBool = false - } - case strings.Contains(*reportPortsPtr, ","): - { - portsArray, err = transportUtils.CheckPortsArray(*reportPortsPtr) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - portArrayBool = true - } - default: - { - portsRange := *reportPortsPtr - startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - portArrayBool = false - } - } - } + startPort, endPort, portsArray, portArrayBool = transportUtils.PortsInputHelper(reportPortsPtr, + startPort, endPort, portsArray, portArrayBool) var ( reportIgnoreDir []string @@ -343,50 +303,10 @@ func PortSubcommandCheckFlags(portCommand flag.FlagSet, portTargetPtr *string, p var ( portArrayBool bool portsArray []int - err error ) - if *portsPtr != "" { - if strings.Contains(*portsPtr, "-") && strings.Contains(*portsPtr, ",") { - fmt.Println("You can specify a ports range or an array, not both.") - os.Exit(1) - } - - switch { - case strings.Contains(*portsPtr, "-"): - { - portsRange := *portsPtr - startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - portArrayBool = false - } - case strings.Contains(*portsPtr, ","): - { - portsArray, err = transportUtils.CheckPortsArray(*portsPtr) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - portArrayBool = true - } - default: - { - portsRange := *portsPtr - startPort, endPort, err = transportUtils.CheckPortsRange(portsRange, startPort, endPort) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - portArrayBool = false - } - } - } + startPort, endPort, portsArray, portArrayBool = transportUtils.PortsInputHelper(portsPtr, + startPort, endPort, portsArray, portArrayBool) // output files all different if *portOutputJSON != "" { From 40744f619fc566ad15a5d0aa5eae6c5427b2af20 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sun, 16 Oct 2022 19:14:00 +0200 Subject: [PATCH 20/25] update tests --- internal/url/url.go | 43 ++-- internal/url/url_test.go | 410 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+), 17 deletions(-) create mode 100644 internal/url/url_test.go diff --git a/internal/url/url.go b/internal/url/url.go index 9a4f255..84fd537 100644 --- a/internal/url/url.go +++ b/internal/url/url.go @@ -37,16 +37,21 @@ import ( // ProtocolExists checks if the protocol is present in the URL // taken as input. func ProtocolExists(target string) bool { - res := strings.Index(target, "://") + u, err := url.Parse(target) + if err != nil { + return false + } - return res >= 0 + return u.Scheme != "" } // CleanProtocol removes the protocol from the url. func CleanProtocol(target string) string { - res := strings.Index(target, "://") - if res >= 0 { - return target[res+3:] + if ProtocolExists(target) { + res := strings.Index(target, "://") + if res >= 0 { + return target[res+3:] + } } return target @@ -62,6 +67,10 @@ func CleanURL(input string) string { return input } + if u.Scheme == "" { + u.Scheme = "http" + } + return u.Scheme + "://" + u.Host + u.Path } @@ -89,10 +98,11 @@ func AppendDir(scheme string, domain string, dir string) (string, string) { // CleanSubdomainsOk takes as input a slice of subdomains and remove // from the input slice all the 'wrong' subdomains. func CleanSubdomainsOk(target string, input []string) []string { - var result []string + result := []string{} for _, elem := range input { - if strings.Contains(elem, "."+target) && elem[len(elem)-len(target):] == target { + if strings.Contains(elem, "."+target) && elem != "."+target && + elem[len(elem)-len(target):] == target { if strings.Contains(elem, "\n") { splits := strings.Split(elem, "\n") elem = splits[1] @@ -106,18 +116,17 @@ func CleanSubdomainsOk(target string, input []string) []string { // RetrieveProtocol remove from the url the protocol scheme. func RetrieveProtocol(target string) string { - res := strings.Index(target, "://") - - if res >= 0 { - return target[:res] + u, err := url.Parse(target) + if err != nil { + return "" } - return target + return u.Scheme } // AbsoluteURL takes as input a path and returns the full // absolute URL with protocol + host + path. -func AbsoluteURL(protocol string, target string, path string) string { +func AbsoluteURL(scheme string, target string, path string) string { // if the path variable starts with a scheme, it means that the // path is itself an absolute path. if ProtocolExists(path) { @@ -125,22 +134,22 @@ func AbsoluteURL(protocol string, target string, path string) string { } if path[0] == '/' { - return protocol + "://" + target + path + return scheme + "://" + target + path } - return protocol + "://" + target + "/" + path + return scheme + "://" + target + "/" + path } // RetrieveHost takes as input a URL and returns // as output the domain (host). func RetrieveHost(input string) string { - url, err := url.Parse(input) + u, err := url.Parse(input) if err != nil { return input } - return url.Host + return u.Host } // GetRootHost returns the root host (domain.tld). diff --git a/internal/url/url_test.go b/internal/url/url_test.go new file mode 100644 index 0000000..067d996 --- /dev/null +++ b/internal/url/url_test.go @@ -0,0 +1,410 @@ +/* + +======================= +Scilla - Information Gathering Tool +======================= + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see http://www.gnu.org/licenses/. + + @Repository: https://github.com/edoardottt/scilla + + @Author: edoardottt, https://www.edoardoottavianelli.it + + @License: https://github.com/edoardottt/scilla/blob/main/LICENSE + +*/ + +package utils_test + +import ( + "testing" + + urlUtils "github.com/edoardottt/scilla/internal/url" + "github.com/stretchr/testify/require" +) + +func TestProtocolExists(t *testing.T) { + tests := []struct { + name string + input string + want bool + }{ + { + name: "single value", + input: "1", + want: false, + }, + { + name: "good value", + input: "http://ciao.com", + want: true, + }, + { + name: "malformed input", + input: "http/http/ciao.com/ciao", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.ProtocolExists(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestCleanProtocol(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "single value", + input: "1", + want: "1", + }, + { + name: "good value1", + input: "http://ciao.com", + want: "ciao.com", + }, + { + name: "good value2", + input: "http://ciao.com/ciao?id=1&ip=1.1.1.1", + want: "ciao.com/ciao?id=1&ip=1.1.1.1", + }, + { + name: "malformed input", + input: "http/http/ciao.com/ciao", + want: "http/http/ciao.com/ciao", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.CleanProtocol(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestCleanURL(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "good value1", + input: "http://ciao.com", + want: "http://ciao.com", + }, + { + name: "good value2", + input: "http://ciao.com/ciao?id=1&ip=1.1.1.1", + want: "http://ciao.com/ciao", + }, + { + name: "malformed input", + input: "http/http/ciao.com/ciao", + want: "http://http/http/ciao.com/ciao", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.CleanURL(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestIsURL(t *testing.T) { + tests := []struct { + name string + input string + want bool + }{ + { + name: "good value1", + input: "http://ciao.com", + want: true, + }, + { + name: "good value2", + input: "http://ciao.com/ciao?id=1&ip=1.1.1.1", + want: true, + }, + { + name: "malformed input1", + input: "\\", + want: false, + }, + { + name: "malformed input2", + input: "#ciao.com", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.IsURL(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestBuildURL(t *testing.T) { + tests := []struct { + name string + scheme string + subdomain string + domain string + want string + }{ + { + name: "good value1", + scheme: "http", + subdomain: "sub", + domain: "ciao.com", + want: "http://sub.ciao.com", + }, + { + name: "good value2", + scheme: "https", + subdomain: "verylongsub.sub.sub", + domain: "ciao.com", + want: "https://verylongsub.sub.sub.ciao.com", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.BuildURL(tt.scheme, tt.subdomain, tt.domain) + require.Equal(t, tt.want, got) + }) + } +} + +func TestAppendDir(t *testing.T) { + tests := []struct { + name string + scheme string + domain string + dir string + want1 string + want2 string + }{ + { + name: "good value", + scheme: "http", + domain: "ciao.com", + dir: "secret", + want1: "http://ciao.com/secret/", + want2: "http://ciao.com/secret", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got1, got2 := urlUtils.AppendDir(tt.scheme, tt.domain, tt.dir) + require.Equal(t, tt.want1, got1) + require.Equal(t, tt.want2, got2) + }) + } +} + +func TestCleanSubdomainsOk(t *testing.T) { + tests := []struct { + name string + target string + input []string + want []string + }{ + { + name: "good value1", + target: "ciao.com", + input: []string{"sub1.ciao.com", "sub1ciao.com", "ciao.com", ".ciao.com"}, + want: []string{"sub1.ciao.com"}, + }, + { + name: "good value2", + target: "ciao.com", + input: []string{"sub2.sub1.ciao.com", "sub1.ciao.com", "sub1ciao.com", "ciao.com", ".ciao.com"}, + want: []string{"sub2.sub1.ciao.com", "sub1.ciao.com"}, + }, + { + name: "bad value", + target: "ciao.com", + input: []string{"sub1ciao.com", "sub1ciao.com", "ciaocom", ".ciaocom."}, + want: []string{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.CleanSubdomainsOk(tt.target, tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestRetrieveProtocol(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "single value", + input: "1", + want: "", + }, + { + name: "good value1", + input: "http://ciao.com", + want: "http", + }, + { + name: "good value2", + input: "http://ciao.com/ciao?id=1&ip=1.1.1.1", + want: "http", + }, + { + name: "malformed input", + input: "http/http/ciao.com/ciao", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.RetrieveProtocol(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestAbsoluteURL(t *testing.T) { + tests := []struct { + name string + scheme string + target string + path string + want string + }{ + { + name: "good value", + scheme: "http", + target: "ciao.com", + path: "secret", + want: "http://ciao.com/secret", + }, + { + name: "good value", + scheme: "https", + target: "sub.ciao.com", + path: "secret?ciao=1", + want: "https://sub.ciao.com/secret?ciao=1", + }, + { + name: "absolute path", + scheme: "https", + target: "sub.ciao.com", + path: "http://ciao.com/secret?ciao=1", + want: "http://ciao.com/secret?ciao=1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.AbsoluteURL(tt.scheme, tt.target, tt.path) + require.Equal(t, tt.want, got) + }) + } +} + +func TestRetrieveHost(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "single value", + input: "1", + want: "", + }, + { + name: "good value1", + input: "http://ciao.com", + want: "ciao.com", + }, + { + name: "good value2", + input: "http://ciao.com/ciao?id=1&ip=1.1.1.1", + want: "ciao.com", + }, + { + name: "malformed input", + input: "http/http/ciao.com/ciao", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.RetrieveHost(tt.input) + require.Equal(t, tt.want, got) + }) + } +} + +func TestGetRootHost(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "single value", + input: "1", + want: "", + }, + { + name: "good value1", + input: "http://ciao.com", + want: "ciao.com", + }, + { + name: "good value2", + input: "http://sub1.ciao.com", + want: "ciao.com", + }, + { + name: "good value3", + input: "http://sub2.sub1.ciao.com", + want: "ciao.com", + }, + { + name: "good value2", + input: "http://ciao.com/ciao?id=1&ip=1.1.1.1", + want: "ciao.com", + }, + { + name: "malformed input", + input: "http/http/ciao.com/ciao", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := urlUtils.GetRootHost(tt.input) + require.Equal(t, tt.want, got) + }) + } +} From a78b2c4f87cdfb811e403bd8b9a963a01adac6a9 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Sun, 16 Oct 2022 19:34:35 +0200 Subject: [PATCH 21/25] Fix JSON output --- pkg/output/json.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/output/json.go b/pkg/output/json.go index 8ce3d1a..26b7b2b 100644 --- a/pkg/output/json.go +++ b/pkg/output/json.go @@ -50,9 +50,13 @@ func AppendOutputToJSON(output string, key string, record string, filename strin log.Fatal(err) } + if len(file) == 0 { + file = []byte(`{}`) + } + data := File{} - err = json.Unmarshal(file, &data) + err = json.Unmarshal(file, &data) if err != nil { log.Fatal(err) } From 4ca77cbb31dc9c40810ccc582f43c5a88180803f Mon Sep 17 00:00:00 2001 From: edoardottt Date: Mon, 17 Oct 2022 11:33:42 +0200 Subject: [PATCH 22/25] Fix output counter --- pkg/enumeration/dirs.go | 22 +++++++++------------- pkg/enumeration/port.go | 16 +++++++--------- pkg/enumeration/subs.go | 20 ++++++++------------ pkg/output/dirs.go | 4 ++-- pkg/output/subs.go | 2 +- 5 files changed, 27 insertions(+), 37 deletions(-) diff --git a/pkg/enumeration/dirs.go b/pkg/enumeration/dirs.go index 8456fe7..c0f1cd7 100644 --- a/pkg/enumeration/dirs.go +++ b/pkg/enumeration/dirs.go @@ -71,18 +71,11 @@ func AsyncDir(urls []string, ignore []string, outputFileJSON, outputFileHTML, ou waitgroup.Add(1) - if count%50 == 0 { // update counter - if !plain { - fmt.Fprint(os.Stdout, "\r \r") - } - - output.PrintDirs(dirs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) + if !plain { + fmt.Fprint(os.Stdout, "\r") } - if !plain && count%100 == 0 { // update counter - fmt.Fprint(os.Stdout, "\r \r") - fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) - } + output.PrintDirs(dirs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) go func(domain string) { defer waitgroup.Done() @@ -121,14 +114,17 @@ func AsyncDir(urls []string, ignore []string, outputFileJSON, outputFileHTML, ou output.AddDirs(domain, resp.Status, dirs, mutex) resp.Body.Close() }(domain) + + if !plain { // update counter + fmt.Fprint(os.Stdout, "\r") + fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) + } } - output.PrintDirs(dirs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) waitgroup.Wait() output.PrintDirs(dirs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) if !plain { - fmt.Fprint(os.Stdout, "\r \r") - fmt.Println() + fmt.Fprint(os.Stdout, "\r") } } diff --git a/pkg/enumeration/port.go b/pkg/enumeration/port.go index 97479dd..18a6f5a 100644 --- a/pkg/enumeration/port.go +++ b/pkg/enumeration/port.go @@ -138,11 +138,6 @@ func AsyncPort(portsArray []int, portsArrayBool bool, startingPort int, endingPo limiter <- portStr - if !plain && count%100 == 0 { // update counter - fmt.Fprint(os.Stdout, "\r \r") - fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) - } - go func(portStr string, host string) { defer func() { <-limiter }() defer waitgroup.Done() @@ -152,7 +147,7 @@ func AsyncPort(portsArray []int, portsArrayBool bool, startingPort int, endingPo if resp { if !plain { - fmt.Fprint(os.Stdout, "\r \r") + fmt.Fprint(os.Stdout, "\r") fmt.Printf("[+]FOUND: %s ", host) color.Green("%s\n", portStr) } else { @@ -172,14 +167,17 @@ func AsyncPort(portsArray []int, portsArrayBool bool, startingPort int, endingPo } } }(portStr, host) + + if !plain { // update counter + fmt.Fprint(os.Stdout, "\r") + fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) + } } waitgroup.Wait() if !plain { - fmt.Fprint(os.Stdout, "\r \r") - fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) - fmt.Println() + fmt.Fprint(os.Stdout, "\r") } if outputFileHTML != "" { diff --git a/pkg/enumeration/subs.go b/pkg/enumeration/subs.go index 7a28037..82fad4c 100644 --- a/pkg/enumeration/subs.go +++ b/pkg/enumeration/subs.go @@ -69,18 +69,11 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o waitgroup.Add(1) - if count%50 == 0 { // update counter - if !plain { - fmt.Fprint(os.Stdout, "\r \r") - } - - output.PrintSubs(subs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) + if !plain { + fmt.Fprint(os.Stdout, "\r") } - if !plain && count%10 == 0 { // update counter - fmt.Fprint(os.Stdout, "\r \r") - fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) - } + output.PrintSubs(subs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) go func(domain string) { defer waitgroup.Done() @@ -128,13 +121,16 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o resp.Body.Close() } }(domain) + if !plain { // update counter + fmt.Fprint(os.Stdout, "\r") + fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) + } } waitgroup.Wait() output.PrintSubs(subs, ignore, outputFileJSON, outputFileHTML, outputFileTXT, mutex, plain) if !plain { - fmt.Fprint(os.Stdout, "\r \r") - fmt.Println() + fmt.Fprint(os.Stdout, "\r") } } diff --git a/pkg/output/dirs.go b/pkg/output/dirs.go index 1e97ac7..a4c2d8c 100644 --- a/pkg/output/dirs.go +++ b/pkg/output/dirs.go @@ -52,7 +52,7 @@ func PrintDirs(dirs map[string]Asset, ignore []string, outputFileJSON, outputFil if !plain { if string(resp[0]) == "2" || string(resp[0]) == "3" { - fmt.Fprint(os.Stdout, "\r \r") + fmt.Fprint(os.Stdout, "\r") fmt.Printf("[+]FOUND: %s ", domain) color.Green("%s\n", resp) @@ -68,7 +68,7 @@ func PrintDirs(dirs map[string]Asset, ignore []string, outputFileJSON, outputFil AppendWhere(domain, fmt.Sprint(resp), "DIR", "", "txt", outputFileTXT) } } else if (resp[:3] != "404") || string(resp[0]) == "5" { - fmt.Fprint(os.Stdout, "\r \r") + fmt.Fprint(os.Stdout, "\r") fmt.Printf("[+]FOUND: %s ", domain) color.Red("%s\n", resp) diff --git a/pkg/output/subs.go b/pkg/output/subs.go index 1d82e5c..1b39532 100644 --- a/pkg/output/subs.go +++ b/pkg/output/subs.go @@ -53,7 +53,7 @@ func PrintSubs(subs map[string]Asset, ignore []string, outputFileJSON, outputFil var resp = asset.Value if !plain { - fmt.Fprint(os.Stdout, "\r \r") + fmt.Fprint(os.Stdout, "\r") if resp == "" || resp[:3] != "404" { subDomainFound := urlUtils.CleanProtocol(domain) From 1698b607c233299db510e7315eac5c913cbca321 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Mon, 17 Oct 2022 11:37:23 +0200 Subject: [PATCH 23/25] Fix html output --- pkg/enumeration/subs.go | 1 + pkg/output/html.go | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/pkg/enumeration/subs.go b/pkg/enumeration/subs.go index 82fad4c..9429d57 100644 --- a/pkg/enumeration/subs.go +++ b/pkg/enumeration/subs.go @@ -121,6 +121,7 @@ func AsyncGet(protocol string, urls []string, ignore []string, outputFileJSON, o resp.Body.Close() } }(domain) + if !plain { // update counter fmt.Fprint(os.Stdout, "\r") fmt.Printf("%0.2f%% : %d / %d", mathUtils.Percentage(count, total), count, total) diff --git a/pkg/output/html.go b/pkg/output/html.go index 1402308..2b718c3 100644 --- a/pkg/output/html.go +++ b/pkg/output/html.go @@ -88,6 +88,10 @@ func AppendOutputToHTML(output string, status string, filename string) { statusColor = status } + if !urlUtils.ProtocolExists(output) { + output = "http://" + output + } + if _, err := file.WriteString("
  • " + urlUtils.CleanProtocol(output) + " " + statusColor + "
  • "); err != nil { From 5e37f501eb390fb81037b0e0159c379ff06ecdb0 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Mon, 17 Oct 2022 11:38:43 +0200 Subject: [PATCH 24/25] update README.md --- README.md | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/README.md b/README.md index 9ba4b2f..33a84fc 100644 --- a/README.md +++ b/README.md @@ -270,44 +270,12 @@ Special thanks to: [danielmiessler](https://github.com/danielmiessler), [sonarSe **To do:** - - [ ] Tests (😂) + - [ ] Add more tests - [ ] Tor support - [ ] Proxy support - - [x] JSON output - - - [x] Dockerfile - - - [x] Plain output (print only results) - - - [x] Scan only common ports - - - [x] Add option to use a public database of known subdomains - - - [x] Recursive Web crawling for subdomains and directories - - - [x] Check input and if it's an IP try to change to hostname when dns or subdomain is active - - - [x] Ignore responses by status codes (partially done, to do with `*`, e.g. `-i 4**`) - - - [x] HTML output - - - [x] Build an Input Struct and use it as parameter - - - [x] Output color - - - [x] Subdomains enumeration - - - [x] DNS enumeration - - - [x] Port enumeration - - - [x] Directories enumeration - - - [x] TXT output - License 📝 ------- From e6244f084326fd81891c47b5545508fb37945790 Mon Sep 17 00:00:00 2001 From: edoardottt Date: Mon, 17 Oct 2022 11:44:48 +0200 Subject: [PATCH 25/25] v.1.2.6 --- Dockerfile | 2 +- pkg/output/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 881a6d6..018d12e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.16 +FROM golang:1.18 WORKDIR $GOPATH/src/github.com/edoardottt/scilla diff --git a/pkg/output/version.go b/pkg/output/version.go index 1a110ac..09eb333 100644 --- a/pkg/output/version.go +++ b/pkg/output/version.go @@ -1,3 +1,3 @@ package output -const version = "v1.2.5" +const version = "v1.2.6"