-
Notifications
You must be signed in to change notification settings - Fork 0
/
shodan-gzip.go
143 lines (114 loc) · 2.89 KB
/
shodan-gzip.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
package main
import (
"bufio"
"compress/gzip"
"fmt"
"io"
"log"
"os"
"strings"
"github.com/buger/jsonparser"
"github.com/vulncheck-oss/go-exploit/db"
)
// decompress the gzip into a tmp directory: .tmp/shodan.json.
func decompressShodan(shodanGZIP string) bool {
tmpDir := ".tmp"
err := os.Mkdir(tmpDir, 0o755)
if err != nil && !os.IsExist(err) {
log.Printf("Failed to create directory: %v\n", err)
return false
}
inFile, err := os.Open(shodanGZIP)
if err != nil {
log.Printf("Failed to open input file: %v\n", err)
return false
}
defer inFile.Close()
gzipReader, err := gzip.NewReader(inFile)
if err != nil {
log.Printf("Failed to create gzip reader: %v\n", err)
return false
}
defer gzipReader.Close()
outputFile := tmpDir + "/shodan.json"
outFile, err := os.Create(outputFile)
if err != nil {
log.Printf("Failed to create output file: %v\n", err)
return false
}
defer outFile.Close()
_, err = io.Copy(outFile, gzipReader)
if err != nil {
log.Printf("Failed to copy data to output file: %v\n", err)
return false
}
return true
}
// we need to extract:
// 1. ip_str
// 2. port
// 3. data (http headers)
// 4. http.html
//
// return headers+html, ip, port, ok.
func parseShodanJSON(line string) (string, string, int, bool) {
// do html first so we can fail early
html, err := jsonparser.GetString([]byte(line), "http", "html")
if err != nil {
return "", "", 0, false
}
headers, err := jsonparser.GetString([]byte(line), "data")
if err != nil {
return "", "", 0, false
}
// Shodan fixes up the payload so remove transfer encoding: chunked, otherwise
// go deserialization fails
headers = strings.Replace(headers, "Transfer-Encoding: chunked\r\n", "", 1)
ipStr, err := jsonparser.GetString([]byte(line), "ip_str")
if err != nil {
return "", "", 0, false
}
port, err := jsonparser.GetInt([]byte(line), "port")
if err != nil {
return "", "", 0, false
}
return headers + html, ipStr, int(port), true
}
func readShodanJSON(jsonFile string) bool {
file, err := os.Open(jsonFile)
if err != nil {
fmt.Printf("Failed to open file: %v\n", err)
return false
}
defer file.Close()
// Create a new buffered reader
reader := bufio.NewReader(file)
// Read the file line by line
for {
line, err := reader.ReadString('\n')
if err != nil {
if err.Error() == "EOF" {
// End of file reached
break
}
fmt.Printf("Error reading line: %v\n", err)
return false
}
httpData, ip, port, ok := parseShodanJSON(line)
if !ok {
continue
}
db.CacheHTTPResponse(ip, port, "/", []byte(httpData))
}
return true
}
func DoShodanGZIP(inputFile string) bool {
defer os.RemoveAll(".tmp/")
log.Println("Decompressing the Shodan GZIP...")
if !decompressShodan(inputFile) {
return false
}
log.Println("Decompressed file written to .tmp/shodan.json")
log.Println("Generating database entries...")
return readShodanJSON(".tmp/shodan.json")
}