65c4ea6a15
Added structs for whois calls. Added ability to write WhoIs to file. Added structured output for Whois Records. Added String Method for WhoIsRecord and WhoIsHistory Records.
262 lines
7.8 KiB
Go
262 lines
7.8 KiB
Go
package dehashed
|
|
|
|
import (
|
|
"dehasher/internal/debug"
|
|
"dehasher/internal/export"
|
|
"dehasher/internal/sqlite"
|
|
"encoding/json"
|
|
"fmt"
|
|
"go.uber.org/zap"
|
|
"os"
|
|
)
|
|
|
|
// Dehasher is a struct for querying the Dehashed API
|
|
type Dehasher struct {
|
|
options sqlite.QueryOptions
|
|
nextPage int
|
|
debug bool
|
|
balance int
|
|
request *DehashedSearchRequest
|
|
client *DehashedClientV2
|
|
}
|
|
|
|
// NewDehasher creates a new Dehasher
|
|
func NewDehasher(options *sqlite.QueryOptions) *Dehasher {
|
|
dh := &Dehasher{
|
|
options: *options,
|
|
nextPage: options.StartingPage + 1,
|
|
debug: options.Debug,
|
|
balance: 0,
|
|
}
|
|
dh.setQueries()
|
|
dh.request = NewDehashedSearchRequest(dh.options.StartingPage, dh.options.MaxRecords, dh.options.WildcardMatch, dh.options.RegexMatch, false, options.Debug)
|
|
dh.buildRequest()
|
|
return dh
|
|
}
|
|
|
|
// SetClientCredentials sets the client credentials for the dehasher
|
|
func (dh *Dehasher) SetClientCredentials(key string) {
|
|
dh.client = NewDehashedClientV2(key, dh.debug)
|
|
}
|
|
|
|
func (dh *Dehasher) getNextPage() int {
|
|
if dh.debug {
|
|
debug.PrintInfo(fmt.Sprintf("getting next page: %d", dh.nextPage))
|
|
}
|
|
nextPage := dh.nextPage
|
|
dh.nextPage += 1
|
|
return nextPage
|
|
}
|
|
|
|
// setQueries sets the number of queries to make based on the number of records and requests
|
|
func (dh *Dehasher) setQueries() {
|
|
var numQueries int
|
|
|
|
if dh.debug {
|
|
debug.PrintInfo("setting queries")
|
|
}
|
|
|
|
switch {
|
|
case dh.options.MaxRequests == 0:
|
|
zap.L().Error("max requests cannot be zero")
|
|
fmt.Println("[!] Max Requests cannot be zero")
|
|
os.Exit(1)
|
|
case dh.options.MaxRecords <= 10000 || dh.options.MaxRequests == 1:
|
|
numQueries = 1
|
|
if dh.options.MaxRecords > 10000 {
|
|
dh.options.MaxRecords = 10000
|
|
}
|
|
zap.L().Info("max requests set to 1", zap.Int("max_records", dh.options.MaxRecords))
|
|
case dh.options.MaxRequests < 0 && dh.options.MaxRecords > 20000:
|
|
numQueries = 3
|
|
dh.options.MaxRecords = 10000
|
|
zap.L().Info("max requests set to 3", zap.Int("max_records", dh.options.MaxRecords))
|
|
case dh.options.MaxRequests < 0 && dh.options.MaxRecords > 10000:
|
|
numQueries = 2
|
|
dh.options.MaxRecords = 10000
|
|
zap.L().Info("max requests set to 2", zap.Int("max_records", dh.options.MaxRecords))
|
|
case dh.options.MaxRecords < 0 && dh.options.MaxRecords < 10000:
|
|
numQueries = 1
|
|
zap.L().Info("max requests set to 1", zap.Int("max_records", dh.options.MaxRecords))
|
|
case dh.options.MaxRequests == 2 && dh.options.MaxRecords > 20000:
|
|
numQueries = 2
|
|
dh.options.MaxRecords = 10000
|
|
zap.L().Info("max requests set to 2", zap.Int("max_records", dh.options.MaxRecords))
|
|
case dh.options.MaxRequests == 2 && dh.options.MaxRecords <= 10000:
|
|
numQueries = 1
|
|
zap.L().Info("max requests set to 1", zap.Int("max_records", dh.options.MaxRecords))
|
|
default:
|
|
numQueries = 3
|
|
dh.options.MaxRecords = 10000
|
|
zap.L().Info("max requests set to 3", zap.Int("max_records", dh.options.MaxRecords))
|
|
}
|
|
|
|
dh.options.MaxRequests = numQueries
|
|
|
|
if dh.debug {
|
|
debug.PrintInfo(fmt.Sprintf("setting max requests: %d", numQueries))
|
|
debug.PrintInfo(fmt.Sprintf("setting max records: %d", dh.options.MaxRecords))
|
|
}
|
|
|
|
fmt.Printf("Making %d Requests for %d Records (%d Total)\n", dh.options.MaxRequests, dh.options.MaxRecords, dh.options.MaxRequests*dh.options.MaxRecords)
|
|
}
|
|
|
|
// Start starts the querying process
|
|
func (dh *Dehasher) Start() {
|
|
fmt.Printf("[*] Querying Dehashed API...\n")
|
|
for i := 0; i < dh.options.MaxRequests; i++ {
|
|
fmt.Printf(" [*] Performing Request...\n")
|
|
count, balance, err := dh.client.Search(*dh.request)
|
|
if err != nil {
|
|
if dh.debug {
|
|
debug.PrintInfo("error performing request")
|
|
debug.PrintError(err)
|
|
}
|
|
|
|
// Check if it's a DehashError
|
|
if dhErr, ok := err.(*DehashError); ok {
|
|
fmt.Printf(" [!] Dehashed API Error: %s (Code: %d)\n", dhErr.Message, dhErr.Code)
|
|
zap.L().Error("dehashed_api_error",
|
|
zap.String("message", dhErr.Message),
|
|
zap.Int("code", dhErr.Code),
|
|
)
|
|
} else {
|
|
fmt.Printf(" [!] Error performing request: %v\n", err)
|
|
zap.L().Error("request_error",
|
|
zap.String("message", "failed to perform request"),
|
|
zap.Error(err),
|
|
)
|
|
}
|
|
|
|
if len(dh.client.results) > 0 {
|
|
fmt.Printf(" [!] Partial results retrieved. Storing Results...\n")
|
|
err := sqlite.StoreResults(dh.client.GetResults())
|
|
if err != nil {
|
|
zap.L().Error("store_results",
|
|
zap.String("message", "failed to store results"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf(" [!] Error storing results: %v\n", err)
|
|
}
|
|
}
|
|
dh.parseResults()
|
|
os.Exit(-1)
|
|
}
|
|
|
|
dh.balance = balance
|
|
|
|
if count < dh.options.MaxRecords {
|
|
fmt.Printf(" [+] Retrieved %d records\n", count)
|
|
fmt.Printf(" [-] Not enough entries, ending queries\n")
|
|
break
|
|
} else {
|
|
fmt.Printf(" [+] Retrieved %d records\n", dh.options.MaxRecords)
|
|
}
|
|
|
|
if dh.options.PrintBalance {
|
|
fmt.Printf(" [*] Balance: %d\n", balance)
|
|
}
|
|
|
|
dh.request.Page = dh.getNextPage()
|
|
}
|
|
|
|
dh.parseResults()
|
|
}
|
|
|
|
// buildRequest constructs the query map
|
|
func (dh *Dehasher) buildRequest() {
|
|
if len(dh.options.UsernameQuery) > 0 {
|
|
dh.request.AddUsernameQuery(dh.options.UsernameQuery)
|
|
}
|
|
if len(dh.options.EmailQuery) > 0 {
|
|
dh.request.AddEmailQuery(dh.options.EmailQuery)
|
|
}
|
|
if len(dh.options.IpQuery) > 0 {
|
|
dh.request.AddIpAddressQuery(dh.options.IpQuery)
|
|
}
|
|
if len(dh.options.HashQuery) > 0 {
|
|
dh.request.AddHashedPasswordQuery(dh.options.HashQuery)
|
|
}
|
|
if len(dh.options.PassQuery) > 0 {
|
|
dh.request.AddPasswordQuery(dh.options.PassQuery)
|
|
}
|
|
if len(dh.options.NameQuery) > 0 {
|
|
dh.request.AddNameQuery(dh.options.NameQuery)
|
|
}
|
|
if len(dh.options.DomainQuery) > 0 {
|
|
dh.request.AddDomainQuery(dh.options.DomainQuery)
|
|
}
|
|
if len(dh.options.VinQuery) > 0 {
|
|
dh.request.AddVinQuery(dh.options.VinQuery)
|
|
}
|
|
if len(dh.options.LicensePlateQuery) > 0 {
|
|
dh.request.AddLicensePlateQuery(dh.options.LicensePlateQuery)
|
|
}
|
|
if len(dh.options.AddressQuery) > 0 {
|
|
dh.request.AddAddressQuery(dh.options.AddressQuery)
|
|
}
|
|
if len(dh.options.PhoneQuery) > 0 {
|
|
dh.request.AddPhoneQuery(dh.options.PhoneQuery)
|
|
}
|
|
if len(dh.options.SocialQuery) > 0 {
|
|
dh.request.AddSocialQuery(dh.options.SocialQuery)
|
|
}
|
|
if len(dh.options.CryptoAddressQuery) > 0 {
|
|
dh.request.AddCryptoAddressQuery(dh.options.CryptoAddressQuery)
|
|
}
|
|
}
|
|
|
|
// 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))
|
|
err := sqlite.StoreCreds(creds)
|
|
if err != nil {
|
|
zap.L().Error("store_creds",
|
|
zap.String("message", "failed to store creds"),
|
|
zap.Error(err),
|
|
)
|
|
}
|
|
zap.L().Info("creds_stored", zap.Int("count", len(creds)))
|
|
|
|
zap.L().Info("storing_results")
|
|
err = sqlite.StoreResults(results)
|
|
if err != nil {
|
|
zap.L().Error("store_results",
|
|
zap.String("message", "failed to store results"),
|
|
zap.Error(err),
|
|
)
|
|
}
|
|
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())
|
|
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)
|
|
} else {
|
|
fmt.Println("\n\t\t[*] Success\n")
|
|
}
|
|
} else {
|
|
creds := results.ExtractCredentials()
|
|
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)
|
|
} else {
|
|
fmt.Println("\n\t\t[*] Success\n")
|
|
}
|
|
}
|
|
}
|
|
}
|