diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..deb9588 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Nemesis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e3db3d --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# Subhunter +## A fast subdomain takeover tool + + + +## Description: + +Subdomain takeover is a common vulnerability that allows an attacker to gain control over a subdomain of a target domain and redirect users intended for an organization's domain to a website that performs malicious activities, such as phishing campaigns, +stealing user cookies, etc. It occurs when an attacker gains control over a subdomain of a target domain. +Typically, this happens when the subdomain has a CNAME in the DNS, but no host is providing content for it. +Subhunter takes a given list of subdomains and scans them to check this vulnerability. + +## Features: + +- Auto update +- Uses random user agents +- Built in Go +- Uses a fork of fingerprint data from well known sources ([can-i-take-over-xyz](https://github.com/EdOverflow/can-i-take-over-xyz/blob/master/README.md)) + +## Installation: + +### Option 1: + +[Download](https://github.com/Nemesis0U/Subhunter/releases) from releases + +### Option 2: +Build from source: + + $ git clone https://github.com/Nemesis0U/Subhunter.git + $ go build subhunter.go + +## Usage: + +### Options: + +``` +Usage of subhunter: + -l string + File including a list of hosts to scan + -o string + File to save results + -t int + Number of threads for scanning (default 50) + -timeout int + Timeout in seconds (default 20) +``` + +### Demo (Added fake fingerprint for POC): + +``` +./Subhunter -l subdomains.txt -o test.txt + + ____ _ _ _ + / ___| _ _ | |__ | |__ _ _ _ __ | |_ ___ _ __ + \___ \ | | | | | '_ \ | '_ \ | | | | | '_ \ | __| / _ \ | '__| + ___) | | |_| | | |_) | | | | | | |_| | | | | | | |_ | __/ | | + |____/ \__,_| |_.__/ |_| |_| \__,_| |_| |_| \__| \___| |_| + + +A fast subdomain takeover tool + +Created by Nemesis + +Loaded 88 fingerprints for current scan + +----------------------------------------------------------------------------- + +[+] Nothing found at www.ubereats.com: Not Vulnerable +[+] Nothing found at testauth.ubereats.com: Not Vulnerable +[+] Nothing found at apple-maps-app-clip.ubereats.com: Not Vulnerable +[+] Nothing found at about.ubereats.com: Not Vulnerable +[+] Nothing found at beta.ubereats.com: Not Vulnerable +[+] Nothing found at ewp.ubereats.com: Not Vulnerable +[+] Nothing found at edgetest.ubereats.com: Not Vulnerable +[+] Nothing found at guest.ubereats.com: Not Vulnerable +[+] Google Cloud: Possible takeover found at testauth.ubereats.com: Vulnerable +[+] Nothing found at info.ubereats.com: Not Vulnerable +[+] Nothing found at learn.ubereats.com: Not Vulnerable +[+] Nothing found at merchants.ubereats.com: Not Vulnerable +[+] Nothing found at guest-beta.ubereats.com: Not Vulnerable +[+] Nothing found at merchant-help.ubereats.com: Not Vulnerable +[+] Nothing found at merchants-beta.ubereats.com: Not Vulnerable +[+] Nothing found at merchants-staging.ubereats.com: Not Vulnerable +[+] Nothing found at messages.ubereats.com: Not Vulnerable +[+] Nothing found at order.ubereats.com: Not Vulnerable +[+] Nothing found at restaurants.ubereats.com: Not Vulnerable +[+] Nothing found at payments.ubereats.com: Not Vulnerable +[+] Nothing found at static.ubereats.com: Not Vulnerable + +Subhunter exiting... +Results written to test.txt + + +``` + diff --git a/banner.png b/banner.png new file mode 100644 index 0000000..d293b4a Binary files /dev/null and b/banner.png differ diff --git a/fingerprint.json b/fingerprint.json new file mode 100644 index 0000000..5ee45e2 --- /dev/null +++ b/fingerprint.json @@ -0,0 +1,482 @@ +[ + { + "service": "AWS/Elastic Beanstalk", + "cname": ["elasticbeanstalk.com"], + "fingerprint": "NXDOMAIN" + }, + { + "service": "AWS/S3", + "cname": ["s3.amazonaws.com"], + "fingerprint": "The specified bucket does not exist" + }, + { + "service": "Agile CRM", + "cname": ["agilecrm.com"], + "fingerprint": "Sorry, this page is no longer available." + }, + { + "service": "Airee.ru", + "cname": ["airee.ru"], + "fingerprint": "Ошибка 402. Сервис Айри.рф не оплачен" + }, + { + "service": "Anima", + "cname": ["animaapp.io"], + "fingerprint": "The page you were looking for does not exist." + }, + { + "service": "Bitbucket", + "cname": ["bitbucket.io"], + "fingerprint": "Repository not found" + }, + { + "service": "Campaign Monitor", + "cname": [], + "fingerprint": "Trying to access your account?" + }, + { + "service": "Canny", + "cname": [], + "fingerprint": "Company Not Found. There is no such company. Did you enter the right URL?" + }, + { + "service": "Cargo Collective", + "cname": [], + "fingerprint": "404 Not Found" + }, + { + "service": "Digital Ocean", + "cname": [], + "fingerprint": "Domain uses DO name servers with no records in DO." + }, + { + "service": "Discourse", + "cname": ["trydiscourse.com"], + "fingerprint": "NXDOMAIN" + }, + { + "service": "Gemfury", + "cname": ["furyns.com"], + "fingerprint": "404: This page could not be found." + }, + { + "service": "Getresponse", + "cname": [], + "fingerprint": "With GetResponse Landing Pages, lead generation has never been easier" + }, + { + "service": "Ghost", + "cname": ["ghost.io"], + "fingerprint": "Site unavailable. Failed to resolve DNS path for this host" + }, + { + "service": "HatenaBlog", + "cname": ["hatenablog.com"], + "fingerprint": "404 Blog is not found" + }, + { + "service": "Help Juice", + "cname": ["helpjuice.com"], + "fingerprint": "We could not find what you're looking for." + }, + { + "service": "Help Scout", + "cname": ["helpscoutdocs.com"], + "fingerprint": "No settings were found for this company:" + }, + { + "service": "Helprace", + "cname": ["helprace.com"], + "fingerprint": "HTTP_STATUS=301" + }, + { + "service": "JetBrains", + "cname": ["youtrack.cloud"], + "fingerprint": "is not a registered InCloud YouTrack" + }, + { + "service": "LaunchRock", + "cname": ["launchrock.com"], + "fingerprint": "HTTP_STATUS=500" + }, + { + "service": "Microsoft Azure", + "cname": [ + "cloudapp.net", + "cloudapp.azure.com", + "azurewebsites.net", + "blob.core.windows.net", + "cloudapp.azure.com", + "azure-api.net", + "azurehdinsight.net", + "azureedge.net", + "azurecontainer.io", + "database.windows.net", + "azuredatalakestore.net", + "search.windows.net", + "azurecr.io", + "redis.cache.windows.net", + "azurehdinsight.net", + "servicebus.windows.net", + "visualstudio.com" + ], + "fingerprint": "NXDOMAIN" + }, + { + "service": "Ngrok", + "cname": ["ngrok.io"], + "fingerprint": "Tunnel .*ngrok.io not found" + }, + { + "service": "Pantheon", + "cname": [], + "fingerprint": "404 error unknown site!" + }, + { + "service": "Pingdom", + "cname": [], + "fingerprint": "Sorry, couldn't find the status page" + }, + { + "service": "Readme.io", + "cname": ["readme.io"], + "fingerprint": "The creators of this project are still working on making everything perfect!" + }, + { + "service": "Readthedocs", + "cname": [], + "fingerprint": "The link you have followed or the URL that you entered does not exist." + }, + { + "service": "Short.io", + "cname": [], + "fingerprint": "Link does not exist" + }, + { + "service": "SmartJobBoard", + "cname": ["52.16.160.97"], + "fingerprint": "This job board website is either expired or its domain name is invalid." + }, + { + "service": "Smugsmug", + "cname": [], + "fingerprint": "" + }, + { + "service": "Strikingly", + "cname": ["s.strikinglydns.com"], + "fingerprint": "PAGE NOT FOUND." + }, + { + "service": "Surge.sh", + "cname": ["na-west1.surge.sh"], + "fingerprint": "project not found" + }, + { + "service": "SurveySparrow", + "cname": ["surveysparrow.com"], + "fingerprint": "Account not found." + }, + { + "service": "Uberflip", + "cname": ["read.uberflip.com"], + "fingerprint": "The URL you've accessed does not provide a hub." + }, + { + "service": "Uptimerobot", + "cname": ["stats.uptimerobot.com"], + "fingerprint": "page not found" + }, + { + "service": "Wordpress", + "cname": ["wordpress.com"], + "fingerprint": "Do you want to register .*wordpress.com?" + }, + { + "service": "Worksites", + "cname": ["worksites.net", "69.164.223.206"], + "fingerprint": "Hello! Sorry, but the website you’re looking for doesn’t exist." + }, + { + "service": "GitHub", + "cname": ["github.io", "github.map.fastly.net"], + "fingerprint": [ + "There isn't a GitHub Pages site here.", + "For root URLs (like http://example.com/) you must provide an index.html file" + ] + }, + { + "service": "Heroku", + "cname": ["herokudns.com", "herokussl.com", "herokuapp.com"], + "fingerprint": [ + "There's nothing here, yet.", + "herokucdn.com/error-pages/no-such-app.html", + "No such app" + ] + }, + { + "service": "Unbounce", + "cname": ["unbouncepages.com"], + "fingerprint": [ + "The requested URL / was not found on this server.", + "The requested URL was not found on this server" + ] + }, + { + "service": "Tumblr", + "cname": ["tumblr.com"], + "fingerprint": [ + "There's nothing here.", + "Whatever you were looking for doesn't currently exist at this address." + ] + }, + { + "service": "Shopify", + "cname": ["myshopify.com"], + "fingerprint": [ + "Sorry, this shop is currently unavailable.", + "Only one step left!" + ] + }, + { + "service": "Instapage", + "cname": ["pageserve.co", "secure.pageserve.co", "https://instapage.com/"], + "fingerprint": ["You've Discovered A Missing Link. Our Apologies!"] + }, + { + "service": "Desk", + "cname": ["desk.com"], + "fingerprint": [ + "Please try again or try Desk.com free for 14 days.", + "Sorry, We Couldn't Find That Page" + ] + }, + { + "service": "Tictail", + "cname": ["tictail.com", "domains.tictail.com"], + "fingerprint": [ + "Building a brand of your own?", + "to target URL: Trying to access your account?" + ] + }, + { + "service": "Cargo Collective", + "cname": ["cargocollective.com"], + "fingerprint": ["404 Not Found"] + }, + { + "service": "Statuspage", + "cname": ["statuspage.io"], + "fingerprint": ["Better Status Communication", "You are being redirected"] + }, + { + "service": "Amazon AWS", + "cname": ["amazonaws.com"], + "fingerprint": ["NoSuchBucket", "The specified bucket does not exist"] + }, + { + "service": "Cloudfront", + "cname": ["cloudfront.net"], + "fingerprint": ["The request could not be satisfied", "ERROR: The request could not be satisfied"] + }, + { + "service": "Bitbucket", + "cname": ["bitbucket.org"], + "fingerprint": ["The page you have requested does not exist"] + }, + { + "service": "Smartling", + "cname": ["smartling.com"], + "fingerprint": ["Domain is not configured"] + }, + { + "service": "Acquia", + "cname": ["acquia.com"], + "fingerprint": ["If you are an Acquia Cloud customer and expect to see your site at this address"] + }, + { + "service": "Fastly", + "cname": ["fastly.net"], + "fingerprint": ["Please check that this domain has been added to a service", "Fastly error: unknown domain"] + }, + { + "service": "Pantheon", + "cname": ["pantheonsite.io"], + "fingerprint": ["The gods are wise", "The gods are wise, but do not know of the site which you seek."] + }, + { + "service": "Zendesk", + "cname": ["zendesk.com"], + "fingerprint": ["Help Center Closed | Zendesk", "Help Center Closed"] + }, + { + "service": "UserVoice", + "cname": ["uservoice.com"], + "fingerprint": ["This UserVoice subdomain is currently available!"] + }, + { + "service": "Ghost", + "cname": ["ghost.io"], + "fingerprint": ["The thing you were looking for is no longer here", "The thing you were looking for is no longer here, or never was"] + }, + { + "service": "Pingdom", + "cname": ["stats.pingdom.com"], + "fingerprint": ["pingdom"] + }, + { + "service": "Tilda", + "cname": ["tilda.ws"], + "fingerprint": ["Domain has been assigned"] + }, + { + "service": "Wordpress", + "cname": ["wordpress.com"], + "fingerprint": ["Do you want to register"] + }, + { + "service": "Teamwork", + "cname": ["teamwork.com"], + "fingerprint": ["Oops - We didn't find your site."] + }, + { + "service": "Help Juice", + "cname": ["helpjuice.com"], + "fingerprint": ["We could not find what you're looking for."] + }, + { + "service": "Help Scout", + "cname": ["helpscoutdocs.com"], + "fingerprint": ["No settings were found for this company:"] + }, + { + "service": "Cargo Collective", + "cname": ["cargocollective.com"], + "fingerprint": ["If you're moving your domain away from Cargo you must make this configuration through your registrar's DNS control panel."] + }, + { + "service": "Feedpress", + "cname": ["redirect.feedpress.me"], + "fingerprint": ["The feed has not been found."] + }, + { + "service": "Surge", + "cname": ["surge.sh"], + "fingerprint": ["project not found"] + }, + { + "service": "SurveyGizmo", + "cname": ["privatedomain.sgizmo.com", "privatedomain.surveygizmo.eu", "privatedomain.sgizmoca.com"], + "fingerprint": ["data-html-name"] + }, + { + "service": "Mashery", + "cname": ["mashery.com"], + "fingerprint": ["Unrecognized domain "] + }, + { + "service": "Intercom", + "cname": ["custom.intercom.help"], + "fingerprint": ["This page is reserved for artistic dogs.", "

