forked from zmap/zgrab2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscanner.go
202 lines (175 loc) · 5.26 KB
/
scanner.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
// Package banner provides simple banner grab and matching implementation of the zgrab2.Module.
// It sends a customizble probe (default to "\n") and filters the results based on custom regexp (--pattern)
package banner
import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"regexp"
"strconv"
"encoding/hex"
"github.com/zmap/zgrab2"
)
// Flags give the command-line flags for the banner module.
type Flags struct {
zgrab2.BaseFlags
Probe string `long:"probe" default:"\\n" description:"Probe to send to the server. Use triple slashes to escape, for example \\\\\\n is literal \\n. Mutually exclusive with --probe-file" `
ProbeFile string `long:"probe-file" description:"Read probe from file as byte array (hex). Mutually exclusive with --probe"`
Pattern string `long:"pattern" description:"Pattern to match, must be valid regexp."`
UseTLS bool `long:"tls" description:"Sends probe with TLS connection. Loads TLS module command options. "`
MaxTries int `long:"max-tries" default:"1" description:"Number of tries for timeouts and connection errors before giving up. Includes making TLS connection if enabled."`
Hex bool `long:"hex" description:"Store banner value in hex. "`
zgrab2.TLSFlags
}
// Module is the implementation of the zgrab2.Module interface.
type Module struct {
}
// Scanner is the implementation of the zgrab2.Scanner interface.
type Scanner struct {
config *Flags
regex *regexp.Regexp
probe []byte
}
// ScanResults instances are returned by the module's Scan function.
type Results struct {
Banner string `json:"banner,omitempty"`
Length int `json:"length,omitempty"`
TLSLog *zgrab2.TLSLog `json:"tls,omitempty"`
}
// RegisterModule is called by modules/banner.go to register the scanner.
func RegisterModule() {
var module Module
_, err := zgrab2.AddCommand("banner", "Banner", module.Description(), 80, &module)
if err != nil {
log.Fatal(err)
}
}
// NewFlags returns a new default flags object.
func (m *Module) NewFlags() interface{} {
return new(Flags)
}
// GetName returns the Scanner name defined in the Flags.
func (scanner *Scanner) GetName() string {
return scanner.config.Name
}
// GetTrigger returns the Trigger defined in the Flags.
func (scanner *Scanner) GetTrigger() string {
return scanner.config.Trigger
}
// Protocol returns the protocol identifier of the scan.
func (scanner *Scanner) Protocol() string {
return "banner"
}
// InitPerSender initializes the scanner for a given sender.
func (scanner *Scanner) InitPerSender(senderID int) error {
return nil
}
// NewScanner returns a new Scanner object.
func (m *Module) NewScanner() zgrab2.Scanner {
return new(Scanner)
}
// Validate validates the flags and returns nil on success.
func (f *Flags) Validate(args []string) error {
if f.Probe != "\\n" && f.ProbeFile != "" {
log.Fatal("Cannot set both --probe and --probe-file")
return zgrab2.ErrInvalidArguments
}
return nil
}
// Description returns an overview of this module.
func (module *Module) Description() string {
return "Fetch a raw banner by sending a static probe and checking the result against a regular expression"
}
// Help returns the module's help string.
func (f *Flags) Help() string {
return ""
}
// Init initializes the Scanner with the command-line flags.
func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
var err error
f, _ := flags.(*Flags)
scanner.config = f
scanner.regex = regexp.MustCompile(scanner.config.Pattern)
if len(f.ProbeFile) != 0 {
scanner.probe, err = ioutil.ReadFile(f.ProbeFile)
if err != nil {
log.Fatal("Failed to open probe file")
return zgrab2.ErrInvalidArguments
}
} else {
strProbe, err := strconv.Unquote(fmt.Sprintf(`"%s"`, scanner.config.Probe))
if err != nil {
panic("Probe error")
}
scanner.probe = []byte(strProbe)
}
return nil
}
var NoMatchError = errors.New("pattern did not match")
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) {
try := 0
var (
conn net.Conn
tlsConn *zgrab2.TLSConnection
err error
readerr error
)
for try < scanner.config.MaxTries {
try++
conn, err = target.Open(&scanner.config.BaseFlags)
if err != nil {
continue
}
if scanner.config.UseTLS {
tlsConn, err = scanner.config.TLSFlags.GetTLSConnection(conn)
if err != nil {
continue
}
if err = tlsConn.Handshake(); err != nil {
continue
}
conn = tlsConn
}
break
}
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, err
}
defer conn.Close()
var ret []byte
try = 0
for try < scanner.config.MaxTries {
try++
_, err = conn.Write(scanner.probe)
ret, readerr = zgrab2.ReadAvailable(conn)
if err != nil {
continue
}
if readerr != io.EOF && readerr != nil {
continue
}
break
}
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, err
}
if readerr != io.EOF && readerr != nil {
return zgrab2.TryGetScanStatus(readerr), nil, readerr
}
var results Results
if scanner.config.Hex {
results = Results{Banner: hex.EncodeToString(ret), Length: len(ret)}
} else {
results = Results{Banner: string(ret), Length: len(ret)}
}
if tlsConn != nil {
results.TLSLog = tlsConn.GetLog()
}
if scanner.regex.Match(ret) {
return zgrab2.SCAN_SUCCESS, &results, nil
}
return zgrab2.SCAN_PROTOCOL_ERROR, &results, NoMatchError
}