Cleans up TODOs and includes more results to collect from scans.

This commit is contained in:
Clayton Zimmerman 2018-06-12 09:27:45 -04:00
parent e46f988d28
commit ffaeeab0f1
3 changed files with 55 additions and 36 deletions

@ -42,6 +42,7 @@ func attributeByteString(syntaxTag byte, name string, value string) []byte {
return b return b
} }
//TODO: Dynamically create nothing except uri?
//Construct a minimal request that an IPP server will respond to //Construct a minimal request that an IPP server will respond to
func getPrinterAttributesRequest(uri string) bytes.Buffer { func getPrinterAttributesRequest(uri string) bytes.Buffer {
var b bytes.Buffer var b bytes.Buffer

@ -7,9 +7,11 @@ import (
//"bytes" //"bytes"
"encoding/binary" "encoding/binary"
//"errors" //"errors"
"io" //"fmt"
//"io"
"net/http" "net/http"
"strconv" "strconv"
"strings"
//"net" //"net"
//"net/url" //"net/url"
//"time" //"time"
@ -18,15 +20,20 @@ import (
"github.com/zmap/zgrab2" "github.com/zmap/zgrab2"
) )
const (
CONTENT_TYPE string = "application/ipp"
)
//TODO: Tag relevant results and exlain in comments //TODO: Tag relevant results and exlain in comments
// ScanResults instances are returned by the module's Scan function. // ScanResults instances are returned by the module's Scan function.
type ScanResults struct { type ScanResults struct {
Response *http.Response `json:"response,omitempty"` //TODO: Include a full response or at least a blob in the data
//Response *http.Response `json:"response,omitempty"`
MajorVersion int8 `json:"major_version"` MajorVersion int8 `json:"version_major"`
MinorVersion int8 `json:"minor_version"` MinorVersion int8 `json:"version_minor"`
Version string `json:"version_string,omitempty"` VersionString string `json:"version_string,omitempty"`
CUPSVersion string `json:"cups_version,omitempty"` CUPSVersion string `json:"cups_version,omitempty"`
//TODO: Uncomment this when implementing the TLS version of things //TODO: Uncomment this when implementing the TLS version of things
@ -34,35 +41,30 @@ type ScanResults struct {
// TLSLog *zgrab2.TLSLog `json:"tls,omitempty"` // TLSLog *zgrab2.TLSLog `json:"tls,omitempty"`
} }
//FIXME: We don't need this. // TODO: Annotate every flag thoroughly
func readResultsFromResponseBody(body *io.ReadCloser) *ScanResults { // TODO: Add more protocol-specific flags as needed
return &ScanResults{}
}
// TODO: Add more protocol-specific flags
// Flags holds the command-line configuration for the ipp scan module. // Flags holds the command-line configuration for the ipp scan module.
// Populated by the framework. // Populated by the framework.
type Flags struct { type Flags struct {
zgrab2.BaseFlags zgrab2.BaseFlags
//FIXME: Borrowed from http module //FIXME: Borrowed from http module
MaxSize int `long:"max-size" default:"256" description:"Max kilobytes to read in response to an HTTP request"` MaxRead int `long:"max-size" default:"256" description:"Max kilobytes to read in response to an HTTP request"`
//TODO: Include once TLS is implemented // TODO: Protocols that support TLS should include zgrab2.TLSFlags (do once implemented)
// Protocols that support TLS should include zgrab2.TLSFlags // TODO: Maybe implement both an ipps connection and upgrade to https
IPPSecure bool `long:"ipps" description:"Perform a TLS handshake immediately upon connecting."`
Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"` Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
} }
//TODO: Figure out what moduel-global state may be necessary
// Module implements the zgrab2.Module interface. // Module implements the zgrab2.Module interface.
type Module struct { type Module struct {
// TODO: Add any module-global state // TODO: Add any module-global state if necessary
} }
//TODO: Figure out what scan state may be necessary
// Scanner implements the zgrab2.Scanner interface. // Scanner implements the zgrab2.Scanner interface.
type Scanner struct { type Scanner struct {
config *Flags config *Flags
// TODO: Add scan state // TODO: Add scan state if any is necessary
} }
// RegisterModule registers the zgrab2 module. // RegisterModule registers the zgrab2 module.
@ -97,7 +99,6 @@ func (flags *Flags) Help() string {
return "" return ""
} }
//TODO: Implement
// Init initializes the Scanner. // Init initializes the Scanner.
func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error { func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error {
f, _ := flags.(*Flags) f, _ := flags.(*Flags)
@ -127,7 +128,6 @@ func (scanner *Scanner) GetPort() uint {
} }
//FIXME: Maybe switch to ipp/ipps schemes, at least optionally //FIXME: Maybe switch to ipp/ipps schemes, at least optionally
//FIXME: Stolen from http module, which isn't a good practice
func getIPPURL(https bool, host string, port uint16, endpoint string) string { func getIPPURL(https bool, host string, port uint16, endpoint string) string {
var proto string var proto string
if https { if https {
@ -138,6 +138,15 @@ func getIPPURL(https bool, host string, port uint16, endpoint string) string {
return proto + "://" + host + ":" + strconv.FormatUint(uint64(port), 10) + endpoint return proto + "://" + host + ":" + strconv.FormatUint(uint64(port), 10) + endpoint
} }
func ippInContentType(resp http.Response) bool {
for _, t := range resp.Header["Content-Type"] {
if strings.Contains(t, CONTENT_TYPE) {
return true
}
}
return false
}
//TODO: Doesn't support TLS at all right now //TODO: Doesn't support TLS at all right now
func (scanner *Scanner) grab(target zgrab2.ScanTarget) (int8, int8, *zgrab2.ScanError) { func (scanner *Scanner) grab(target zgrab2.ScanTarget) (int8, int8, *zgrab2.ScanError) {
//FIXME: This is not where this hostname assignment logic should live //FIXME: This is not where this hostname assignment logic should live
@ -145,25 +154,31 @@ func (scanner *Scanner) grab(target zgrab2.ScanTarget) (int8, int8, *zgrab2.Scan
if host == "" { if host == "" {
host = target.IP.String() host = target.IP.String()
} }
//TODO: Make https bool depend on scanner's config //FIXME: ?Should just use endpoint "/", since we get the same response as "/ipp" on CUPS??
//TODO: ?Shouldn't put any endpoint, since we get the same response w/o on CUPS?? uri := getIPPURL(scanner.config.IPPSecure, host, uint16(scanner.config.BaseFlags.Port), "/ipp")
uri := getIPPURL(false, host, uint16(scanner.config.BaseFlags.Port), "/ipp")
b := getPrinterAttributesRequest(uri) b := getPrinterAttributesRequest(uri)
resp, err := http.Post(uri, "application/ipp", &b) resp, err := http.Post(uri, CONTENT_TYPE, &b)
if err != nil { if err != nil {
//FIXME: Create a descriptive error //TODO: Create a descriptive error
return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err) return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err)
} }
if resp != nil && resp.Body != nil { if resp != nil && resp.Body != nil {
defer resp.Body.Close() defer resp.Body.Close()
} else { } else {
//FIXME: Determine whether we need this error to avoid reading from Body //TODO: Determine whether we need this error to avoid reading from Body
return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err) return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err)
} }
//FIXME: Maybe add something to handle redirects //FIXME: Maybe add something to handle redirects
//FIXME: Probably return the whole response for further inspection, rather //FIXME: Probably return the whole response for further inspection by ztag, rather
// than grabbing first 2 bytes. In that case, probs instate maxRead like http // than grabbing first 2 bytes. In that case, implement maxRead like http module
//FIXME: Check to make sure that the response is actually IPP
//Check to make sure that the repsonse received is actually IPP
//Content-Type header matches is sufficient
//HTTP on port 631 is sufficient
//Still record data in the case of protocol error to see what that data looks like
//TODO: Record server-header version numbers
//protocols := resp.Header["Server"])
var version int16 var version int16
if err := binary.Read(resp.Body, binary.BigEndian, &version); err != nil { if err := binary.Read(resp.Body, binary.BigEndian, &version); err != nil {
return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err) return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err)
@ -172,17 +187,16 @@ func (scanner *Scanner) grab(target zgrab2.ScanTarget) (int8, int8, *zgrab2.Scan
} }
// Scan TODO: describe how scan operates // Scan TODO: describe how scan operates
//1. FIXME: Don't open connection, because we don't need it? //1. Send a request (currently get-printer-attributes)
//2. Send something (currently get-printer-attributes) //2. Take in that response & read out version numbers
//3. Take in that response & read out version numbers
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) { func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) {
// TODO: implement // TODO: use Connection again, at least when implementing TLS
major, minor, err := scanner.grab(target) major, minor, err := scanner.grab(target)
//FIXME: Triggering even though error IS nil //FIXME: Triggering even though error IS nil
//FIXME: This is a sloppy bodge to handle the issue, since you must know implementation details below you //FIXME: This is a sloppy bodge to handle the issue
if major == 0 && minor == 0 && err != nil { if major == 0 && minor == 0 && err != nil {
//TODO: Consider mimicking HTTP Scan's retryHTTPS functionality //TODO: Consider mimicking HTTP Scan's retryHTTPS functionality
//TODO: Create relevant error, or send something more descriptive? //TODO: Create more detailed error message?
return zgrab2.TryGetScanStatus(err), nil, err return zgrab2.TryGetScanStatus(err), nil, err
} }
results := &ScanResults{} results := &ScanResults{}

@ -9,7 +9,11 @@ import zgrab2
ipp_scan_response = SubRecord({ ipp_scan_response = SubRecord({
"result": SubRecord({ "result": SubRecord({
"test_key": String(doc="FIXME: Remove this") "version_major": Signed8BitInteger(),
"version_minor": Signed8BitInteger(),
"version_string": String(),
"cups_version": String(),
#"tls": zgrab2.tls_log,
}) })
}, extends=zgrab2.base_scan_response) }, extends=zgrab2.base_scan_response)