Updated Readme to reflect new branding
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
@@ -30,14 +30,18 @@ clean:
|
||||
|
||||
# Build for current platform
|
||||
build:
|
||||
$(GO) build -o $(BUILD_DIR)/$(BINARY_NAME) -ldflags "-X main.version=$(VERSION)" crowsnest.go
|
||||
CGO_ENABLED=1 $(GO) build -o $(BUILD_DIR)/$(BINARY_NAME) -ldflags "-X main.version=$(VERSION)" crowsnest.go
|
||||
|
||||
# Build for all platforms
|
||||
build-all: clean
|
||||
@for platform in $(PLATFORMS); do \
|
||||
for arch in $(ARCHS); do \
|
||||
echo "Building for $$platform/$$arch..."; \
|
||||
GOOS=$$platform GOARCH=$$arch $(GO) build -o $(BUILD_DIR)/$(BINARY_NAME)-$$platform-$$arch -ldflags "-X main.version=$(VERSION)" crowsnest.go; \
|
||||
if [ "$$platform" = "windows" ] || [ "$$platform" = "darwin" ]; then \
|
||||
GOOS=$$platform GOARCH=$$arch CGO_ENABLED=0 $(GO) build -o $(BUILD_DIR)/$(BINARY_NAME)-$$platform-$$arch -ldflags "-X main.version=$(VERSION)" crowsnest.go; \
|
||||
else \
|
||||
GOOS=$$platform GOARCH=$$arch CGO_ENABLED=1 $(GO) build -o $(BUILD_DIR)/$(BINARY_NAME)-$$platform-$$arch -ldflags "-X main.version=$(VERSION)" crowsnest.go; \
|
||||
fi; \
|
||||
if [ "$$platform" = "windows" ]; then \
|
||||
mv $(BUILD_DIR)/$(BINARY_NAME)-$$platform-$$arch $(BUILD_DIR)/$(BINARY_NAME)-$$platform-$$arch.exe; \
|
||||
fi; \
|
||||
|
||||
@@ -61,30 +61,25 @@ To configure the database location:
|
||||
###️ Initial Setup
|
||||
|
||||
CrowsNest requires an API key from Dehashed. Set it up with:
|
||||

|
||||
```bash
|
||||
ar1ste1a@kali:~$ crowsnest set-dehashed <redacted>
|
||||
```
|
||||
|
||||
### Simple Query
|
||||
CrowsNest can be used simply for example to query for credentials matching a given email domain.
|
||||

|
||||
``` go
|
||||
# Provide credentials for domains matching target.com
|
||||
crowsnest api -D target.com -C
|
||||
crowsnest dehashed -D target.com
|
||||
```
|
||||
|
||||
### Simple Credentials Query
|
||||
CrowsNest can also be used to return only credentials for a given query.
|
||||

|
||||
``` go
|
||||
# Provide credentials for emails matching @target.com
|
||||
crowsnest api -E @target.com -C
|
||||
```
|
||||
|
||||
### Multiple Match Query
|
||||
CrowsNest is capable of handling multiple queries for the same field.
|
||||
This is useful for when you want to search for multiple domains, or multiple usernames.
|
||||
``` go
|
||||
# Provide credentials for domains matching target.com and target2.com, retrieving only credentials
|
||||
crowsnest api -D target.com,target2.com -C
|
||||
crowsnest dehashed -D @target.com -C
|
||||
```
|
||||
|
||||
### Wildcard Query
|
||||
@@ -92,34 +87,46 @@ CrowsNest is capable of handling wildcard queries.
|
||||
A wildcard query cannot begin with a wildcard.
|
||||
This is a limitation of the Dehashed API.
|
||||
An asterisk can be used to denote multiple characters, and a question mark can be used to denote a single character.
|
||||

|
||||

