Skip to content

Commit

Permalink
Added JARM fingerprinting module (#282)
Browse files Browse the repository at this point in the history
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
silascutler and Silas Cutler authored Jun 7, 2021
1 parent daaf631 commit 9a23e80
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 0 deletions.
7 changes: 7 additions & 0 deletions modules/jarm.go
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()
}
153 changes: 153 additions & 0 deletions modules/jarm/scanner.go
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
}

0 comments on commit 9a23e80

Please sign in to comment.