2023-08-01 22:35:47 +00:00
|
|
|
package shodan
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ns3777k/go-shodan/v4/shodan"
|
|
|
|
|
|
|
|
"git.tcp.direct/perp/shogo/internal/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Search query
|
|
|
|
type Search struct {
|
|
|
|
Query string // Search query
|
|
|
|
Page int // Current page
|
|
|
|
Fields []string // Filter fields
|
|
|
|
Separator string // Filter separator
|
|
|
|
Results chan string // Results channel
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return shodan search results
|
|
|
|
func (s *Search) Search() {
|
|
|
|
// Setup options
|
|
|
|
options := &shodan.HostQueryOptions{
|
|
|
|
Query: s.Query,
|
|
|
|
Page: s.Page,
|
|
|
|
Minify: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// More than 2 matches
|
|
|
|
if len(results.Matches) > 2 {
|
|
|
|
// Go through matches
|
|
|
|
for match := range results.Matches {
|
|
|
|
if len(s.Fields) != 0 {
|
|
|
|
fields := map[string]string{
|
|
|
|
"product": results.Matches[match].Product,
|
|
|
|
"ip_str": results.Matches[match].IP.String(),
|
|
|
|
"org": results.Matches[match].Organization,
|
|
|
|
"isp": results.Matches[match].ISP,
|
|
|
|
"transport": results.Matches[match].Transport,
|
|
|
|
"data": results.Matches[match].Data,
|
|
|
|
"asn": results.Matches[match].ASN,
|
|
|
|
"port": strconv.Itoa(results.Matches[match].Port),
|
|
|
|
"timestamp": results.Matches[match].Timestamp,
|
|
|
|
"os": results.Matches[match].OS,
|
|
|
|
}
|
|
|
|
|
|
|
|
var result string
|
|
|
|
var content string
|
|
|
|
|
|
|
|
// Go through custom fields
|
|
|
|
for key, value := range fields {
|
|
|
|
// Go through real fields
|
|
|
|
for index := range s.Fields {
|
|
|
|
// Real field matched custom field
|
|
|
|
if s.Fields[index] == key {
|
|
|
|
// Port may go on the wrong side
|
|
|
|
if key == "port" {
|
|
|
|
content += value
|
|
|
|
} else {
|
|
|
|
content += value + s.Separator
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lines := strings.Split(content, "\n")
|
|
|
|
for line := range lines {
|
|
|
|
result += strings.TrimRight(lines[line], ":")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print results
|
|
|
|
fmt.Println(result)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Send results
|
|
|
|
content := fmt.Sprintf("%s: %s\n%s: %s\n%s: %s\n",
|
|
|
|
utils.Green("IP"), utils.Blue(results.Matches[match].IP.String()),
|
|
|
|
utils.Blue("Port"), utils.Green(results.Matches[match].Port),
|
|
|
|
utils.Green("Hostname"), utils.Blue(strings.Join(results.Matches[0].Hostnames, ",")),
|
|
|
|
)
|
|
|
|
|
|
|
|
lines := strings.Split(results.Matches[match].Data, "\n")
|
|
|
|
green := true
|
|
|
|
for line := range lines {
|
|
|
|
values := strings.Split(lines[line], ":")
|
|
|
|
if green {
|
|
|
|
content += fmt.Sprintf("%s:%s\n", utils.Green(values[0]), utils.Blue(strings.Join(values[1:], "")))
|
|
|
|
green = false
|
|
|
|
} else {
|
|
|
|
content += fmt.Sprintf("%s:%s\n", utils.Blue(values[0]), utils.Green(strings.Join(values[1:], "")))
|
|
|
|
green = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Results <- content
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-02 04:10:59 +00:00
|
|
|
// Todo: Redo filter sorting
|