-
Notifications
You must be signed in to change notification settings - Fork 71
/
shodan.go
230 lines (192 loc) · 7.28 KB
/
shodan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
package main
import (
"fmt" // printing
"gopkg.in/ns3777k/go-shodan.v1/shodan" // shodan api
"github.com/PuerkitoBio/goquery"
"log"
"os" // os commands
"bufio" //input output
"strconv"
)
func bugcrowd() []string{
doc, err := goquery.NewDocument("https://www.bugcrowd.com/bug-bounty-list/") //link to bugcrowd list
if err != nil { // if cant connect
log.Fatal(err)
}
s := make([]string, 455 ) //slice of strings
doc.Find("td a").Each(func(index int, item *goquery.Selection) { //for every organization in "td a" (table)
linkTag := item.Text() // get text
s[index] = linkTag //put in to map
})
return s // return slice of organizations
}
func intro() (){
fmt.Println("Search multiple organization with Shodan.")
fmt.Println("Prepare txt file with organizations names")
fmt.Println("and pass it to script as argument")
fmt.Println("----------------------------------------")
fmt.Println("Example")
fmt.Println("Hosts.txt includes:")
fmt.Println("Sony")
fmt.Println("Facebook")
fmt.Println("Dropbox")
fmt.Println("---------------------------------------")
fmt.Println("Run ./shodan hosts.txt")
fmt.Println("As output script makes directory with organization's name")
fmt.Println("and writes response as txt file")
fmt.Println("/Sony")
fmt.Println("---xxx.xxx.xxx.xxx")
fmt.Println("---xxx.xxx.xxx.xxx")
fmt.Println("/Facebook")
fmt.Println("---xxx.xxx.xxx.xxx")
fmt.Println("---xxx.xxx.xxx.xxx")
}
func in_array(val int, array []int) (ok bool, i int) { //https://codereview.stackexchange.com/questions/60074/in-array-in-go
for i = range array {
if ok = array[i] == val; ok {
return
}
}
return
}
func func_unique(input []string) []string { //https://kylewbanks.com/blog/creating-unique-slices-in-go
u := make([]string, 0, len(input))
m := make(map[string]bool)
for _, val := range input {
if _, ok := m[val]; !ok {
m[val] = true
u = append(u, val)
}
}
return u
}
func read_file(input string) (orgs_string []string) { // https://stackoverflow.com/questions/8757389/reading-file-line-by-line-in-go
//var orgs_string [400]string
file, err := os.Open(input)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
//fmt.Println(scanner.Text())
orgs_string = append(orgs_string, scanner.Text())
}
if err := scanner.Err(); err != nil {
intro()
os.Exit(1)
}
return orgs_string
}
/* function for infinite loop in user input; when user type 111 - exit from loop
it gets slice of strings (uniique) and return index and breaking point*/
func loop(query []string) (breaking bool, index int) {
index = 0
breaking = false
var input int
fmt.Scan(&input) // get input
if input == 111 {
breaking = true
return breaking, index // return false (do not exit from main loop), return index = 0
}else{
index = input
breaking = false
return breaking, index
}
return breaking, index
}
/*Printing loop, gets slice of unique organizations and map{org:value of appaerances}
Needs for counting results */
func print_loop(orgs []string, counter map[string]int) {
for index, value :=range orgs{
fmt.Println(index,"-------->", value, "-", counter[value], "results for that organization") //get value from counter for every organizations in unique
}
fmt.Println("Type 111 to go to next organization")
}
func main() {
if len(os.Args) == 1 {
intro()
os.Exit(1)
}
argsWithoutProg := os.Args[1]
// multiple ports query, dont need to check if port is in array
ports := "port:'80, 81, 443, 8000, 8001, 8008, 8080, 8083, 8443, 8834, 8888'"
// ports := []int{80, 81, 443, 591, 2082, 2095, 2096, 3000, 8000, 8001, 8008, 8080, 8083, 8443, 8834, 8888, 55672}
orgquery := read_file(argsWithoutProg) //
client := shodan.NewClient(nil, "YOUR_API_KEY") //") //connect with shodan
//fmt.Println(client.GetAPIInfo()) //Api info
for i:= range orgquery{ // for every item in slice
organtion_query := "org:" + orgquery[i] + " " + ports //make string "org: Company ports: ....."
fmt.Println("Query:", organtion_query) // print query
a := &shodan.HostQueryOptions{Query:organtion_query} //first query "org: Company port: ....."
query, err := client.GetHostsForQuery(a) /*get host from previous query and return
type HostMatch struct {
Total int `json:"total"`
Facets map[string][]*Facet `json:"facets"`
Matches []*HostData `json:"matches"` }*/
fmt.Println("Error:", err) //print error
fmt.Println("Founded: ", query.Total, "total result(s)") // print amount of results for everything
if query.Total == 0 { // debugging
fmt.Println("Nothing was found. Going to next one\n")
continue
}
organization := make([]string, len(query.Matches)) //slice for organizations
for i:= range query.Matches { //for every match in query
organization[i] = query.Matches[i].Organization //get organization
// now organization is [Company1, Company2 ...] with repetives
}
unique := func_unique(organization) // get uniqie from organization
counts := make(map[string]int) //map for counting orgs
for _, helperorg := range organization{ // for every value in organization
counts[helperorg]++ // add to map and ++
}
fmt.Println("Organizations:")
//print_loop(unique)
print_loop(unique, counts)
i = 0
// starbuck. sony
for{ // for {} means infinite loop
breaking_point, index := loop(unique) //
if breaking_point == false {
if index >= len(unique){
fmt.Println("Wrong choice, try again")
print_loop(unique, counts)
continue
}
fmt.Println("Company: ", unique[index]) // print founded organizations
uniquery := "org:'" + string(unique[index]) + "' " + ports // make query for next request {org: i from unique organizations}
fmt.Println("Query:", uniquery)
c := &shodan.HostQueryOptions{Query:uniquery} // connect and query
query1, _ := client.GetHostsForQuery(c) // make request
//fmt.Println(query1.Total)
//fmt.Println(query1.Total) // print total results from unique organizations for EVERY COMPANY!!
for j:= range query1.Matches{ // for every matches from query1
path := unique[index] + "/" + query1.Matches[j].IP // company/111.111.111.111
fmt.Println("Making file in ", path)
os.Mkdir(unique[index], os.FileMode(0666)) // make directory with
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666) // read and write for everyone
w := bufio.NewWriter(f) // make new writer
s := strconv.Itoa(query1.Matches[j].Port)
fmt.Fprintf(w, "Port:")
fmt.Fprintf(w, s)
fmt.Fprintf(w, "\n")
//fmt.Fprintf(w, "\n")
if len(query1.Matches[j].Hostnames) > 0 { //if there is hostname related to match
for a:= range query1.Matches[j].Hostnames{ // for every founded hostname
fmt.Fprintln(w, query1.Matches[j].Hostnames[a]) //add to file
//fmt.Fprintf(w, "\n")
}
}
fmt.Fprintf(w, query1.Matches[j].Data) //save data (http response) to new writer
w.Flush() // flussssssssssssssh
i++
}
fmt.Println("\n")
print_loop(unique, counts)
}else{
break
}
}
}
}