|
||||
``` go
|
||||
# Provide credentials for emails matching @target.com and @target2.com
|
||||
crowsnest api -E @target?.com -C -W
|
||||
crowsnest dehashed -E @target?.com -C -W
|
||||
```
|
||||
|
||||
### Email Query
|
||||
Dehashed has dictated that emails should be searched in the following format:
|
||||
`email:target.name&domain:target.com`.
|
||||
As such, to query an email, please use the following format (note, wildcard is not required but can be useful):
|
||||
<br>
|
||||
*see photo above in Wildcard Query*
|
||||
``` go
|
||||
# Provide credentials for emails matching target.*@target.com
|
||||
crowsnest api -W -E 'target*' -D target.com
|
||||
crowsnest dehashed -W -E 'target*' -D target.com
|
||||
```
|
||||
You may also query the domain and find emails as well
|
||||
``` go
|
||||
# Provide credentials for emails matching target.com
|
||||
crowsnest api -D target.com -C
|
||||
crowsnest dehashed -D target.com -C
|
||||
```
|
||||
|
||||
### Combining Queries
|
||||
CrowsNest is capable of combining queries.
|
||||
This is useful for when you want to query for credentials matching a given email or domain, but only for a specific username.
|
||||

|
||||
``` go
|
||||
# Provide credentials for emails matching @target.com and username containing 'admin'
|
||||
crowsnest dehashed -D target.com -U admin
|
||||
```
|
||||
|
||||
### Regex Query
|
||||
CrowsNest is capable of handling regex queries.
|
||||
Simply denote regex queries with the `-R` flag.
|
||||
Place all regex queries in quotes with the corresponding query flag in single quotes.
|
||||
<br>
|
||||
!!!! *Currently, the Regex Operators appear to be broken. I am waiting on a response from Dehashed* !!!!
|
||||
``` go
|
||||
# Return matches for emails matching this given regex query
|
||||
crowsnest api -R -E '[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)?@target.com'
|
||||
crowsnest dehashed -R -E 'joh?n(ath[oa]n)' -D hotmail.com'
|
||||
```
|
||||
|
||||
### Output Text (default JSON)
|
||||
@@ -129,7 +136,7 @@ To change the output format, use the `-f` flag.
|
||||
CrowsNest currently supports JSON, YAML, XML, and TEXT output formats.
|
||||
``` go
|
||||
# Return matches for usernames exactly matching "admin" and write to text file 'admins_file.txt'
|
||||
crowsnest api -U admin -o admins_file -f txt
|
||||
crowsnest dehashed -U admin -o admins_file -f txt
|
||||
```
|
||||
|
||||
---
|
||||
@@ -141,7 +148,7 @@ The WhoIs Lookups require a separate API Credit from the Dehashed API.
|
||||
### Domain Lookup
|
||||
CrowsNest can perform a domain lookup for a given domain.
|
||||
This provides a tree view of the domain's WHOIS information.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a WHOIS lookup for example.com
|
||||
crowsnest whois -d example.com
|
||||
@@ -156,10 +163,20 @@ The history lookup is immediately written to file and not displayed in the termi
|
||||
crowsnest whois -d example.com -H
|
||||
```
|
||||
|
||||
### Subdomain Scan
|
||||
CrowsNest can perform a subdomain scan for a given domain.
|
||||
This provides a list of all subdomains that match the given query.
|
||||

|
||||
```bash
|
||||
# Perform a WHOIS subdomain scan for google.com
|
||||
crowsnest whois -d google.com -s
|
||||
```
|
||||
|
||||
### Reverse WHOIS Lookup
|
||||
CrowsNest can perform a reverse WHOIS lookup for given criteria.
|
||||
This provides a list of all domains that match the given query.
|
||||
The reverse WHOIS lookup is immediately written to file and not displayed in the terminal or stored in the database.
|
||||
The reverse WHOIS lookup is immediately written to file and not stored in the database.
|
||||

|
||||
```bash
|
||||
# Perform a reverse WHOIS lookup for example.com
|
||||
crowsnest whois -I example.com
|
||||
@@ -168,7 +185,7 @@ crowsnest whois -I example.com
|
||||
### IP Lookup
|
||||
CrowsNest can perform a reverse IP lookup for a given IP address.
|
||||
This provides a list of all domains that match the given query.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a reverse IP lookup for 8.8.8.8
|
||||
crowsnest whois -i 8.8.8.8
|
||||
@@ -177,28 +194,21 @@ crowsnest whois -i 8.8.8.8
|
||||
### MX Lookup
|
||||
CrowsNest can perform an MX lookup for a given MX hostname.
|
||||
This provides a list of all domains that match the given query.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a reverse MX lookup for google.com
|
||||
crowsnest whois -m google.com
|
||||
crowsnest whois -m stmp.google.com
|
||||
```
|
||||
### NS Lookup
|
||||
CrowsNest can perform an NS lookup for a given NS hostname.
|
||||
This provides a list of all domains that match the given query.
|
||||
The picture below also includes the --debug global flag.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a reverse NS lookup for google.com
|
||||
crowsnest whois -n google.com
|
||||
```
|
||||
### Subdomain Scan
|
||||
CrowsNest can perform a subdomain scan for a given domain.
|
||||
This provides a list of all subdomains that match the given query.
|
||||

