-
Notifications
You must be signed in to change notification settings - Fork 371
Expand file tree
/
Copy pathscanner.go
More file actions
104 lines (86 loc) · 2.98 KB
/
Copy pathscanner.go
File metadata and controls
104 lines (86 loc) · 2.98 KB
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
// Ref: https://github.com/salesforce/jarm
// https://engineering.salesforce.com/easily-identify-malicious-servers-on-the-internet-with-jarm-e095edac525a?gi=4dd05e2277e4
package jarm
import (
"context"
"errors"
"fmt"
"net"
"strings"
"time"
"github.com/hdm/jarm-go"
"github.com/zmap/zgrab2"
)
// Flags give the command-line flags for the jarm module.
type Flags struct {
zgrab2.BaseFlags `group:"Basic Options"`
MaxTries int `long:"max-tries" default:"1" description:"Number of tries for timeouts and connection errors before giving up."`
}
// Module is the implementation of the zgrab2.Module interface.
func NewModule() *zgrab2.TypedModule[Flags, Scanner, *Scanner] {
return zgrab2.NewTypedModule[Flags, Scanner, *Scanner]("jarm", "TLS server fingerprinting (JARM)", "Send TLS requests and generate a JARM fingerprint", 443)
}
// Scanner is the implementation of the zgrab2.Scanner interface.
type Scanner struct {
zgrab2.BaseScanner
config *Flags
}
type Results struct {
Fingerprint string `json:"fingerprint"`
}
// GetPort returns the port being scanned.
func (scanner *Scanner) GetPort() uint {
return scanner.config.Port
}
// Init initializes the Scanner with the command-line flags.
func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
f, _ := flags.(*Flags)
scanner.config = f
scanner.SetBaseFlags(&f.BaseFlags)
scanner.DialerGroupConfig = &zgrab2.DialerGroupConfig{
TransportAgnosticDialerProtocol: zgrab2.TransportTCP,
BaseFlags: &f.BaseFlags,
}
return nil
}
func (scanner *Scanner) Scan(ctx context.Context, dialGroup *zgrab2.DialerGroup, target *zgrab2.ScanTarget) (zgrab2.ScanStatus, any, error) {
// Stores raw hashes returned from parsing each protocols Hello message
rawhashes := []string{}
// Loop through each Probe type
for _, probe := range jarm.GetProbes(target.Host(), int(scanner.GetPort())) {
if zgrab2.HasCtxExpired(ctx) {
return zgrab2.SCAN_IO_TIMEOUT, nil, errors.New("scan timed out")
}
var (
conn net.Conn
err error
ret []byte
)
conn, err = dialGroup.Dial(ctx, target)
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, fmt.Errorf("could not dial target %s: %w", target.String(), err)
}
_, err = conn.Write(jarm.BuildProbe(probe))
if err != nil {
rawhashes = append(rawhashes, "")
zgrab2.CloseConnAndHandleError(conn)
continue
}
ret, _ = zgrab2.ReadAvailableWithOptions(conn, 1484, 500*time.Millisecond, 0, 1484)
ans, err := jarm.ParseServerHello(ret, probe)
if err != nil {
rawhashes = append(rawhashes, "")
zgrab2.CloseConnAndHandleError(conn)
continue
}
rawhashes = append(rawhashes, ans)
zgrab2.CloseConnAndHandleError(conn)
}
var fingerprint = jarm.RawHashToFuzzyHash(strings.Join(rawhashes, ","))
if fingerprint == "00000000000000000000000000000000000000000000000000000000000000" {
return zgrab2.SCAN_APPLICATION_ERROR, nil, errors.New("unable to calculate hashes from server")
}
return zgrab2.SCAN_SUCCESS, &Results{
Fingerprint: fingerprint,
}, nil
}