From d158df24a6bf72ef99bbb62a442edb9736a3c84e Mon Sep 17 00:00:00 2001 From: PinkDev1 <5990@protonmail.com> Date: Tue, 9 Nov 2021 00:29:14 -0300 Subject: [PATCH 1/5] Added out-of-scope filtering for URLs in custom out-of-scopes file --- main.go | 107 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/main.go b/main.go index 43acaf3..5466099 100644 --- a/main.go +++ b/main.go @@ -37,8 +37,9 @@ func main() { var reuseList string //should only be "Y", "N" or "" var explicitLevel int //should only be [0], 1, or 2 var scopesListFilepath string + var outofScopesListFilepath string - const usage = `Usage: ./hacker-scoper --file /path/to/targets [--company company | --custom-scopes-file /path/to/scopes] [--explicit-level INT] [--reuse Y/N] [--chain-mode] + const usage = `Usage: ./hacker-scoper --file /path/to/targets [--company company | --custom-inscopes-file /path/to/inscopes [--custom-outofcopes-file] /path/to/outofscopes] [--explicit-level INT] [--reuse Y/N] [--chain-mode] Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company google --explicit-level 2 -c, --company string Specify the company name to lookup. @@ -53,9 +54,12 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company -f, --file string Path to your file containing URLs - -csf, --custom-scopes-file string + -csf, --custom-inscopes-file string Path to a custom plaintext file containing scopes + -cosf, --custom-outofcopes-file + Path to a custom plaintext file containing scopes exclusions + -e, --explicit-level int How explicit we expect the scopes to be: 1 (default): Include subdomains in the scope even if there's not a wildcard in the scope @@ -78,7 +82,9 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company flag.StringVar(&targetsListFilepath, "f", "", "Path to your file containing URLs") flag.StringVar(&targetsListFilepath, "file", "", "Path to your file containing URLs") flag.StringVar(&scopesListFilepath, "csf", "", "Path to a custom plaintext file containing scopes") - flag.StringVar(&scopesListFilepath, "custom-scopes-file", "", "Path to a custom plaintext file containing scopes") + flag.StringVar(&scopesListFilepath, "custom-inscopes-file", "", "Path to a custom plaintext file containing scopes") + flag.StringVar(&outofScopesListFilepath, "cosf", "", "Path to a custom plaintext file containing scopes exclusions") + flag.StringVar(&outofScopesListFilepath, "custom-outofcopes-file", "", "Path to a custom plaintext file containing scopes exclusions") flag.IntVar(&explicitLevel, "e", 1, "Level of explicity expected. ([1]/2/3)") flag.IntVar(&explicitLevel, "explicit-level", 1, "Level of explicity expected. ([1]/2/3)") flag.BoolVar(&stxt, "cstxt", false, "Whether or not we will try to scrape security.txt from all domains and subdomains") @@ -432,7 +438,7 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company } } - parseScopesWrapper(scope, explicitLevel, targetsListFilepath) + parseScopesWrapper(scope, explicitLevel, targetsListFilepath, outofScopesListFilepath) } } @@ -457,7 +463,7 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company scopesScanner := bufio.NewScanner(scopesFile) for scopesScanner.Scan() { - parseScopesWrapper(scopesScanner.Text(), explicitLevel, targetsListFilepath) + parseScopesWrapper(scopesScanner.Text(), explicitLevel, targetsListFilepath, outofScopesListFilepath) } scopesFile.Close() @@ -567,8 +573,9 @@ func updateFireBountyJSON() { // *.example.com // 192.168.0.1 // 192.168.0.1/24 -func parseScopes(scope string, targetsListFilepath string, isWilcard bool) { - +// 192.168.0.1 +// 192.168.0.1/24 +func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outofScopesListFilepath string) { schemedScope := "http://" + scope var CIDR *net.IPNet @@ -648,19 +655,23 @@ func parseScopes(scope string, targetsListFilepath string, isWilcard bool) { //ex: wordpress.example.com with a scope of *.example.com will give a match //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) if strings.HasSuffix(removePortFromHost(currentTargetURL), scopeURL.Host) { - if !chainMode { - fmt.Println("[+] IN-SCOPE: " + scanner.Text()) - } else { - fmt.Println(scanner.Text()) + if !isOutOfScope(currentTargetURL, outofScopesListFilepath) { + if !chainMode { + fmt.Println("[+] IN-SCOPE: " + scanner.Text()) + } else { + fmt.Println(scanner.Text()) + } } } } else { if removePortFromHost(currentTargetURL) == scopeURL.Host { - if !chainMode { - fmt.Println("[+] IN-SCOPE: " + scanner.Text()) - } else { - fmt.Println(scanner.Text()) + if !isOutOfScope(currentTargetURL, outofScopesListFilepath) { + if !chainMode { + fmt.Println("[+] IN-SCOPE: " + scanner.Text()) + } else { + fmt.Println(scanner.Text()) + } } } @@ -675,22 +686,21 @@ func parseScopes(scope string, targetsListFilepath string, isWilcard bool) { } } -func parseScopesWrapper(scope string, explicitLevel int, targetsListFilepath string) { - +func parseScopesWrapper(scope string, explicitLevel int, targetsListFilepath string, outofScopesListFilepath string) { //if we have a wildcard domain if strings.Contains(scope, "*.") { //shorter way of saying if explicitLevel != 3 && explicitLevel !=1 if explicitLevel == 2 { //remove wildcard ("*.") scope = strings.ReplaceAll(scope, "*.", "") - parseScopes(scope, targetsListFilepath, true) + parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath) } } else if explicitLevel == 1 { //this is NOT a wildcard domain, but we'll treat it as such anyway - parseScopes(scope, targetsListFilepath, true) + parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath) } else { //this is NOT a wildcard domain. we will parse it explicitly - parseScopes(scope, targetsListFilepath, false) + parseScopes(scope, false, targetsListFilepath, outofScopesListFilepath) } } @@ -710,3 +720,60 @@ func removePortFromHost(url *url.URL) string { portless = strings.Replace(portless, ":", "", 1) return portless } + +//out-of-scopes are parsed as --explicit-level==2 +func isOutOfScope(target *url.URL, outofScopesListFilepath string) bool { + var err error + if _, err = os.Stat(outofScopesListFilepath); err == nil { + // path/to/whatever exists + //open the file + //https://stackoverflow.com/a/16615559/11490425 + outOfScopesFile, err := os.Open(outofScopesListFilepath) + if err != nil { + crash("Could not open "+outofScopesListFilepath, err) + } + + //Read the file line per line using bufio + outofScopeScanner := bufio.NewScanner(outOfScopesFile) + + for outofScopeScanner.Scan() { + isWildcard := strings.Contains(outofScopeScanner.Text(), "*.") + outOfScopeURL, err := url.Parse("http://" + outofScopeScanner.Text()) + if err != nil { + if !chainMode { + warning("Couldn't parse out-of-scope \"" + outofScopeScanner.Text() + "\" as a URL.") + } + return false + } + + if isWildcard { + //parse the scope as a URL + + //if x is a subdomain of y + //ex: wordpress.example.com with a scope of *.example.com will give a match + //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) + if strings.HasSuffix(removePortFromHost(target), outOfScopeURL.Host) { + return true + + } + } else { + if removePortFromHost(target) == outOfScopeURL.Host { + return true + + } + } + } + outOfScopesFile.Close() + + } else if errors.Is(err, os.ErrNotExist) { + // path/to/whatever does *not* exist + crash("OutOfScopes file supplied, but it does not exist!", err) + + } else { + // Schrodinger: file may or may not exist. See err for details. + crash("Couldn't verify existance of outofscopesFile", err) + + } + //actually unnecesary. Added to make compiler shut up + return false +} From 8fbe17e44fd5505e10ce8066de50f45eca950d83 Mon Sep 17 00:00:00 2001 From: PinkDev1 <5990@protonmail.com> Date: Tue, 9 Nov 2021 01:15:17 -0300 Subject: [PATCH 2/5] Added out-of-scope detection for IP addresses parsing of out-of-scope CIDR ranges is redundant --- main.go | 72 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/main.go b/main.go index 5466099..f311ec5 100644 --- a/main.go +++ b/main.go @@ -628,19 +628,23 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof if CIDR == nil { //Couldn't parse scope as CIDR range, retrying as ip match") if targetIp.String() == scopeIP.String() { - if !chainMode { - fmt.Println("[+] IN-SCOPE: " + scanner.Text()) - } else { - fmt.Println(scanner.Text()) + if !isOutOfScope(nil, outofScopesListFilepath, targetIp) { + if !chainMode { + fmt.Println("[+] IN-SCOPE: " + scanner.Text()) + } else { + fmt.Println(scanner.Text()) + } } } } else { if CIDR.Contains(targetIp) { - if !chainMode { - fmt.Println("[+] IN-SCOPE: " + scanner.Text()) - } else { - fmt.Println(scanner.Text()) + if !isOutOfScope(nil, outofScopesListFilepath, targetIp) { + if !chainMode { + fmt.Println("[+] IN-SCOPE: " + scanner.Text()) + } else { + fmt.Println(scanner.Text()) + } } } } @@ -655,7 +659,7 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof //ex: wordpress.example.com with a scope of *.example.com will give a match //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) if strings.HasSuffix(removePortFromHost(currentTargetURL), scopeURL.Host) { - if !isOutOfScope(currentTargetURL, outofScopesListFilepath) { + if !isOutOfScope(currentTargetURL, outofScopesListFilepath, nil) { if !chainMode { fmt.Println("[+] IN-SCOPE: " + scanner.Text()) } else { @@ -666,7 +670,7 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof } } else { if removePortFromHost(currentTargetURL) == scopeURL.Host { - if !isOutOfScope(currentTargetURL, outofScopesListFilepath) { + if !isOutOfScope(currentTargetURL, outofScopesListFilepath, nil) { if !chainMode { fmt.Println("[+] IN-SCOPE: " + scanner.Text()) } else { @@ -722,7 +726,7 @@ func removePortFromHost(url *url.URL) string { } //out-of-scopes are parsed as --explicit-level==2 -func isOutOfScope(target *url.URL, outofScopesListFilepath string) bool { +func isOutOfScope(targetURL *url.URL, outofScopesListFilepath string, targetIP net.IP) bool { var err error if _, err = os.Stat(outofScopesListFilepath); err == nil { // path/to/whatever exists @@ -737,29 +741,41 @@ func isOutOfScope(target *url.URL, outofScopesListFilepath string) bool { outofScopeScanner := bufio.NewScanner(outOfScopesFile) for outofScopeScanner.Scan() { - isWildcard := strings.Contains(outofScopeScanner.Text(), "*.") - outOfScopeURL, err := url.Parse("http://" + outofScopeScanner.Text()) - if err != nil { - if !chainMode { - warning("Couldn't parse out-of-scope \"" + outofScopeScanner.Text() + "\" as a URL.") + if targetURL != nil { + //parse target as a URL + isWildcard := strings.Contains(outofScopeScanner.Text(), "*.") + outOfScopeURL, err := url.Parse("http://" + outofScopeScanner.Text()) + if err != nil { + if !chainMode { + warning("Couldn't parse out-of-scope \"" + outofScopeScanner.Text() + "\" as a URL.") + } + return false } - return false - } - if isWildcard { - //parse the scope as a URL + if isWildcard { + //if x is a subdomain of y + //ex: wordpress.example.com with a scope of *.example.com will give a match + //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) + if strings.HasSuffix(removePortFromHost(targetURL), outOfScopeURL.Host) { + return true - //if x is a subdomain of y - //ex: wordpress.example.com with a scope of *.example.com will give a match - //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) - if strings.HasSuffix(removePortFromHost(target), outOfScopeURL.Host) { - return true + } + } else { + if removePortFromHost(targetURL) == outOfScopeURL.Host { + return true + } } } else { - if removePortFromHost(target) == outOfScopeURL.Host { - return true - + //IP mode + //attempt to parse current outOfScope as an IP + outOfScopeIp := net.ParseIP(outofScopeScanner.Text()) + //if we can parse the current outOfScope as an IP... + if outOfScopeIp != nil { + //try IP match + if targetIP.String() == outOfScopeIp.String() { + return true + } } } } From 0b46d7d0859210095d2ed1019d2493cdf8516392 Mon Sep 17 00:00:00 2001 From: PinkDev1 <5990@protonmail.com> Date: Fri, 12 Nov 2021 16:41:09 -0300 Subject: [PATCH 3/5] Fixed wildcards not being parsed by -e=1 --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index f311ec5..9fc46ed 100644 --- a/main.go +++ b/main.go @@ -693,8 +693,8 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof func parseScopesWrapper(scope string, explicitLevel int, targetsListFilepath string, outofScopesListFilepath string) { //if we have a wildcard domain if strings.Contains(scope, "*.") { - //shorter way of saying if explicitLevel != 3 && explicitLevel !=1 - if explicitLevel == 2 { + //shorter way of saying if explicitLevel == 2 || explicitLevel ==1 + if explicitLevel != 3 { //remove wildcard ("*.") scope = strings.ReplaceAll(scope, "*.", "") parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath) From 8c068b516864b4258e26551ad1a1280461a4bc67 Mon Sep 17 00:00:00 2001 From: PinkDev1 <5990@protonmail.com> Date: Fri, 12 Nov 2021 22:19:45 -0300 Subject: [PATCH 4/5] Added out-of-scope detection for firebounty scopes --- main.go | 211 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 123 insertions(+), 88 deletions(-) diff --git a/main.go b/main.go index 9fc46ed..027f922 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,34 @@ import ( const firebountyAPIURL = "https://firebounty.com/api/v1/scope/all/url_only/" const firebountyJSONFilename = "firebounty-scope-url_only.json" +//https://tutorialedge.net/golang/parsing-json-with-golang/ +type Scope struct { + Scope string //either a domain, or a wildcard domain + Scope_type string //we only care about "web_application" +} + +type Program struct { + Firebounty_url string //url.URL not allowed appearently + Scopes struct { + In_scopes []Scope + Out_of_scopes []Scope + } + Slug string + Tag string + Url string //url.URL not allowed appearently + Name string +} + +type WhiteLists struct { + Regex string //can't be "*regexp.Regexp" because they're actually domain wildcards + Program_slug string +} + +type Firebounty struct { + White_listed []WhiteLists + Pgms []Program +} + var chainMode bool var targetsListFilepath string @@ -382,34 +410,6 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company byteValue, _ := ioutil.ReadAll(jsonFile) jsonFile.Close() - //https://tutorialedge.net/golang/parsing-json-with-golang/ - type Scope struct { - Scope string //either a domain, or a wildcard domain - Scope_type string //we only care about "web_application" - } - - type Program struct { - Firebounty_url string //url.URL not allowed appearently - Scopes struct { - In_scopes []Scope - Out_of_scopes []Scope - } - Slug string - Tag string - Url string //url.URL not allowed appearently - Name string - } - - type WhiteLists struct { - Regex string //can't be "*regexp.Regexp" because they're actually domain wildcards - Program_slug string - } - - type Firebounty struct { - White_listed []WhiteLists - Pgms []Program - } - var firebountyJSON Firebounty err = json.Unmarshal(byteValue, &firebountyJSON) if err != nil { @@ -438,7 +438,7 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company } } - parseScopesWrapper(scope, explicitLevel, targetsListFilepath, outofScopesListFilepath) + parseScopesWrapper(scope, explicitLevel, targetsListFilepath, outofScopesListFilepath, firebountyJSON.Pgms[companyCounter].Scopes.Out_of_scopes) } } @@ -463,7 +463,7 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company scopesScanner := bufio.NewScanner(scopesFile) for scopesScanner.Scan() { - parseScopesWrapper(scopesScanner.Text(), explicitLevel, targetsListFilepath, outofScopesListFilepath) + parseScopesWrapper(scopesScanner.Text(), explicitLevel, targetsListFilepath, outofScopesListFilepath, nil) } scopesFile.Close() @@ -575,7 +575,7 @@ func updateFireBountyJSON() { // 192.168.0.1/24 // 192.168.0.1 // 192.168.0.1/24 -func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outofScopesListFilepath string) { +func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outofScopesListFilepath string, firebountyOutOfScopes []Scope) { schemedScope := "http://" + scope var CIDR *net.IPNet @@ -628,7 +628,7 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof if CIDR == nil { //Couldn't parse scope as CIDR range, retrying as ip match") if targetIp.String() == scopeIP.String() { - if !isOutOfScope(nil, outofScopesListFilepath, targetIp) { + if !isOutOfScope(nil, outofScopesListFilepath, targetIp, firebountyOutOfScopes) { if !chainMode { fmt.Println("[+] IN-SCOPE: " + scanner.Text()) } else { @@ -639,7 +639,7 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof } } else { if CIDR.Contains(targetIp) { - if !isOutOfScope(nil, outofScopesListFilepath, targetIp) { + if !isOutOfScope(nil, outofScopesListFilepath, targetIp, firebountyOutOfScopes) { if !chainMode { fmt.Println("[+] IN-SCOPE: " + scanner.Text()) } else { @@ -659,7 +659,7 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof //ex: wordpress.example.com with a scope of *.example.com will give a match //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) if strings.HasSuffix(removePortFromHost(currentTargetURL), scopeURL.Host) { - if !isOutOfScope(currentTargetURL, outofScopesListFilepath, nil) { + if !isOutOfScope(currentTargetURL, outofScopesListFilepath, nil, firebountyOutOfScopes) { if !chainMode { fmt.Println("[+] IN-SCOPE: " + scanner.Text()) } else { @@ -670,7 +670,7 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof } } else { if removePortFromHost(currentTargetURL) == scopeURL.Host { - if !isOutOfScope(currentTargetURL, outofScopesListFilepath, nil) { + if !isOutOfScope(currentTargetURL, outofScopesListFilepath, nil, firebountyOutOfScopes) { if !chainMode { fmt.Println("[+] IN-SCOPE: " + scanner.Text()) } else { @@ -690,21 +690,21 @@ func parseScopes(scope string, isWilcard bool, targetsListFilepath string, outof } } -func parseScopesWrapper(scope string, explicitLevel int, targetsListFilepath string, outofScopesListFilepath string) { +func parseScopesWrapper(scope string, explicitLevel int, targetsListFilepath string, outofScopesListFilepath string, firebountyOutOfScopes []Scope) { //if we have a wildcard domain if strings.Contains(scope, "*.") { //shorter way of saying if explicitLevel == 2 || explicitLevel ==1 if explicitLevel != 3 { //remove wildcard ("*.") scope = strings.ReplaceAll(scope, "*.", "") - parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath) + parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath, firebountyOutOfScopes) } } else if explicitLevel == 1 { //this is NOT a wildcard domain, but we'll treat it as such anyway - parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath) + parseScopes(scope, true, targetsListFilepath, outofScopesListFilepath, firebountyOutOfScopes) } else { //this is NOT a wildcard domain. we will parse it explicitly - parseScopes(scope, false, targetsListFilepath, outofScopesListFilepath) + parseScopes(scope, false, targetsListFilepath, outofScopesListFilepath, firebountyOutOfScopes) } } @@ -726,70 +726,105 @@ func removePortFromHost(url *url.URL) string { } //out-of-scopes are parsed as --explicit-level==2 -func isOutOfScope(targetURL *url.URL, outofScopesListFilepath string, targetIP net.IP) bool { +func isOutOfScope(targetURL *url.URL, outofScopesListFilepath string, targetIP net.IP, firebountyOutOfScopes []Scope) bool { var err error - if _, err = os.Stat(outofScopesListFilepath); err == nil { - // path/to/whatever exists - //open the file - //https://stackoverflow.com/a/16615559/11490425 - outOfScopesFile, err := os.Open(outofScopesListFilepath) - if err != nil { - crash("Could not open "+outofScopesListFilepath, err) - } - //Read the file line per line using bufio - outofScopeScanner := bufio.NewScanner(outOfScopesFile) + if outofScopesListFilepath != "" { + //user chose to use their own out-of-scopes file + if _, err = os.Stat(outofScopesListFilepath); err == nil { + // path/to/whatever exists + //open the file + //https://stackoverflow.com/a/16615559/11490425 + outOfScopesFile, err := os.Open(outofScopesListFilepath) + if err != nil { + crash("Could not open "+outofScopesListFilepath, err) + } + + //Read the file line per line using bufio + outofScopeScanner := bufio.NewScanner(outOfScopesFile) - for outofScopeScanner.Scan() { - if targetURL != nil { - //parse target as a URL - isWildcard := strings.Contains(outofScopeScanner.Text(), "*.") - outOfScopeURL, err := url.Parse("http://" + outofScopeScanner.Text()) - if err != nil { - if !chainMode { - warning("Couldn't parse out-of-scope \"" + outofScopeScanner.Text() + "\" as a URL.") - } - return false + for outofScopeScanner.Scan() { + + if parseOutOfScopes(targetURL, outofScopeScanner.Text(), targetIP) { + return true } + } + outOfScopesFile.Close() + return false - if isWildcard { - //if x is a subdomain of y - //ex: wordpress.example.com with a scope of *.example.com will give a match - //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) - if strings.HasSuffix(removePortFromHost(targetURL), outOfScopeURL.Host) { - return true + } else if errors.Is(err, os.ErrNotExist) { + // path/to/whatever does *not* exist + crash("OutOfScopes file supplied, but it does not exist!", err) - } - } else { - if removePortFromHost(targetURL) == outOfScopeURL.Host { - return true + } else { + // Schrodinger: file may or may not exist. See err for details. + crash("Couldn't verify existance of outofscopesFile", err) + } + } else { + //check target agains firebounty out-of-scopes + //for every outOfScope + for outOfScopeCounter := 0; outOfScopeCounter < len(firebountyOutOfScopes); outOfScopeCounter++ { + //if the scope_type is web_application and it's not empty + if firebountyOutOfScopes[outOfScopeCounter].Scope_type == "web_application" && firebountyOutOfScopes[outOfScopeCounter].Scope != "" { + outOfScope := firebountyOutOfScopes[outOfScopeCounter].Scope + if !chainMode { + //alert the user about potentially mis-configured bug-bounty program + if outOfScope[0:4] == "com." || outOfScope[0:4] == "org." { + warning("Scope starting with \"com.\" or \"org. found. This may be a sign of a misconfigured bug bounty program. Consider editing the \"" + firebountyJSONFilename + " file and removing the faulty entries. Also, report the failure to the mainters of the bug bounty program.") } } - } else { - //IP mode - //attempt to parse current outOfScope as an IP - outOfScopeIp := net.ParseIP(outofScopeScanner.Text()) - //if we can parse the current outOfScope as an IP... - if outOfScopeIp != nil { - //try IP match - if targetIP.String() == outOfScopeIp.String() { - return true - } + if parseOutOfScopes(targetURL, outOfScope, targetIP) { + return true } } + } - outOfScopesFile.Close() + } - } else if errors.Is(err, os.ErrNotExist) { - // path/to/whatever does *not* exist - crash("OutOfScopes file supplied, but it does not exist!", err) + //if we got no matches for any outOfScope + return false +} - } else { - // Schrodinger: file may or may not exist. See err for details. - crash("Couldn't verify existance of outofscopesFile", err) +func parseOutOfScopes(targetURL *url.URL, outOfScope string, targetIP net.IP) bool { + if targetURL != nil { + //parse target as a URL + isWildcard := strings.Contains(outOfScope, "*.") + outOfScopeURL, err := url.Parse("http://" + outOfScope) + if err != nil { + if !chainMode { + warning("Couldn't parse out-of-scope \"" + outOfScope + "\" as a URL.") + } + return false + } + + if isWildcard { + //if x is a subdomain of y + //ex: wordpress.example.com with a scope of *.example.com will give a match + //we DON'T do it by splitting on dots and matching, because that would cause errors with domains that have two top-level-domains (gov.br for example) + if strings.HasSuffix(removePortFromHost(targetURL), outOfScopeURL.Host) { + return true + + } + } else { + if removePortFromHost(targetURL) == outOfScopeURL.Host { + return true + } + } + } else { + //IP mode + //attempt to parse current outOfScope as an IP + outOfScopeIp := net.ParseIP(outOfScope) + //if we can parse the current outOfScope as an IP... + if outOfScopeIp != nil { + //try IP match + if targetIP.String() == outOfScopeIp.String() { + return true + } + } } - //actually unnecesary. Added to make compiler shut up + + //if nothing matched return false } From 739f5423420360772724292302732eb87d89fc8f Mon Sep 17 00:00:00 2001 From: PinkDev1 <5990@protonmail.com> Date: Fri, 12 Nov 2021 22:20:13 -0300 Subject: [PATCH 5/5] turned dangling panics into "crash" calls --- main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 027f922..750d873 100644 --- a/main.go +++ b/main.go @@ -256,7 +256,7 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company //open the output file for writing f, err := os.OpenFile(outputFileName, os.O_APPEND|os.O_WRONLY, 0600) if err != nil { - panic(err) + crash("Coulnd't open file "+outputFileName+" for writing security.txt URLs.", err) } defer f.Close() @@ -371,7 +371,8 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company } if company == "" && scopesListFilepath == "" { - panic("A company name is required to smartly weed-out out-of-scope URLs") + var err error + crash("A company name is required to smartly weed-out out-of-scope URLs", err) } else { //default value. user will use the integrated scope list @@ -413,7 +414,7 @@ Example: ./hacker-scoper --file /home/kali/Downloads/recon-targets.txt --company var firebountyJSON Firebounty err = json.Unmarshal(byteValue, &firebountyJSON) if err != nil { - panic(err) + crash("Couldn't parse firebountyJSON into pre-defined struct.", err) } //for every company...