Uh oh. That page doesn’t exist.

"] + }, + { + "service": "Webflow", + "cname": ["proxy.webflow.io"], + "fingerprint": ["

The page you are looking for doesn't exist or has been moved.

"] + }, + { + "service": "Kajabi", + "cname": ["endpoint.mykajabi.com"], + "fingerprint": ["

The page you were looking for doesn't exist.

"] + }, + { + "service": "Thinkific", + "cname": ["thinkific.com"], + "fingerprint": ["You may have mistyped the address or the page may have moved."] + }, + { + "service": "Tave", + "cname": ["clientaccess.tave.com"], + "fingerprint": ["

Error 404: Page Not Found

"] + }, + { + "service": "Wishpond", + "cname": ["wishpond.com"], + "fingerprint": ["https://www.wishpond.com/404?campaign=true"] + }, + { + "service": "AfterShip", + "cname": ["aftership.com"], + "fingerprint": ["Oops.

The page you're looking for doesn't exist."] + }, + { + "service": "Aha", + "cname": ["ideas.aha.io"], + "fingerprint": ["There is no portal here ... sending you back to Aha!"] + }, + { + "service": "Brightcove", + "cname": ["brightcovegallery.com", "gallery.video", "bcvp0rtal.com"], + "fingerprint": ["

