Skip to content

Commit

Permalink
New functionality for zgrab2-banner: md5, sha1, sha256, base64 (#385)
Browse files Browse the repository at this point in the history
* refactor a little

* add base64

* add md5,sha1,sha25

* fix typo

* add data size check

* check empty regexp

* refactor a little
  • Loading branch information
crazylazyowl authored Feb 18, 2024
1 parent 2858073 commit ec3a192
Showing 1 changed file with 79 additions and 46 deletions.
125 changes: 79 additions & 46 deletions modules/banner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
package banner

import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
Expand All @@ -12,20 +17,23 @@ import (
"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"`
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. "`
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. "`
Hex bool `long:"hex" description:"Store banner value in hex. Mutually exclusive with --base64."`
Base64 bool `long:"base64" description:"Store banner value in base64. Mutually exclusive with --hex."`
MD5 bool `long:"md5" description:"Calculate MD5 hash of banner value."`
SHA1 bool `long:"sha1" description:"Calculate SHA1 hash of banner value."`
SHA256 bool `long:"sha256" description:"Calculate SHA256 hash of banner value."`
zgrab2.TLSFlags
}

Expand All @@ -44,12 +52,17 @@ type Scanner struct {
type Results struct {
Banner string `json:"banner,omitempty"`
Length int `json:"length,omitempty"`
MD5 string `json:"md5,omitempty"`
SHA1 string `json:"sha1,omitempty"`
SHA256 string `json:"sha25,omitempty"`
}

var NoMatchError = errors.New("pattern did not match")

// 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)
var m Module
_, err := zgrab2.AddCommand("banner", "Banner", m.Description(), 80, &m)
if err != nil {
log.Fatal(err)
}
Expand All @@ -61,22 +74,22 @@ func (m *Module) NewFlags() interface{} {
}

// GetName returns the Scanner name defined in the Flags.
func (scanner *Scanner) GetName() string {
return scanner.config.Name
func (s *Scanner) GetName() string {
return s.config.Name
}

// GetTrigger returns the Trigger defined in the Flags.
func (scanner *Scanner) GetTrigger() string {
return scanner.config.Trigger
func (s *Scanner) GetTrigger() string {
return s.config.Trigger
}

// Protocol returns the protocol identifier of the scan.
func (scanner *Scanner) Protocol() string {
func (s *Scanner) Protocol() string {
return "banner"
}

// InitPerSender initializes the scanner for a given sender.
func (scanner *Scanner) InitPerSender(senderID int) error {
func (s *Scanner) InitPerSender(senderID int) error {
return nil
}

Expand All @@ -95,7 +108,7 @@ func (f *Flags) Validate(args []string) error {
}

// Description returns an overview of this module.
func (module *Module) Description() string {
func (m *Module) Description() string {
return "Fetch a raw banner by sending a static probe and checking the result against a regular expression"
}

Expand All @@ -105,46 +118,44 @@ func (f *Flags) Help() string {
}

// Init initializes the Scanner with the command-line flags.
func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
func (s *Scanner) Init(flags zgrab2.ScanFlags) error {
var err error
f, _ := flags.(*Flags)
scanner.config = f
scanner.regex = regexp.MustCompile(scanner.config.Pattern)
s.config = f
if s.config.Pattern != "" {
s.regex = regexp.MustCompile(s.config.Pattern)
}
if len(f.ProbeFile) != 0 {
scanner.probe, err = ioutil.ReadFile(f.ProbeFile)
s.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))
strProbe, err := strconv.Unquote(fmt.Sprintf(`"%s"`, s.config.Probe))
if err != nil {
panic("Probe error")
}
scanner.probe = []byte(strProbe)
s.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
func (s *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) {
var (
conn net.Conn
tlsConn *zgrab2.TLSConnection
err error
readerr error
readErr error
)
for try < scanner.config.MaxTries {
try++
conn, err = target.Open(&scanner.config.BaseFlags)

for try := 0; try < s.config.MaxTries; try++ {
conn, err = target.Open(&s.config.BaseFlags)
if err != nil {
continue
}
if scanner.config.UseTLS {
tlsConn, err = scanner.config.TLSFlags.GetTLSConnection(conn)
if s.config.UseTLS {
tlsConn, err = s.config.TLSFlags.GetTLSConnection(conn)
if err != nil {
continue
}
Expand All @@ -153,44 +164,66 @@ func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, inter
}
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)
var data []byte

for try := 0; try < s.config.MaxTries; try++ {
_, err = conn.Write(s.probe)
data, readErr = zgrab2.ReadAvailable(conn)
if err != nil {
continue
}
if readerr != io.EOF && readerr != nil {
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
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)}

if s.config.Hex {
results.Banner = hex.EncodeToString(data)
} else if s.config.Base64 {
results.Banner = base64.StdEncoding.EncodeToString(data)
} else {
results = Results{Banner: string(ret), Length: len(ret)}
results.Banner = string(data)
}
results.Length = len(data)

if len(data) > 0 {
if s.config.MD5 {
digest := md5.Sum(data)
results.MD5 = hex.EncodeToString(digest[:])
}
if s.config.SHA1 {
digest := sha1.Sum(data)
results.SHA1 = hex.EncodeToString(digest[:])
}
if s.config.SHA256 {
digest := sha256.Sum256(data)
results.SHA256 = hex.EncodeToString(digest[:])
}
}
if scanner.regex.Match(ret) {

if s.regex == nil {
return zgrab2.SCAN_SUCCESS, &results, nil
}

return zgrab2.SCAN_PROTOCOL_ERROR, &results, NoMatchError
if s.regex.Match(data) {
return zgrab2.SCAN_SUCCESS, &results, nil
}

return zgrab2.SCAN_PROTOCOL_ERROR, &results, NoMatchError
}

0 comments on commit ec3a192

Please sign in to comment.