Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New functionality for zgrab2-banner: md5, sha1, sha256, base64 #385

Merged
merged 8 commits into from
Feb 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}