"] + }, + { + "service": "Bigcartel", + "cname": ["bigcartel.com"], + "fingerprint": ["

Oops! We couldn’t find that page.

"] + }, + { + "service": "ActiveCampaign", + "cname": ["activehosted.com"], + "fingerprint": ["alt=\"LIGHTTPD - fly light.\""] + }, + { + "service": "Campaign Monitor", + "cname": ["createsend.com"], + "fingerprint": ["Double check the URL or
%v", target, errs) + } + resultMessage := fmt.Sprintf("Failed to check %s: Error", target) + PrintResult(Red, resultMessage) + NotVulnerableResults = append(NotVulnerableResults, resultMessage) + } +} + +var CheckedTargetsMutex sync.Mutex // Declares the mutex globally +var CheckedTargets = make(map[string]bool) // Declares CheckedTargets globally + +func Checker(target string) { + TargetCNAME, err := net.LookupCNAME(target) + if err != nil { + return + } + + CheckedTargetsMutex.Lock() // Locks the mutex + if All != true && CNAMEExists(TargetCNAME) == true { + if Verbose == true { + log.Printf("(CNAME Selected) %s => %s", target, TargetCNAME) + } + Check(target, TargetCNAME) + } else if All == true && !CheckedTargets[target] { // Checks if the target hasn't been checked already + CheckedTargets[target] = true // Marks the target as checked + Check(target, "All") + } + CheckedTargetsMutex.Unlock() // Unlocks the mutex +} + +func main() { + All = true + Verbose = true + ParseArguments() + + // Initializes fingerprints before using them + InitializeFingerprints() + + for _, Host := range Targets { + go Checker(Host) + } + + fmt.Println("") + Banner := figure.NewColorFigure("Subhunter", "", "red", true) + Banner.Print() + fmt.Println("\n\nA fast subdomain takeover tool\n") + fmt.Println("Created by Nemesis") + fmt.Printf("\nLoaded %d fingerprints for current scan\n", len(Fingerprints)) + fmt.Println("\n-----------------------------------------------------------------------------\n") + + if HostsList == "" { + fmt.Printf("Subhunter: No subdomains list specified for the scan!") + fmt.Printf("\n\nInfo: Use -h for showing the help message\n\n") + os.Exit(1) + } + + Hosts, err := ReadFile(HostsList) + if err != nil { + fmt.Printf("\nread: %s\n", err) + os.Exit(1) + } + + Targets = append(Targets, Hosts...) + + hosts := make(chan string, Threads) + processGroup := new(sync.WaitGroup) + processGroup.Add(Threads) + + for i := 0; i < Threads; i++ { + go func() { + for { + host := <-hosts + if host == "" { + break + } + + Checker(host) + } + + processGroup.Done() + }() + } + + for _, Host := range Targets { + hosts <- Host + } + + close(hosts) + processGroup.Wait() + + fmt.Printf("\nSubhunter exiting...\n") + + // Writes the results to the output file if provided + if OutputFile != "" { + WriteResultsToFile(OutputFile, VulnerableResults, NotVulnerableResults) + } +} + +func WriteResultsToFile(filename string, vulnerableResults []string, notVulnerableResults []string) { + file, err := os.Create(filename) + if err != nil { + log.Fatalf("Error creating output file: %v", err) + } + defer file.Close() + + // Writes vulnerable results + for _, result := range vulnerableResults { + _, err := file.WriteString(result + "\n") + if err != nil { + log.Fatalf("Error writing to output file: %v", err) + } + } + + // Writes other results + for _, result := range notVulnerableResults { + _, err := file.WriteString(result + "\n") + if err != nil { + log.Fatalf("Error writing to output file: %v", err) + } + } + + fmt.Printf("Results written to %s\n", filename) +}