-
Notifications
You must be signed in to change notification settings - Fork 307
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added JARM fingerprinting module (#282)
JARM is an active-fingerprinting technique developed by Salesforce. It was released https://github.com/salesforce/jarm and a write-up on it can be found at: https://engineering.salesforce.com/easily-identify-malicious-servers-on-the-internet-with-jarm-e095edac525a Co-authored-by: Silas Cutler <[email protected]>
- Loading branch information
1 parent
daaf631
commit 9a23e80
Showing
2 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package modules | ||
|
||
import "github.com/zmap/zgrab2/modules/jarm" | ||
|
||
func init() { | ||
jarm.RegisterModule() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// 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 ( | ||
_ "fmt" | ||
jarm "github.com/RumbleDiscovery/jarm-go" | ||
"github.com/zmap/zgrab2" | ||
"io" | ||
"log" | ||
"net" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// Flags give the command-line flags for the banner module. | ||
type Flags struct { | ||
zgrab2.BaseFlags | ||
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. | ||
type Module struct { | ||
} | ||
|
||
// Scanner is the implementation of the zgrab2.Scanner interface. | ||
type Scanner struct { | ||
config *Flags | ||
} | ||
|
||
type Results struct { | ||
Fingerprint string `json:"fingerprint"` | ||
error string `json:"error,omitempty"` | ||
} | ||
|
||
// RegisterModule is called by modules/banner.go to register the scanner. | ||
func RegisterModule() { | ||
var module Module | ||
_, err := zgrab2.AddCommand("jarm", "jarm", module.Description(), 443, &module) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
// NewFlags returns a new default flags object. | ||
func (m *Module) NewFlags() interface{} { | ||
return new(Flags) | ||
} | ||
|
||
// Description returns an overview of this module. | ||
func (module *Module) Description() string { | ||
return "Send TLS requiests and generate a JARM fingerprint" | ||
} | ||
|
||
// GetName returns the Scanner name defined in the Flags. | ||
func (scanner *Scanner) GetName() string { | ||
return scanner.config.Name | ||
} | ||
|
||
// GetPort returns the port being scanned. | ||
func (scanner *Scanner) GetPort() uint { | ||
return scanner.config.Port | ||
} | ||
|
||
// 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 "jarm" | ||
} | ||
|
||
// 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 { | ||
return nil | ||
} | ||
|
||
// 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 { | ||
f, _ := flags.(*Flags) | ||
scanner.config = f | ||
return nil | ||
} | ||
|
||
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) { | ||
// Stores raw hashes returned from parsing each protocols Hello message | ||
rawhashes := []string{} | ||
|
||
// Stores final module results | ||
r := Results{} | ||
|
||
// Loop through each Probe type | ||
for _, probe := range jarm.GetProbes(target.Host(), int(scanner.GetPort())) { | ||
data := jarm.BuildProbe(probe) | ||
|
||
var ( | ||
conn net.Conn | ||
err error | ||
ret []byte | ||
) | ||
conn, err = target.Open(&scanner.config.BaseFlags) | ||
if err != nil { | ||
return zgrab2.TryGetScanStatus(err), nil, err | ||
} | ||
|
||
_, err = conn.Write([]byte(data)) | ||
if err != nil { | ||
rawhashes = append(rawhashes, "") | ||
conn.Close() | ||
continue | ||
} | ||
|
||
// ret, err = zgrab2.ReadAvailable(conn) | ||
ret, err = zgrab2.ReadAvailableWithOptions(conn, 1484, 500*time.Millisecond, 0, 1484) | ||
if err != io.EOF && err != nil { | ||
rawhashes = append(rawhashes, "") | ||
conn.Close() | ||
continue | ||
} | ||
|
||
ans, err := jarm.ParseServerHello(ret, probe) | ||
if err != nil { | ||
rawhashes = append(rawhashes, "") | ||
conn.Close() | ||
continue | ||
} | ||
|
||
rawhashes = append(rawhashes, string(ans)) | ||
conn.Close() | ||
|
||
} | ||
|
||
fprint := jarm.RawHashToFuzzyHash(strings.Join(rawhashes, ",")) | ||
r.Fingerprint = string(fprint) | ||
return zgrab2.SCAN_SUCCESS, &r, nil | ||
} |