-
Notifications
You must be signed in to change notification settings - Fork 0
/
runzero-jsonl.go
110 lines (91 loc) · 2.6 KB
/
runzero-jsonl.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
package main
import (
"bufio"
"fmt"
"io"
"log"
"net/http"
"os"
"strconv"
"strings"
"github.com/buger/jsonparser"
"github.com/vulncheck-oss/go-exploit/db"
)
func validateHTTPData(httpData string) bool {
resp, err := http.ReadResponse(bufio.NewReader(strings.NewReader(httpData)), nil)
if err != nil {
// don't cache this, it's an incomplete payload due to (presumably) a limit
// runzero has in their data
return false
}
defer resp.Body.Close()
_, err = io.ReadAll(resp.Body)
return err == nil
}
// we need to extract:
// 1. service.address
// 2. service.port
// 3. http.uri
// 4. banner
// 5. http.body
// 6. http.head.contentLength.
func parseRunZeroJSON(line string) {
services, _, _, _ := jsonparser.Get([]byte(line), "services")
_ = jsonparser.ObjectEach(services, func(_ []byte, serviceEntry []byte, _ jsonparser.ValueType, _ int) error {
httpCode, err := jsonparser.GetString(serviceEntry, "http.code")
if err != nil || len(httpCode) == 0 {
return nil
}
portString, _ := jsonparser.GetString(serviceEntry, "service.port")
port, err := strconv.Atoi(portString)
if err != nil {
return nil
}
contentLength := 0
contentLengthStr, err := jsonparser.GetString(serviceEntry, "http.head.contentLength")
if err == nil && len(contentLengthStr) != 0 {
contentLength, _ = strconv.Atoi(contentLengthStr)
}
ipStr, _ := jsonparser.GetString(serviceEntry, "service.address")
uri, _ := jsonparser.GetString(serviceEntry, "http.uri")
banner, _ := jsonparser.GetString(serviceEntry, "banner")
// The banner isn't limited to the HTTP header, so we need to yeet out the extra data
headerEnd := strings.Index(banner, "\r\n\r\n")
if headerEnd != -1 {
banner = banner[:headerEnd]
}
body, _ := jsonparser.GetString(serviceEntry, "http.body")
// RunZero seems to trim trailing \n? Check if there is an off by 1 error and add the on char back in
if contentLength != 0 && (contentLength-1) == len(body) {
body += "\n"
}
httpData := banner + "\r\n\r\n" + body
if validateHTTPData(httpData) {
db.CacheHTTPResponse(ipStr, port, uri, []byte(httpData))
}
return nil
})
}
func DoRunZeroJSONL(jsonFile string) bool {
log.Println("Generating database entries...")
file, err := os.Open(jsonFile)
if err != nil {
fmt.Printf("Failed to open file: %v\n", err)
return false
}
defer file.Close()
reader := bufio.NewReader(file)
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
}
parseRunZeroJSON(line)
}
return true
}