diff --git a/internal/shodan/alert/clear.go b/internal/shodan/alert/clear.go index ae91f8d..4a01583 100644 --- a/internal/shodan/alert/clear.go +++ b/internal/shodan/alert/clear.go @@ -3,36 +3,48 @@ package alert import ( "context" "fmt" + "strings" "git.tcp.direct/perp/shogo/internal/utils" ) // Clear all alerts -func Clear() { +func (a *Alert) Clear() { // Get results results, err := utils.Client.GetAlerts(context.Background()) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - utils.Title.Println("Clearing alerts...") + // Store lines + var lines string + + // Add lines + lines += utils.Title.Sprintln("Clearing alerts...") for index := range results { // Set results result, err := utils.Client.DeleteAlert(context.Background(), results[index].ID) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results + // Add lines if result { - fmt.Printf("%s: %s\n", utils.Green("Deleted alert"), utils.Blue(results[index].ID)) + lines += fmt.Sprintf( + "%s: %s\n", + utils.Green("Deleted alert"), + utils.Blue(results[index].ID), + ) } else { - fmt.Printf("%s: %s\n", utils.Red("Error"), "failed deleting an alert") + lines += fmt.Sprintf("%s: %s\n", utils.Red("Error"), "failed deleting an alert") } } -} -// Todo: Make this threaded + // Remove empty newline + lines = strings.TrimRight(lines, "\n") + // Send results + a.Results <- lines +} diff --git a/internal/shodan/alert/create.go b/internal/shodan/alert/create.go index d1c2c1b..a5f0b44 100644 --- a/internal/shodan/alert/create.go +++ b/internal/shodan/alert/create.go @@ -8,17 +8,23 @@ import ( ) // Create an alert -func Create(name, ip string) { - host := []string{ip} +func (a *Alert) Create() { + host := []string{a.IP} // Get results - results, err := utils.Client.CreateAlert(context.Background(), name, host, 0) + results, err := utils.Client.CreateAlert(context.Background(), a.Name, host, 0) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Println("Successfully created alert!") - fmt.Printf("%s: %s\n", utils.Green("Alert ID"), utils.Blue(results.ID)) + // Store lines + var lines string + + // Add lines + lines += utils.Title.Sprintln("Successfully created alert!") + lines += fmt.Sprintf("%s: %s", utils.Green("Alert ID"), utils.Blue(results.ID)) + + // Send result + a.Results <- lines } diff --git a/internal/shodan/alert/delete.go b/internal/shodan/alert/delete.go index 33a2d14..4e69e69 100644 --- a/internal/shodan/alert/delete.go +++ b/internal/shodan/alert/delete.go @@ -8,18 +8,18 @@ import ( ) // Delete an alert -func Delete(id string) { +func (a *Alert) Delete() { // Set results - results, err := utils.Client.DeleteAlert(context.Background(), id) + results, err := utils.Client.DeleteAlert(context.Background(), a.ID) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results + // Send result if results { - utils.Title.Println("Successfully deleted alert!") + a.Results <- utils.Title.Sprintf("Successfully deleted alert!") } else { - fmt.Printf("%s: %s\n", utils.Red("Error"), "alert does not exist") + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), "alert does not exist") } } diff --git a/internal/shodan/alert/info.go b/internal/shodan/alert/info.go index 68f1c9e..194a35a 100644 --- a/internal/shodan/alert/info.go +++ b/internal/shodan/alert/info.go @@ -9,21 +9,27 @@ import ( ) // Return alert information -func Info(id string) { +func (a *Alert) Info() { // Get results - results, err := utils.Client.GetAlert(context.Background(), id) + results, err := utils.Client.GetAlert(context.Background(), a.ID) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Printf("Alert %s\n", id) - fmt.Printf("%s: %s\n", utils.Green("Name"), utils.Blue(results.Name)) - fmt.Printf( + // Store lines + var lines string + + // Add lines + lines += utils.Title.Sprintf("Alert %s\n", a.ID) + lines += fmt.Sprintf("%s: %s\n", utils.Green("Name"), utils.Blue(results.Name)) + lines += fmt.Sprintf( "%s: %s\n", utils.Blue("Network"), utils.Green(strings.Join(results.Filters.IP, ",")), ) - fmt.Printf("%s: %s\n", utils.Green("Created"), utils.Blue(results.Created)) + lines += fmt.Sprintf("%s: %s", utils.Green("Created"), utils.Blue(results.Created)) + + // Send results + a.Results <- lines } diff --git a/internal/shodan/alert/list.go b/internal/shodan/alert/list.go index b993255..27ad764 100644 --- a/internal/shodan/alert/list.go +++ b/internal/shodan/alert/list.go @@ -9,23 +9,31 @@ import ( ) // Return all the active alerts -func List() { +func (a *Alert) List() { // Get results results, err := utils.Client.GetAlerts(context.Background()) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + a.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Printf("%s%13s%28s\n", "Alert ID", "Name", "IP/Network") + // Store lines + var lines string + + // Add lines + lines += utils.Title.Sprintf("%s%13s%28s\n", "Alert ID", "Name", "IP/Network") for index := range results { - fmt.Printf( + lines += fmt.Sprintf( "%-14s %-24s %24s\n", utils.Green(results[index].ID), utils.Blue(results[index].Name), utils.Green(strings.Join(results[index].Filters.IP, ",")), ) } + + // Remove empty newline + // Send results + lines = strings.TrimRight(lines, "\n") + a.Results <- lines } diff --git a/internal/shodan/count.go b/internal/shodan/count.go index 4e51b58..8c85903 100644 --- a/internal/shodan/count.go +++ b/internal/shodan/count.go @@ -3,7 +3,6 @@ package shodan import ( "context" "fmt" - "os" "github.com/ns3777k/go-shodan/v4/shodan" @@ -11,20 +10,19 @@ import ( ) // Return your query result count -func Count(query string) { +func (s *Shodan) Count() { // Setup query options := &shodan.HostQueryOptions{ - Query: query, + Query: s.Flags.Query, } // Get results results, err := utils.Client.GetHostsCountForQuery(context.Background(), options) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) - os.Exit(1) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) + return } - // Print results - utils.Title.Printf("Count: %s\n", query) - fmt.Printf("%s\n", utils.Blue(results.Total)) + // Send result + s.Results <- utils.Title.Sprintf("Count: %s\n", s.Flags.Query) + fmt.Sprintf("%s", utils.Blue(results.Total)) } diff --git a/internal/shodan/domain.go b/internal/shodan/domain.go index 034c9cc..86527a5 100644 --- a/internal/shodan/domain.go +++ b/internal/shodan/domain.go @@ -3,41 +3,27 @@ package shodan import ( "context" "fmt" - "net" - - "github.com/ns3777k/go-shodan/v4/shodan" "git.tcp.direct/perp/shogo/internal/utils" ) // Return domain information -func Domain(host string) { - // Parse IP - ips, err := net.LookupIP(host) - if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) - return - } - +func Domain(domain string) { // Get results - results, err := utils.Client.GetServicesForHost( - context.Background(), - ips[0].To4().String(), - &shodan.HostServicesOptions{}, - ) + results, err := utils.Client.GetDomain(context.Background(), domain) if err != nil { fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) return } // Print results - utils.Title.Printf("Domain: %s", host) + utils.Title.Printf("Domain: %s", domain) fmt.Printf("\n\n") for index := range results.Data { - fmt.Println(results.Data[index].Domains) + fmt.Println(results.Data[index]) } } -// Todo: Find domain records +// Todo: Find domain records, add padding, add to pool diff --git a/internal/shodan/host.go b/internal/shodan/host.go index 5fd9361..1cd284c 100644 --- a/internal/shodan/host.go +++ b/internal/shodan/host.go @@ -11,49 +11,53 @@ import ( ) // Return host information -func Host(ip string) { +func (s *Shodan) Host() { // Get results results, err := utils.Client.GetServicesForHost( context.Background(), - ip, + s.Flags.Query, &shodan.HostServicesOptions{}, ) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Printf("Host: %s\n", ip) - fmt.Printf( + // Alternate between colors + var alternate bool + // Store lines + var lines string + // Store port/protocol/service + var port string + + // Add lines + lines += utils.Title.Sprintf("Host: %s\n", s.Flags.Query) + lines += fmt.Sprintf( "%s: %s\n", utils.Green("Hostnames"), utils.Blue(strings.Join(results.Hostnames, ",")), ) - fmt.Printf("%s: %s\n", utils.Blue("Organization"), utils.Green(results.Organization)) - fmt.Printf("%s: %s\n", utils.Green("Country"), utils.Blue(results.Country)) - fmt.Printf("%s: %s\n", utils.Blue("City"), utils.Green(results.City)) - fmt.Printf("%s: %s\n", utils.Green("Updated"), utils.Blue(results.LastUpdate)) - fmt.Printf("%s: %s\n", utils.Blue("Port count"), utils.Green(len(results.Ports))) - fmt.Printf("\n%s:\n", utils.Green("Ports")) - - // Color alternator & current line - var alternate bool - var line string + lines += fmt.Sprintf("%s: %s\n", utils.Blue("Organization"), utils.Green(results.Organization)) + lines += fmt.Sprintf("%s: %s\n", utils.Green("Country"), utils.Blue(results.Country)) + lines += fmt.Sprintf("%s: %s\n", utils.Blue("City"), utils.Green(results.City)) + lines += fmt.Sprintf("%s: %s\n", utils.Green("Updated"), utils.Blue(results.LastUpdate)) + lines += fmt.Sprintf("%s: %s\n", utils.Blue("Port count"), utils.Green(len(results.Ports))) + lines += fmt.Sprintf("\n%s:\n", utils.Green("Ports")) + // Go through data for index := range results.Data { // Alternate between colors - // Find each port & transport + // Find port & transport if alternate { alternate = false - line = fmt.Sprintf( + port = fmt.Sprintf( "\t%s/%s", utils.Blue(results.Data[index].Port), utils.Green(results.Data[index].Transport), ) } else if !alternate { alternate = true - line = fmt.Sprintf( + port = fmt.Sprintf( "\t%s/%s", utils.Green(results.Data[index].Port), utils.Blue(results.Data[index].Transport), @@ -63,13 +67,17 @@ func Host(ip string) { // Find each product if results.Data[index].Product != "" { if alternate { - line = fmt.Sprintf("%s (%s)", line, utils.Green(results.Data[index].Product)) + port = fmt.Sprintf("%s (%s)", port, utils.Green(results.Data[index].Product)) } else if !alternate { - line = fmt.Sprintf("%s (%s)", line, utils.Blue(results.Data[index].Product)) + port = fmt.Sprintf("%s (%s)", port, utils.Blue(results.Data[index].Product)) } } - // Print results - fmt.Println(line) + lines += port + "\n" } + + // Remove empty newline + // Send results + lines = strings.TrimRight(lines, "\n") + s.Results <- lines } diff --git a/internal/shodan/info.go b/internal/shodan/info.go index 74037b3..320aa51 100644 --- a/internal/shodan/info.go +++ b/internal/shodan/info.go @@ -8,34 +8,37 @@ import ( ) // Return your account information -func Info(profile_enabled bool) { +func (s *Shodan) Info() { // Fetch API information results, err := utils.Client.GetAPIInfo(context.Background()) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Println("API") - fmt.Printf("%s: %s\n", utils.Green("Plan"), utils.Blue(results.Plan)) - fmt.Printf("%s: %s\n", utils.Blue("Query credits"), utils.Green(results.QueryCredits)) - fmt.Printf("%s: %s\n", utils.Green("Scan credits"), utils.Blue(results.ScanCredits)) - fmt.Printf("%s: %s\n", utils.Blue("Telnet"), utils.Green(results.Telnet)) - fmt.Printf("%s: %s\n", utils.Green("HTTPS"), utils.Blue(results.HTTPS)) - fmt.Printf("%s: %s\n", utils.Blue("Unlocked"), utils.Green(results.Unlocked)) + // Store lines + var lines string + // Store profile name + var name string - // Fetch profile information - if profile_enabled { + // Add lines + lines += utils.Title.Sprintln("API") + lines += fmt.Sprintf("%s: %s\n", utils.Green("Plan"), utils.Blue(results.Plan)) + lines += fmt.Sprintf("%s: %s\n", utils.Blue("Query credits"), utils.Green(results.QueryCredits)) + lines += fmt.Sprintf("%s: %s\n", utils.Green("Scan credits"), utils.Blue(results.ScanCredits)) + lines += fmt.Sprintf("%s: %s\n", utils.Blue("Telnet"), utils.Green(results.Telnet)) + lines += fmt.Sprintf("%s: %s\n", utils.Green("HTTPS"), utils.Blue(results.HTTPS)) + lines += fmt.Sprintf("%s: %s", utils.Blue("Unlocked"), utils.Green(results.Unlocked)) + + // Profile enabled + if s.Flags.Profile { + // Fetch profile information results, err := utils.Client.GetAccountProfile(context.Background()) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Profile name - var name string - // Empty name if results.Name == "" { name = "?" @@ -43,13 +46,18 @@ func Info(profile_enabled bool) { name = results.Name } - // Print results - fmt.Println("") + // Add lines + lines += "\n\n" + lines += utils.Title.Sprintln("Profile") + lines += fmt.Sprintf("%s: %s\n", utils.Green("Name"), utils.Blue(name)) + lines += fmt.Sprintf("%s: %s\n", utils.Blue("Member"), utils.Green(results.Member)) + lines += fmt.Sprintf("%s: %s\n", utils.Green("Credits"), utils.Blue(results.Credits)) + lines += fmt.Sprintf("%s: %s", utils.Blue("Created"), utils.Green(results.Created)) - utils.Title.Println("Profile") - fmt.Printf("%s: %s\n", utils.Green("Name"), utils.Blue(name)) - fmt.Printf("%s: %s\n", utils.Blue("Member"), utils.Green(results.Member)) - fmt.Printf("%s: %s\n", utils.Green("Credits"), utils.Blue(results.Credits)) - fmt.Printf("%s: %s\n", utils.Blue("Created"), utils.Green(results.Created)) + // Send results + s.Results <- lines } + + // Send results + s.Results <- lines } diff --git a/internal/shodan/myip.go b/internal/shodan/myip.go index 53b59a0..fdece2f 100644 --- a/internal/shodan/myip.go +++ b/internal/shodan/myip.go @@ -8,14 +8,14 @@ import ( ) // Return your IP address -func MyIp() { +func (s *Shodan) MyIp() { // Fetch IP address results, err := utils.Client.GetMyIP(context.Background()) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - fmt.Printf("%s\n", utils.Blue(results.String())) + // Send line + s.Results <- fmt.Sprintf("%s", utils.Blue(results.String())) } diff --git a/internal/shodan/scan/internet.go b/internal/shodan/scan/internet.go index 115e987..11d8e93 100644 --- a/internal/shodan/scan/internet.go +++ b/internal/shodan/scan/internet.go @@ -9,18 +9,21 @@ import ( ) // Submit an internet scan -func Internet(port int, protocol string) { +func (s *Scan) Internet() { // Get results - results, err := utils.Client.ScanInternet(context.Background(), port, protocol) + results, err := utils.Client.ScanInternet(context.Background(), s.Port, s.Protocol) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Printf("Scanning internet for %d %s\n", port, protocol) + // Store lines + var lines string - fmt.Printf("%s: %s\n", utils.Green("ID"), utils.Blue(results)) + // Print results + lines += utils.Title.Sprintf("Scanning internet for %d %s\n", s.Port, s.Protocol) + + lines += fmt.Sprintf("%s: %s\n", utils.Green("ID"), utils.Blue(results)) for { time.Sleep(time.Second * 3) @@ -28,14 +31,15 @@ func Internet(port int, protocol string) { // Get results results, err := utils.Client.GetScanStatus(context.Background(), results) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s\n", utils.Red("Error"), err.Error()) return } // Get status switch results.Status { case "DONE": - fmt.Printf("%s: %s\n", utils.Blue("Status"), utils.Green(results.Status)) + lines += fmt.Sprintf("%s: %s", utils.Blue("Status"), utils.Green(results.Status)) + s.Results <- lines return } } diff --git a/internal/shodan/scan/protocols.go b/internal/shodan/scan/protocols.go index 37ef1bf..a801318 100644 --- a/internal/shodan/scan/protocols.go +++ b/internal/shodan/scan/protocols.go @@ -3,23 +3,32 @@ package scan import ( "context" "fmt" + "strings" "git.tcp.direct/perp/shogo/internal/utils" ) // Return protocols to scan -func Protocols() { +func (s *Scan) Protocols() { // Get results results, err := utils.Client.GetProtocols(context.Background()) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Println("Protocols") + // Store liens + var lines string + + // Add lines + lines += utils.Title.Sprintln("Protocols") for key, value := range results { - fmt.Printf("%-36s %s\n", utils.Green(key), utils.Blue(value)) + lines += fmt.Sprintf("%-36s %s\n", utils.Green(key), utils.Blue(value)) } + + // Remove empty newline + lines = strings.TrimRight(lines, "\n") + // Send results + s.Results <- lines } diff --git a/internal/shodan/scan/submit.go b/internal/shodan/scan/submit.go index a56f4eb..c858b38 100644 --- a/internal/shodan/scan/submit.go +++ b/internal/shodan/scan/submit.go @@ -9,18 +9,21 @@ import ( ) // Submit a scan -func Submit(ips []string) { +func (s *Scan) Submit() { // Get results - results, err := utils.Client.Scan(context.Background(), ips) + results, err := utils.Client.Scan(context.Background(), s.IPs) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - utils.Title.Printf("Starting scan for %s\n", ips) + // Store lines + var lines string - fmt.Printf( + // Add lines + lines += utils.Title.Sprintf("Starting scan for %s\n", s.IPs) + + lines += fmt.Sprintf( "%s: %s\n%s: %s\n%s: %s\n", utils.Green("ID"), utils.Blue(results.ID), @@ -36,14 +39,15 @@ func Submit(ips []string) { // Get results results, err := utils.Client.GetScanStatus(context.Background(), results.ID) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } // Get status switch results.Status { case "DONE": - fmt.Printf("%s: %s\n", utils.Blue("Status"), utils.Green(results.Status)) + lines += fmt.Sprintf("%s: %s", utils.Blue("Status"), utils.Green(results.Status)) + s.Results <- lines return } } diff --git a/internal/shodan/stats.go b/internal/shodan/stats.go index d74bde5..055236a 100644 --- a/internal/shodan/stats.go +++ b/internal/shodan/stats.go @@ -3,6 +3,7 @@ package shodan import ( "context" "fmt" + "strings" "github.com/ns3777k/go-shodan/v4/shodan" @@ -17,27 +18,52 @@ type Stats struct { } // Return facet stats on a search -func (s *Stats) Stats() { +func (s *Shodan) Stats() { // Setup options options := &shodan.HostQueryOptions{ - Query: s.Query, - Facets: "US", - Page: s.Page, + Query: s.Flags.Query, + Facets: s.Flags.Facets, + Page: 1, } // Get results results, err := utils.Client.GetHostsForQuery(context.Background(), options) if err != nil { - fmt.Printf("%s: %s\n", utils.Red("Error"), err.Error()) - s.Results <- "" + s.Results <- fmt.Sprintf("%s: %s", utils.Red("Error"), err.Error()) return } - // Print results - for host := range results.Matches { - fmt.Println(results.Matches[host]) - } - s.Results <- "" -} + // Store lines + var lines string -// Todo: Fix this + // Split facets + splitted := strings.Split(s.Flags.Facets, ",") + + // Go through splitted + for split := range splitted { + // Get facet & count + facet := strings.Split(splitted[split], ":") + + // Add lines + lines += utils.Title.Sprintf( + "\nTop %s results for %s query with %s facet\n", + facet[1], + s.Flags.Query, + facet[0], + ) + + for index := range results.Facets[facet[0]] { + lines += fmt.Sprintf( + "%s: %s\n", + utils.Green(results.Facets[facet[0]][index].Value), + utils.Blue(results.Facets[facet[0]][index].Count), + ) + } + } + + // Remove empty newline(s) + // Send results + lines = strings.Replace(lines, "\n", "", 1) + lines = strings.TrimRight(lines, "\n") + s.Results <- lines +}