|
||||
```bash
|
||||
# Perform a WHOIS subdomain scan for google.com
|
||||
crowsnest whois -d google.com -s
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
@@ -206,6 +216,7 @@ crowsnest whois -d google.com -s
|
||||
CrowsNest supports Hunter.io lookups.
|
||||
Hunter.io lookups require a separate API Key from the Dehashed API.
|
||||
This can be set using the `set-hunter` command.
|
||||

|
||||
```bash
|
||||
# Set the Hunter.io API key
|
||||
crowsnest set-hunter <redacted>
|
||||
@@ -214,25 +225,16 @@ crowsnest set-hunter <redacted>
|
||||
### Domain Search
|
||||
CrowsNest can perform a domain search for a given domain.
|
||||
This provides information about company including a description, social media information and any technologies in use.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a Hunter.io domain search for example.com
|
||||
crowsnest hunter -d example.com -D
|
||||
```
|
||||
|
||||
### Email Finder
|
||||
CrowsNest can perform an email finder search for a given domain, first name, and last name.
|
||||
This provides information about a user including a confidence score, and any social media accounts linked to a first name, last name and email.
|
||||

|
||||
```bash
|
||||
# Perform a Hunter.io email finder search for example.com
|
||||
crowsnest hunter -d example.com -F John -L Doe -E
|
||||
```
|
||||
|
||||
### Email Verification
|
||||
CrowsNest can perform an email verification search for a given email.
|
||||
This provides a verification and score of a given email address.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a Hunter.io email verification search for example@target.com
|
||||
crowsnest hunter -e example@target.com -V
|
||||
@@ -241,16 +243,25 @@ crowsnest hunter -e example@target.com -V
|
||||
### Company Enrichment
|
||||
CrowsNest can perform a company enrichment search for a given domain.
|
||||
This provides information about a company given its domain.
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a Hunter.io company enrichment search for example.com
|
||||
crowsnest hunter -d example.com -C
|
||||
```
|
||||
|
||||
### Email Finder
|
||||
CrowsNest can perform an email finder search for a given domain, first name, and last name.
|
||||
This provides information about a user including a confidence score, and any social media accounts linked to a first name, last name and email.
|
||||

|
||||
```bash
|
||||
# Perform a Hunter.io email finder search for example.com
|
||||
crowsnest hunter -d example.com -F John -L Doe -E
|
||||
```
|
||||
|
||||
### Person Enrichment
|
||||
CrowsNest can perform a person enrichment search for a given email.
|
||||
This provides information about a user given an email address..
|
||||

|
||||

