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

Merge back into master #2

Merged
merged 13 commits into from
Dec 4, 2020
5 changes: 5 additions & 0 deletions lib/http/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ type Response struct {
Body io.ReadCloser `json:"-"`
BodyText string `json:"body,omitempty"`
BodySHA256 PageFingerprint `json:"body_sha256,omitempty"`
// BodyHash is the hash digest hex of the decoded http body, formatted `<kind>:<hex>`
// e.g. `sha256:deadbeef100020003000400050006000700080009000a000b000c000d000e000`
BodyHash string `json:"body_hash,omitempty"`
// Number of bytes read from the server and encoded into BodyText
BodyTextLength int64 `json:"body_length,omitempty"`

// ContentLength records the length of the associated content. The
// value -1 indicates that the length is unknown. Unless Request.Method
Expand Down
2 changes: 1 addition & 1 deletion modules/ftp/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type Scanner struct {
type Connection struct {
// buffer is a temporary buffer for sending commands -- so, never interleave
// sendCommand calls on a given connection
buffer [1024]byte
buffer [10000]byte
config *Flags
results ScanResults
conn net.Conn
Expand Down
59 changes: 50 additions & 9 deletions modules/http/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ package http
import (
"bytes"
"context"
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"net"
"net/url"
Expand Down Expand Up @@ -60,6 +63,13 @@ type Flags struct {
RedirectsSucceed bool `long:"redirects-succeed" description:"Redirects are always a success, even if max-redirects is exceeded"`

OverrideSH bool `long:"override-sig-hash" description:"Override the default SignatureAndHashes TLS option with more expansive default"`

// ComputeDecodedBodyHashAlgorithm enables computing the body hash later than the default,
// using the specified algorithm, allowing a user of the response to recompute a matching hash
ComputeDecodedBodyHashAlgorithm string `long:"compute-decoded-body-hash-algorithm" choice:"sha256" choice:"sha1" description:"Choose algorithm for BodyHash field"`

// WithBodyLength enables adding the body_size field to the Response
WithBodyLength bool `long:"with-body-size" description:"Enable the body_size attribute, for how many bytes actually read"`
}

// A Results object is returned by the HTTP module's Scanner.Scan()
Expand All @@ -79,7 +89,8 @@ type Module struct {

// Scanner is the implementation of the zgrab2.Scanner interface.
type Scanner struct {
config *Flags
config *Flags
decodedHashFn func([]byte) string
}

// scan holds the state for a single scan. This may entail multiple connections.
Expand Down Expand Up @@ -129,6 +140,21 @@ func (s *Scanner) Protocol() string {
func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
fl, _ := flags.(*Flags)
scanner.config = fl

if fl.ComputeDecodedBodyHashAlgorithm == "sha1" {
scanner.decodedHashFn = func(body []byte) string {
raw_hash := sha1.Sum(body)
return fmt.Sprintf("sha1:%s", hex.EncodeToString(raw_hash[:]))
}
} else if fl.ComputeDecodedBodyHashAlgorithm == "sha256" {
scanner.decodedHashFn = func(body []byte) string {
raw_hash := sha256.Sum256(body)
return fmt.Sprintf("sha256:%s", hex.EncodeToString(raw_hash[:]))
}
} else if fl.ComputeDecodedBodyHashAlgorithm != "" {
log.Panicf("Invalid ComputeDecodedBodyHashAlgorithm choice made it through zflags: %s", scanner.config.ComputeDecodedBodyHashAlgorithm)
}

return nil
}

Expand Down Expand Up @@ -280,12 +306,19 @@ func (scan *scan) getCheckRedirect() func(*http.Request, *http.Response, []*http
if res.ContentLength >= 0 && res.ContentLength < maxReadLen {
readLen = res.ContentLength
}
io.CopyN(b, res.Body, readLen)
bytesRead, _ := io.CopyN(b, res.Body, readLen)
if scan.scanner.config.WithBodyLength {
res.BodyTextLength = bytesRead
}
res.BodyText = b.String()
if len(res.BodyText) > 0 {
m := sha256.New()
m.Write(b.Bytes())
res.BodySHA256 = m.Sum(nil)
if scan.scanner.decodedHashFn != nil {
res.BodyHash = scan.scanner.decodedHashFn([]byte(res.BodyText))
} else {
m := sha256.New()
m.Write(b.Bytes())
res.BodySHA256 = m.Sum(nil)
}
}

if len(via) > scan.scanner.config.MaxRedirects {
Expand Down Expand Up @@ -392,7 +425,11 @@ func (scan *scan) Grab() *zgrab2.ScanError {
if resp.ContentLength >= 0 && resp.ContentLength < maxReadLen {
readLen = resp.ContentLength
}
io.CopyN(buf, resp.Body, readLen)
// EOF ignored here because that's the way it was, CopyN goes up to readLen bytes
bytesRead, _ := io.CopyN(buf, resp.Body, readLen)
if scan.scanner.config.WithBodyLength {
scan.results.Response.BodyTextLength = bytesRead
}
bufAsString := buf.String()

// do best effort attempt to determine the response's encoding
Expand All @@ -410,9 +447,13 @@ func (scan *scan) Grab() *zgrab2.ScanError {
}

if len(scan.results.Response.BodyText) > 0 {
m := sha256.New()
m.Write(buf.Bytes())
scan.results.Response.BodySHA256 = m.Sum(nil)
if scan.scanner.decodedHashFn != nil {
scan.results.Response.BodyHash = scan.scanner.decodedHashFn([]byte(scan.results.Response.BodyText))
} else {
m := sha256.New()
m.Write(buf.Bytes())
scan.results.Response.BodySHA256 = m.Sum(nil)
}
}

return nil
Expand Down
7 changes: 6 additions & 1 deletion modules/telnet/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
type Flags struct {
zgrab2.BaseFlags
MaxReadSize int `long:"max-read-size" description:"Set the maximum number of bytes to read when grabbing the banner" default:"65536"`
Banner bool `long:"force-banner" description:"Always return banner if it has non-zero bytes"`
Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
}

Expand Down Expand Up @@ -105,7 +106,11 @@ func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, inter
defer conn.Close()
result := new(TelnetLog)
if err := GetTelnetBanner(result, conn, scanner.config.MaxReadSize); err != nil {
return zgrab2.TryGetScanStatus(err), result.getResult(), err
if scanner.config.Banner && len(result.Banner) > 0 {
return zgrab2.TryGetScanStatus(err), result, err
} else {
return zgrab2.TryGetScanStatus(err), result.getResult(), err
}
}
return zgrab2.SCAN_SUCCESS, result, nil
}