Implements basic scanning, without checking for correct protocol.
This commit is contained in:
parent
84100ce1b8
commit
6456dda5e1
70
modules/ipp/ipp.go
Normal file
70
modules/ipp/ipp.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
//"io"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
Conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
//func ReadResponse(body *io.ReadCloser) *ScanResults {
|
||||||
|
// result := &ScanResults{}
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
func reverse(b []byte) []byte {
|
||||||
|
for i := 0; i < len(b)/2; i++ {
|
||||||
|
b[i], b[len(b)-1-i] = b[len(b)-1-i], b[i]
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: Clean this up, and use binary package to handle endianness in the correct order
|
||||||
|
//FIXME: Make sure uint isn't messing anything up here, since they should be signed.
|
||||||
|
func attributeByteString(syntaxTag byte, name string, value string) []byte {
|
||||||
|
//special bytestring denoting value syntax
|
||||||
|
b := []byte{syntaxTag}
|
||||||
|
l := make([]byte, 2)
|
||||||
|
binary.PutUvarint(l, uint64(len(name)))
|
||||||
|
l = reverse(l)
|
||||||
|
b = append(b, l...)
|
||||||
|
b = append(b, []byte(name)...)
|
||||||
|
|
||||||
|
l = make([]byte, 2)
|
||||||
|
binary.PutUvarint(l, uint64(len(value)))
|
||||||
|
l = reverse(l)
|
||||||
|
b = append(b, l...)
|
||||||
|
b = append(b, []byte(value)...)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
//Construct a minimal request that an IPP server will respond to
|
||||||
|
func getPrinterAttributesRequest(uri string) bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
//version 2.1 (newest as of 2018)
|
||||||
|
b.Write([]byte{2, 1})
|
||||||
|
//operation-id = get-printer-attributes
|
||||||
|
b.Write([]byte{0, 0xb})
|
||||||
|
//request-id = 1
|
||||||
|
b.Write([]byte{0, 0, 0, 1})
|
||||||
|
//operation-attributes-tag = 1
|
||||||
|
b.Write([]byte{1})
|
||||||
|
|
||||||
|
//attributes-charset
|
||||||
|
b.Write(attributeByteString(0x47, "attributes-charset", "utf-8"))
|
||||||
|
//attributes-natural-language
|
||||||
|
b.Write(attributeByteString(0x48, "attributes-natural-language", "en-us"))
|
||||||
|
//printer-uri
|
||||||
|
b.Write(attributeByteString(0x45, "printer-uri", uri))
|
||||||
|
//requested-attributes
|
||||||
|
b.Write(attributeByteString(0x44, "requested-attributes", "all"))
|
||||||
|
|
||||||
|
//end-of-attributes-tag = 3
|
||||||
|
b.Write([]byte{3})
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
@ -2,10 +2,14 @@
|
|||||||
// TODO: Describe module, the flags, the probe, the output, etc.
|
// TODO: Describe module, the flags, the probe, the output, etc.
|
||||||
package ipp
|
package ipp
|
||||||
|
|
||||||
|
//TODO: Clean up these imports
|
||||||
import (
|
import (
|
||||||
//"bytes"
|
//"bytes"
|
||||||
|
"encoding/binary"
|
||||||
//"errors"
|
//"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
//"net"
|
//"net"
|
||||||
//"net/url"
|
//"net/url"
|
||||||
//"time"
|
//"time"
|
||||||
@ -17,12 +21,12 @@ import (
|
|||||||
//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 {
|
||||||
// TODO: Add protocol
|
Response *http.Response `json:"response,omitempty"`
|
||||||
//TODO: Explain Protocol Version
|
|
||||||
ProtocolVersion int16 `json:"version"`
|
|
||||||
ServerVersion string `json:"version_string"`
|
|
||||||
|
|
||||||
//TODO: Explain CUPS-Version
|
MajorVersion int8 `json:"major_version"`
|
||||||
|
MinorVersion int8 `json:"minor_version"`
|
||||||
|
|
||||||
|
Version 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
|
||||||
@ -40,6 +44,8 @@ func readResultsFromResponseBody(body *io.ReadCloser) *ScanResults {
|
|||||||
// Populated by the framework.
|
// Populated by the framework.
|
||||||
type Flags struct {
|
type Flags struct {
|
||||||
zgrab2.BaseFlags
|
zgrab2.BaseFlags
|
||||||
|
//FIXME: Borrowed from http module
|
||||||
|
MaxSize int `long:"max-size" default:"256" description:"Max kilobytes to read in response to an HTTP request"`
|
||||||
//TODO: Include once TLS is implemented
|
//TODO: Include once TLS is implemented
|
||||||
// Protocols that support TLS should include zgrab2.TLSFlags
|
// Protocols that support TLS should include zgrab2.TLSFlags
|
||||||
|
|
||||||
@ -120,18 +126,67 @@ func (scanner *Scanner) GetPort() uint {
|
|||||||
return scanner.config.Port
|
return scanner.config.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan TODO: describe what is scanned
|
//FIXME: Maybe switch to ipp/ipps schemes, at least optionally
|
||||||
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) {
|
//FIXME: Stolen from http module, which isn't a good practice
|
||||||
conn, err := target.Open(&scanner.config.BaseFlags)
|
func getIPPURL(https bool, host string, port uint16, endpoint string) string {
|
||||||
|
var proto string
|
||||||
|
if https {
|
||||||
|
proto = "https"
|
||||||
|
} else {
|
||||||
|
proto = "http"
|
||||||
|
}
|
||||||
|
return proto + "://" + host + ":" + strconv.FormatUint(uint64(port), 10) + endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Doesn't support TLS at all right now
|
||||||
|
func (scanner *Scanner) grab(target zgrab2.ScanTarget) (int8, int8, *zgrab2.ScanError) {
|
||||||
|
//FIXME: This is not where this hostname assignment logic should live
|
||||||
|
host := target.Domain
|
||||||
|
if host == "" {
|
||||||
|
host = target.IP.String()
|
||||||
|
}
|
||||||
|
//TODO: Make https bool depend on scanner's config
|
||||||
|
//TODO: ?Shouldn't put any endpoint, since we get the same response w/o on CUPS??
|
||||||
|
uri := getIPPURL(false, host, uint16(scanner.config.BaseFlags.Port), "/ipp")
|
||||||
|
b := getPrinterAttributesRequest(uri)
|
||||||
|
resp, err := http.Post(uri, "application/ipp", &b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
//FIXME: Create a descriptive error
|
||||||
|
return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err)
|
||||||
|
}
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
} else {
|
||||||
|
//FIXME: Determine whether we need this error to avoid reading from Body
|
||||||
|
return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err)
|
||||||
|
}
|
||||||
|
//FIXME: Maybe add something to handle redirects
|
||||||
|
//FIXME: Probably return the whole response for further inspection, rather
|
||||||
|
// than grabbing first 2 bytes. In that case, probs instate maxRead like http
|
||||||
|
//FIXME: Check to make sure that the response is actually IPP
|
||||||
|
var version int16
|
||||||
|
if err := binary.Read(resp.Body, binary.BigEndian, &version); err != nil {
|
||||||
|
return 0, 0, zgrab2.NewScanError(zgrab2.SCAN_UNKNOWN_ERROR, err)
|
||||||
|
}
|
||||||
|
return int8(version >> 8), int8(version & 0xff), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan TODO: describe how scan operates
|
||||||
|
//1. FIXME: Don't open connection, because we don't need it?
|
||||||
|
//2. Send something (currently get-printer-attributes)
|
||||||
|
//3. Take in that response & read out version numbers
|
||||||
|
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) {
|
||||||
|
// TODO: implement
|
||||||
|
major, minor, err := scanner.grab(target)
|
||||||
|
//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
|
||||||
|
if major == 0 && minor == 0 && err != nil {
|
||||||
|
//TODO: Consider mimicking HTTP Scan's retryHTTPS functionality
|
||||||
|
//TODO: Create relevant error, or send something more descriptive?
|
||||||
return zgrab2.TryGetScanStatus(err), nil, err
|
return zgrab2.TryGetScanStatus(err), nil, err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
results := &ScanResults{}
|
||||||
// TODO: implement
|
results.MajorVersion = major
|
||||||
|
results.MinorVersion = minor
|
||||||
//FIXME: Dummy result currently, replace with an actual result assignment
|
return zgrab2.SCAN_SUCCESS, results, nil
|
||||||
result := map[string]string{
|
|
||||||
"test_key": "FIXME: Remove this",
|
|
||||||
}
|
|
||||||
return zgrab2.SCAN_SUCCESS, &result, nil
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user