|
||||
```bash
|
||||
# Perform a Hunter.io person enrichment search for example@target.com
|
||||
crowsnest hunter -e example@target.com -P
|
||||
@@ -376,7 +387,7 @@ crowsnest logs -s "05-01-2025" -v error,fatal
|
||||
|
||||
## 🎉 Sample Run
|
||||
```bash
|
||||
ar1ste1a@kali:~$ crowsnest api -D <redacted>.com -o <redacted> -f json
|
||||
ar1ste1a@kali:~$ crowsnest dehashed -D <redacted>.com -o <redacted> -f json
|
||||
Making 3 Requests for 10000 Records (30000 Total)
|
||||
[*] Querying Dehashed API...
|
||||
[*] Performing Request...
|
||||
|
||||
+1
-2
@@ -166,7 +166,7 @@ var (
|
||||
fmt.Println("Email Find Result:")
|
||||
|
||||
var (
|
||||
headers = []string{"Email", "Score", "Domain", "Accept All", "Position", "Twitter", "Linkedin", "Phone Number", "Company", "Sources", "Verification"}
|
||||
headers = []string{"Email", "Score", "Domain", "Accept All", "Position", "Twitter", "Linkedin", "Phone Number", "Company", "Verification"}
|
||||
rows [][]string
|
||||
)
|
||||
|
||||
@@ -180,7 +180,6 @@ var (
|
||||
result.LinkedinURL,
|
||||
result.PhoneNumber,
|
||||
result.Company,
|
||||
fmt.Sprintf("%v", result.Sources),
|
||||
fmt.Sprintf("%v", result.Verification),
|
||||
})
|
||||
|
||||
|
||||
+95
-60
@@ -26,7 +26,7 @@ func init() {
|
||||
whoisCmd.Flags().StringVarP(&whoisNSAddress, "ns", "n", "", "NS hostname for reverse NS lookup")
|
||||
whoisCmd.Flags().StringVarP(&whoisInclude, "include", "I", "", "Up to 4 Terms to include in reverse WHOIS search (comma-separated)")
|
||||
whoisCmd.Flags().StringVarP(&whoisExclude, "exclude", "E", "", "Up to 4 Terms to exclude in reverse WHOIS search (comma-separated)")
|
||||
whoisCmd.Flags().StringVarP(&whoisReverseType, "type", "t", "registrant", "Type of reverse WHOIS search ([default] current or historic)")
|
||||
whoisCmd.Flags().StringVarP(&whoisReverseType, "type", "t", "current", "Type of reverse WHOIS search ([default] current or historic)")
|
||||
whoisCmd.Flags().StringVarP(&whoisOutputFormat, "format", "f", "text", "Output format (text, json)")
|
||||
whoisCmd.Flags().StringVarP(&whoisOutputFile, "output", "o", "whois", "File to output results to including extension")
|
||||
whoisCmd.Flags().BoolVarP(&whoisShowCredits, "credits", "c", false, "Show remaining WHOIS credits")
|
||||
@@ -118,57 +118,59 @@ var (
|
||||
if whoisDomain != "" {
|
||||
fmt.Println("[*] Performing WHOIS lookup...")
|
||||
|
||||
// Domain lookup
|
||||
result, err := w.WhoisSearch(whoisDomain)
|
||||
if err != nil {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("failed to perform whois search")
|
||||
debug.PrintError(err)
|
||||
if !whoisHistory && !whoisSubdomainScan {
|
||||
// Domain lookup
|
||||
result, err := w.WhoisSearch(whoisDomain)
|
||||
if err != nil {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("failed to perform whois search")
|
||||
debug.PrintError(err)
|
||||
}
|
||||
zap.L().Error("whois_search",
|
||||
zap.String("message", "failed to perform whois search"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing WHOIS lookup: %v\n", err)
|
||||
return
|
||||
}
|
||||
zap.L().Error("whois_search",
|
||||
zap.String("message", "failed to perform whois search"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing WHOIS lookup: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if whoisShowCredits {
|
||||
checkBalance(w)
|
||||
}
|
||||
|
||||
// Fix the output format to use proper formatting
|
||||
fmt.Println("WHOIS Lookup Result:")
|
||||
|
||||
// Store the record
|
||||
err = sqlite.StoreWhoisRecord(result)
|
||||
if err != nil {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("failed to store whois record")
|
||||
debug.PrintError(err)
|
||||
if whoisShowCredits {
|
||||
checkBalance(w)
|
||||
}
|
||||
zap.L().Error("store_whois_record",
|
||||
zap.String("message", "failed to store whois record"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error storing WHOIS record: %v\n", err)
|
||||
// Continue execution even if storage fails
|
||||
}
|
||||
|
||||
// Pretty Print WhoIs Record
|
||||
pretty.WhoIsTree(whoisDomain, result)
|
||||
// Fix the output format to use proper formatting
|
||||
fmt.Println("WHOIS Lookup Result:")
|
||||
|
||||
// Write WhoIs Record to file
|
||||
if len(result.DomainName) != 0 {
|
||||
fmt.Printf("[*] Writing WHOIS record to file: %s%s\n", whoisOutputFile, fType.Extension())
|
||||
err = export.WriteWhoIsRecordToFile(result, whoisOutputFile, fType)
|
||||
} else {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("no whois record to write to file")
|
||||
// Store the record
|
||||
err = sqlite.StoreWhoisRecord(result)
|
||||
if err != nil {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("failed to store whois record")
|
||||
debug.PrintError(err)
|
||||
}
|
||||
zap.L().Error("store_whois_record",
|
||||
zap.String("message", "failed to store whois record"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error storing WHOIS record: %v\n", err)
|
||||
// Continue execution even if storage fails
|
||||
}
|
||||
|
||||
// Pretty Print WhoIs Record
|
||||
pretty.WhoIsTree(whoisDomain, result)
|
||||
|
||||
// Write WhoIs Record to file
|
||||
if len(result.DomainName) != 0 {
|
||||
fmt.Printf("[*] Writing WHOIS record to file: %s%s\n", whoisOutputFile, fType.Extension())
|
||||
err = export.WriteWhoIsRecordToFile(result, whoisOutputFile, fType)
|
||||
} else {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("no whois record to write to file")
|
||||
}
|
||||
zap.L().Info("write_whois_record",
|
||||
zap.String("message", "no whois record to write to file"),
|
||||
)
|
||||
}
|
||||
zap.L().Info("write_whois_record",
|
||||
zap.String("message", "no whois record to write to file"),
|
||||
)
|
||||
}
|
||||
|
||||
if whoisHistory {
|
||||
@@ -253,7 +255,6 @@ var (
|
||||
)
|
||||
fmt.Printf("Error performing subdomain scan: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("Subdomain Scan:")
|
||||
err = sqlite.StoreWhoisSubdomainRecords(subdomains)
|
||||
if err != nil {
|
||||
if debugGlobal {
|
||||
@@ -290,6 +291,7 @@ var (
|
||||
}
|
||||
|
||||
// Store the subdomains
|
||||
fmt.Println("Subdomain Scan:")
|
||||
pretty.Table(headers, rows)
|
||||
|
||||
} else {
|
||||
@@ -492,6 +494,12 @@ var (
|
||||
}
|
||||
|
||||
if whoisInclude != "" || whoisExclude != "" {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("performing reverse whois")
|
||||
debug.PrintInfo("include: " + whoisInclude)
|
||||
debug.PrintInfo("exclude: " + whoisExclude)
|
||||
debug.PrintInfo("reverse type: " + whoisReverseType)
|
||||
}
|
||||
// Reverse WHOIS
|
||||
includeTerms := []string{}
|
||||
if whoisInclude != "" {
|
||||
@@ -511,17 +519,10 @@ var (
|
||||
}
|
||||
}
|
||||
|
||||
if whoisReverseType == "" {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("reverse type not specified, using default")
|
||||
}
|
||||
whoisReverseType = "current"
|
||||
} else {
|
||||
toLower := strings.ToLower(whoisReverseType)
|
||||
if toLower != "current" && toLower != "historic" {
|
||||
fmt.Println("[!] Error: Invalid reverse type. Must be 'current' or 'historic'.")
|
||||
return
|
||||
}
|
||||
toLower := strings.ToLower(whoisReverseType)
|
||||
if toLower != "current" && toLower != "historic" {
|
||||
fmt.Println("[!] Error: Invalid reverse type. Must be 'current' or 'historic'.")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("[*] Performing reverse WHOIS lookup...")
|
||||
@@ -538,8 +539,42 @@ var (
|
||||
fmt.Printf("Error performing reverse WHOIS: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Reverse WHOIS Result:")
|
||||
fmt.Println(result)
|
||||
|
||||
// Write to file
|
||||
if len(result.DomainsList) > 0 {
|
||||
fmt.Printf("[*] Writing reverse WHOIS results to file: %s%s\n", whoisOutputFile, fType.Extension())
|
||||
err = export.WriteIStringToFile(result, whoisOutputFile, fType)
|
||||
if err != nil {
|
||||
if debugGlobal {
|
||||
debug.PrintInfo("failed to write reverse whois to file")
|
||||
debug.PrintError(err)
|
||||
}
|
||||
zap.L().Error("write_reverse_whois",
|
||||
zap.String("message", "failed to write reverse whois to file"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error writing reverse WHOIS to file: %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Println("Reverse WHOIS Result:")
|
||||
fmt.Printf("Total Domains: %d\n", result.DomainsCount)
|
||||
|
||||
var (
|
||||
headers = []string{"Domain"}
|
||||
rows [][]string
|
||||
)
|
||||
|
||||
for _, r := range result.DomainsList {
|
||||
rows = append(rows, []string{r})
|
||||
}
|
||||
|
||||
pretty.Table(headers, rows)
|
||||
} else {
|
||||
fmt.Println("[!] No results found")
|
||||
zap.L().Info("reverse_whois",
|
||||
zap.String("message", "no results found"),
|
||||
)
|
||||
}
|
||||
|
||||
if whoisShowCredits {
|
||||
checkBalance(w)
|
||||
|
||||
@@ -166,7 +166,11 @@ func (dcv2 *DehashedClientV2) Search(searchRequest DehashedSearchRequest) (int,
|
||||
zap.String("message", "preparing search request"),
|
||||
)
|
||||
}
|
||||
reqBody, _ := json.Marshal(searchRequest)
|
||||
|
||||
// Create a copy of the search request to avoid modifying the original
|
||||
requestCopy := searchRequest
|
||||
|
||||
reqBody, _ := json.Marshal(requestCopy)
|
||||
|
||||
if dcv2.debug {
|
||||
j := string(reqBody)
|
||||
|
||||
@@ -3,11 +3,12 @@ package dehashed
|
||||
import (
|
||||
"crowsnest/internal/debug"
|
||||
"crowsnest/internal/export"
|
||||
"crowsnest/internal/pretty"
|
||||
"crowsnest/internal/sqlite"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Dehasher is a struct for querying the Dehashed API
|
||||
@@ -208,12 +209,10 @@ func (dh *Dehasher) buildRequest() {
|
||||
|
||||
// parseResults parses the results and writes them to a file
|
||||
func (dh *Dehasher) parseResults() {
|
||||
var data []byte
|
||||
|
||||
zap.L().Info("extracting_credentials")
|
||||
results := dh.client.GetResults()
|
||||
creds := results.ExtractCredentials()
|
||||
fmt.Printf("\n\t[+] Discovered %d Credentials", len(creds))
|
||||
fmt.Printf(" [+] Discovered %d Credentials\n", len(creds))
|
||||
err := sqlite.StoreDehashedCreds(creds)
|
||||
if err != nil {
|
||||
zap.L().Error("store_creds",
|
||||
@@ -234,28 +233,93 @@ func (dh *Dehasher) parseResults() {
|
||||
zap.L().Info("results_stored", zap.Int("count", len(results.Results)))
|
||||
|
||||
if len(results.Results) > 0 {
|
||||
fmt.Printf("\n\t[*] Writing entries to file: %s.%s", dh.options.OutputFile, dh.options.OutputFormat.String())
|
||||
var (
|
||||
headers = []string{"Email", "Username", "Password"}
|
||||
rows [][]string
|
||||
)
|
||||
|
||||
fmt.Printf(" [*] Writing entries to file: %s.%s\n", dh.options.OutputFile, dh.options.OutputFormat.String())
|
||||
if !dh.options.CredsOnly {
|
||||
err := export.WriteToFile(results, dh.options.OutputFile, dh.options.OutputFormat)
|
||||
if err != nil {
|
||||
fmt.Printf("\n[!] Error Writing to file: %v\n\tOutputting to terminal.", err)
|
||||
data, err = json.MarshalIndent(results, "", " ")
|
||||
fmt.Println(string(data))
|
||||
os.Exit(0)
|
||||
fmt.Printf("[!] Error Writing to file: %v Outputting to terminal.\n", err)
|
||||
zap.L().Error("write_results",
|
||||
zap.String("message", "failed to write results to file"),
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
fmt.Println("\n\t\t[*] Success\n")
|
||||
fmt.Println(" [*] Success")
|
||||
}
|
||||
|
||||
if dh.debug {
|
||||
debug.PrintInfo("printing results table")
|
||||
}
|
||||
|
||||
headers = []string{"Name", "Email", "Username", "Password", "Address", "Phone", "Social", "Crypto Address", "Company"}
|
||||
if len(results.Results) > 50 {
|
||||
fmt.Println(" [-] Large number of results recovered, displaying first 50...")
|
||||
for i := 0; i < 50; i++ {
|
||||
r := results.Results[i]
|
||||
rows = append(rows, []string{
|
||||
strings.Join(r.Name, ", "), strings.Join(r.Email, ", "),
|
||||
strings.Join(r.Username, ", "), strings.Join(r.Password, ", "),
|
||||
strings.Join(r.Address, ", "), strings.Join(r.Phone, ", "),
|
||||
strings.Join(r.Social, ", "), strings.Join(r.CryptoCurrencyAddress, ", "),
|
||||
strings.Join(r.Company, ", ")})
|
||||
}
|
||||
} else {
|
||||
for _, r := range results.Results {
|
||||
rows = append(rows, []string{
|
||||
strings.Join(r.Name, ", "), strings.Join(r.Email, ", "),
|
||||
strings.Join(r.Username, ", "), strings.Join(r.Password, ", "),
|
||||
strings.Join(r.Address, ", "), strings.Join(r.Phone, ", "),
|
||||
strings.Join(r.Social, ", "), strings.Join(r.CryptoCurrencyAddress, ", "),
|
||||
strings.Join(r.Company, ", ")})
|
||||
}
|
||||
}
|
||||
|
||||
// Print Table
|
||||
pretty.Table(headers, rows)
|
||||
} else {
|
||||
if dh.debug {
|
||||
debug.PrintInfo("extracting credentials")
|
||||
}
|
||||
creds := results.ExtractCredentials()
|
||||
if dh.debug {
|
||||
debug.PrintInfo("writing credentials to file")
|
||||
}
|
||||
err := export.WriteCredsToFile(creds, dh.options.OutputFile, dh.options.OutputFormat)
|
||||
if err != nil {
|
||||
fmt.Printf("\n[!] Error Writing to file: %v\n\tOutputting to terminal.", err)
|
||||
data, err = json.MarshalIndent(creds, "", " ")
|
||||
fmt.Println(string(data))
|
||||
os.Exit(0)
|
||||
fmt.Printf("[!] Error Writing to file: %v\n Outputting to terminal.", err)
|
||||
zap.L().Error("write_creds",
|
||||
zap.String("message", "failed to write creds to file"),
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
fmt.Println("\n\t\t[*] Success\n")
|
||||
fmt.Println(" [*] Success")
|
||||
}
|
||||
|
||||
if dh.debug {
|
||||
debug.PrintInfo("printing credentials table")
|
||||
}
|
||||
|
||||
headers = []string{"Email", "Username", "Password"}
|
||||
if len(creds) > 50 {
|
||||
fmt.Println(" [-] Large number of results recovered, displaying first 50...")
|
||||
for i := 0; i < 50; i++ {
|
||||
c := creds[i]
|
||||
rows = append(rows, []string{c.Email, c.Username, c.Password})
|
||||
}
|
||||
} else {
|
||||
for _, c := range creds {
|
||||
rows = append(rows, []string{c.Email, c.Username, c.Password})
|
||||
}
|
||||
}
|
||||
|
||||
// Print Table
|
||||
pretty.Table(headers, rows)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(" [-] No results found")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,3 +628,20 @@ func StoreWhoisLookup(lookup []LookupResult) error {
|
||||
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// ReverseWhoisResponse represents the response from a reverse WHOIS lookup
|
||||
type ReverseWhoisResponse struct {
|
||||
RemainingCredits int `json:"remaining_credits"`
|
||||
Data ReverseWhoisData `json:"data"`
|
||||
}
|
||||
|
||||
// ReverseWhoisData contains the domain count and list from a reverse WHOIS lookup
|
||||
type ReverseWhoisData struct {
|
||||
DomainsCount int `json:"domainsCount"`
|
||||
DomainsList []string `json:"domainsList"`
|
||||
NextPageSearchAfter *string `json:"nextPageSearchAfter"`
|
||||
}
|
||||
|
||||
func (rwd ReverseWhoisData) String() string {
|
||||
return fmt.Sprintf("Domains Count: %d\nDomains List: %v\nNext Page Search After: %v\n", rwd.DomainsCount, rwd.DomainsList, rwd.NextPageSearchAfter)
|
||||
}
|
||||
|
||||
+32
-7
@@ -298,7 +298,9 @@ func (w *DehashedWhoIs) WhoisHistory(domain string) ([]sqlite.HistoryRecord, err
|
||||
return whois.Data.Records, nil
|
||||
}
|
||||
|
||||
func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverseType string) (string, error) {
|
||||
func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverseType string) (sqlite.ReverseWhoisData, error) {
|
||||
var whois sqlite.ReverseWhoisData
|
||||
|
||||
if w.debug {
|
||||
debug.PrintInfo("performing reverse whois search")
|
||||
zap.L().Info("reverse_whois_debug",
|
||||
@@ -329,7 +331,7 @@ func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverse
|
||||
zap.String("message", "failed to create request"),
|
||||
zap.Error(err),
|
||||
)
|
||||
return "", err
|
||||
return whois, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
@@ -356,7 +358,7 @@ func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverse
|
||||
zap.String("message", "failed to perform request"),
|
||||
zap.Error(err),
|
||||
)
|
||||
return "", err
|
||||
return whois, err
|
||||
}
|
||||
if res == nil {
|
||||
if w.debug {
|
||||
@@ -365,7 +367,7 @@ func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverse
|
||||
zap.L().Error("reverse_whois",
|
||||
zap.String("message", "response was nil"),
|
||||
)
|
||||
return "", errors.New("response was nil")
|
||||
return whois, errors.New("response was nil")
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(res.Body)
|
||||
@@ -378,7 +380,7 @@ func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverse
|
||||
zap.String("message", "failed to read response body"),
|
||||
zap.Error(err),
|
||||
)
|
||||
return "", err
|
||||
return whois, err
|
||||
}
|
||||
|
||||
// Check for HTTP status code errors
|
||||
@@ -396,7 +398,7 @@ func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverse
|
||||
zap.String("error", dhErr.Error()),
|
||||
zap.String("body_error", string(b)),
|
||||
)
|
||||
return "", &dhErr
|
||||
return whois, &dhErr
|
||||
}
|
||||
|
||||
if w.debug {
|
||||
@@ -404,7 +406,30 @@ func (w *DehashedWhoIs) ReverseWHOIS(include []string, exclude []string, reverse
|
||||
debug.PrintJson(fmt.Sprintf("Body: %s\n", string(b[:])))
|
||||
}
|
||||
|
||||
return string(b), nil
|
||||
var whoisResponse sqlite.ReverseWhoisResponse
|
||||
err = json.Unmarshal(b, &whoisResponse)
|
||||
if err != nil {
|
||||
if w.debug {
|
||||
debug.PrintInfo("failed to unmarshal response body")
|
||||
debug.PrintError(err)
|
||||
}
|
||||
zap.L().Error("reverse_whois",
|
||||
zap.String("message", "failed to unmarshal response body"),
|
||||
zap.Error(err),
|
||||
)
|
||||
return whois, err
|
||||
}
|
||||
|
||||
if w.debug {
|
||||
debug.PrintInfo("unmarshalled response body")
|
||||
debug.PrintJson(fmt.Sprintf("Remaining Credits: %d\n", whoisResponse.RemainingCredits))
|
||||
debug.PrintJson(fmt.Sprintf("Data: %v\n", whoisResponse.Data))
|
||||
}
|
||||
w.balance = whoisResponse.RemainingCredits
|
||||
|
||||
whois = whoisResponse.Data
|
||||
|
||||
return whois, nil
|
||||
}
|
||||
|
||||
func (w *DehashedWhoIs) WhoisIP(ipAddress string) ([]sqlite.LookupResult, error) {
|
||||
|
||||
Reference in New Issue
Block a user