Merge pull request #55 from zmap/feature/lintPostgres
Run golint on postgres module
This commit is contained in:
commit
33d01cda40
@ -14,31 +14,42 @@ import (
|
||||
"github.com/zmap/zgrab2"
|
||||
)
|
||||
|
||||
// Connection wraps the state of a given connection to a server
|
||||
// Connection wraps the state of a given connection to a server.
|
||||
type Connection struct {
|
||||
// Connection is the underlying TCP (or TLS) stream.
|
||||
Connection net.Conn
|
||||
Config *PostgresFlags
|
||||
IsSSL bool
|
||||
|
||||
// Config contains the flags from the command line.
|
||||
Config *Flags
|
||||
|
||||
// IsSSL is true if Connection is a TLS connection.
|
||||
IsSSL bool
|
||||
}
|
||||
|
||||
// ServerPacket is a direct representation of the response packet returned by the server (See e.g. https://www.postgresql.org/docs/9.6/static/protocol-message-formats.html)
|
||||
// ServerPacket is a direct representation of the response packet
|
||||
// returned by the server.
|
||||
// See e.g. https://www.postgresql.org/docs/9.6/static/protocol-message-formats.html
|
||||
// The first byte is a message type, an alphanumeric character.
|
||||
// The following four bytes are the length of the message body.
|
||||
// The following <length> bytes are the message itself.
|
||||
// In certain special cases, the Length can be 0; for instance, a response to an SSLRequest is only a S/N Type with no length / body, while pre-startup errors can be a E Type followed by a \n\0-terminated string.
|
||||
// In certain special cases, the Length can be 0; for instance, a
|
||||
// response to an SSLRequest is only a S/N Type with no length / body,
|
||||
// while pre-startup errors can be a E Type followed by a \n\0-
|
||||
// terminated string.
|
||||
type ServerPacket struct {
|
||||
Type byte
|
||||
Length uint32
|
||||
Body []byte
|
||||
}
|
||||
|
||||
// ServerPacket.ToString() is used in logging, to get a human-readable representation of the packet.
|
||||
// ToString is used in logging, to get a human-readable representation
|
||||
// of the packet.
|
||||
func (p *ServerPacket) ToString() string {
|
||||
// TODO: Don't hex-encode human-readable bodies?
|
||||
return fmt.Sprintf("{ ServerPacket(%p): { Type: '%c', Length: %d, Body: [[\n%s\n]] } }", &p, p.Type, p.Length, hex.Dump(p.Body))
|
||||
}
|
||||
|
||||
// Connection.Send() sends a client packet: a big-endian uint32 length followed by the body.
|
||||
// Send a client packet: a big-endian uint32 length followed by a body.
|
||||
func (c *Connection) Send(body []byte) error {
|
||||
toSend := make([]byte, len(body)+4)
|
||||
copy(toSend[4:], body)
|
||||
@ -50,7 +61,7 @@ func (c *Connection) Send(body []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Connection.SendU32() sends an uint32 packet to the server.
|
||||
// SendU32 sends an uint32 packet to the server.
|
||||
func (c *Connection) SendU32(val uint32) error {
|
||||
toSend := make([]byte, 8)
|
||||
binary.BigEndian.PutUint32(toSend[0:], uint32(8))
|
||||
@ -60,12 +71,12 @@ func (c *Connection) SendU32(val uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Connection.Close() closes out the underlying TCP connection to the server.
|
||||
// Close out the underlying TCP connection to the server.
|
||||
func (c *Connection) Close() error {
|
||||
return c.Connection.Close()
|
||||
}
|
||||
|
||||
// Connection.tryReadPacket() attempts to read a packet length + body from the given connection.
|
||||
// tryReadPacket tries to read a length + body from the connection.
|
||||
func (c *Connection) tryReadPacket(header byte) (*ServerPacket, *zgrab2.ScanError) {
|
||||
ret := ServerPacket{Type: header}
|
||||
var length [4]byte
|
||||
@ -87,9 +98,8 @@ func (c *Connection) tryReadPacket(header byte) (*ServerPacket, *zgrab2.ScanErro
|
||||
ret.Length = 0
|
||||
ret.Body = append(length[:], ret.Body...)
|
||||
return &ret, nil
|
||||
} else {
|
||||
return nil, zgrab2.NewScanError(zgrab2.SCAN_PROTOCOL_ERROR, fmt.Errorf("Server returned too much data: length = 0x%x; first %d bytes = %s", ret.Length, n, hex.EncodeToString(buf[:n])))
|
||||
}
|
||||
return nil, zgrab2.NewScanError(zgrab2.SCAN_PROTOCOL_ERROR, fmt.Errorf("Server returned too much data: length = 0x%x; first %d bytes = %s", ret.Length, n, hex.EncodeToString(buf[:n])))
|
||||
}
|
||||
ret.Body = make([]byte, ret.Length-4) // Length includes the length of the Length uint32
|
||||
_, err = io.ReadFull(c.Connection, ret.Body)
|
||||
@ -99,7 +109,9 @@ func (c *Connection) tryReadPacket(header byte) (*ServerPacket, *zgrab2.ScanErro
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
// Connection.RequestSSL() sends an SSLRequest packet to the server, and returns true iff the server reports that it is SSL-capable. Otherwise it returns false and possibly an error.
|
||||
// RequestSSL sends an SSLRequest packet to the server, and returns true
|
||||
// if and only if the server reports that it is SSL-capable. Otherwise
|
||||
// it returns false and possibly an error.
|
||||
func (c *Connection) RequestSSL() (bool, *zgrab2.ScanError) {
|
||||
// NOTE: The SSLRequest request type was introduced in version 7.2, released in 2002 (though the oldest supported version is 9.3, released 2013-09-09)
|
||||
if err := c.SendU32(postgresSSLRequest); err != nil {
|
||||
@ -136,7 +148,7 @@ func (c *Connection) RequestSSL() (bool, *zgrab2.ScanError) {
|
||||
}
|
||||
}
|
||||
|
||||
// Connection.ReadPacket() reads a ServerPacket from the server.
|
||||
// ReadPacket reads a ServerPacket from the server.
|
||||
func (c *Connection) ReadPacket() (*ServerPacket, *zgrab2.ScanError) {
|
||||
var header [1]byte
|
||||
_, err := io.ReadFull(c.Connection, header[0:1])
|
||||
@ -151,7 +163,8 @@ func (c *Connection) ReadPacket() (*ServerPacket, *zgrab2.ScanError) {
|
||||
return c.tryReadPacket(header[0])
|
||||
}
|
||||
|
||||
// Connection.GetTLSLog() gets the connection's TLSLog, or nil if the connection has not yet been set up as TLS
|
||||
// GetTLSLog gets the connection's TLSLog, or nil if the connection has
|
||||
// not yet been set up as TLS.
|
||||
func (c *Connection) GetTLSLog() *zgrab2.TLSLog {
|
||||
if !c.IsSSL {
|
||||
return nil
|
||||
@ -159,7 +172,8 @@ func (c *Connection) GetTLSLog() *zgrab2.TLSLog {
|
||||
return c.Connection.(*zgrab2.TLSConnection).GetLog()
|
||||
}
|
||||
|
||||
// encodeMap() encodes a map into a byte array of the form "key0\0value\0key1\0value1\0...keyN\0valueN\0\0"
|
||||
// encodeMap encodes a map into a byte array of the form
|
||||
// "key0\0value\0key1\0value1\0...keyN\0valueN\0\0"
|
||||
func encodeMap(dict map[string]string) []byte {
|
||||
var strs []string
|
||||
for k, v := range dict {
|
||||
@ -169,7 +183,8 @@ func encodeMap(dict map[string]string) []byte {
|
||||
return append([]byte(strings.Join(strs, "\x00")), 0x00, 0x00)
|
||||
}
|
||||
|
||||
// Connection.SendStartupMessage() creates and sends a StartupMessage: uint16 Major + uint16 Minor + (key/value pairs)
|
||||
// SendStartupMessage creates and sends a StartupMessage.
|
||||
// The format is uint16 Major + uint16 Minor + (key/value pairs).
|
||||
func (c *Connection) SendStartupMessage(version string, kvps map[string]string) error {
|
||||
dict := encodeMap(kvps)
|
||||
ret := make([]byte, len(dict)+4)
|
||||
@ -179,11 +194,11 @@ func (c *Connection) SendStartupMessage(version string, kvps map[string]string)
|
||||
}
|
||||
major, err := strconv.ParseUint(parts[0], 0, 16)
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing major version %s as a uint16:", parts[0], err)
|
||||
log.Fatalf("Error parsing major version %s as a uint16: %v", parts[0], err)
|
||||
}
|
||||
minor, err := strconv.ParseUint(parts[1], 0, 16)
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing minor version as a uint16:", parts[1], err)
|
||||
log.Fatalf("Error parsing minor version %s as a uint16: %v", parts[1], err)
|
||||
}
|
||||
binary.BigEndian.PutUint16(ret[0:2], uint16(major))
|
||||
binary.BigEndian.PutUint16(ret[2:4], uint16(minor))
|
||||
@ -192,17 +207,17 @@ func (c *Connection) SendStartupMessage(version string, kvps map[string]string)
|
||||
return c.Send(ret)
|
||||
}
|
||||
|
||||
// Connection.ReadAll() reads packets from the given connection until it hits a timeout, EOF, or a 'Z' packet.
|
||||
// ReadAll reads packets from the given connection until it hits a
|
||||
// timeout, EOF, or a 'Z' packet.
|
||||
func (c *Connection) ReadAll() ([]*ServerPacket, *zgrab2.ScanError) {
|
||||
var ret []*ServerPacket = nil
|
||||
var ret []*ServerPacket
|
||||
for {
|
||||
response, readError := c.ReadPacket()
|
||||
if readError != nil {
|
||||
if readError.Status == zgrab2.SCAN_IO_TIMEOUT || readError.Err == io.EOF {
|
||||
return ret, nil
|
||||
} else {
|
||||
return ret, readError
|
||||
}
|
||||
return ret, readError
|
||||
}
|
||||
ret = append(ret, response)
|
||||
if response.Type == 'Z' {
|
||||
@ -211,18 +226,19 @@ func (c *Connection) ReadAll() ([]*ServerPacket, *zgrab2.ScanError) {
|
||||
}
|
||||
}
|
||||
|
||||
// connectionManager is a utility for getting connections and ensuring that they all get closed
|
||||
// TODO: Is there something like this in the standard libraries??
|
||||
// connectionManager is a utility for getting connections and ensuring
|
||||
// that they all get closed.
|
||||
// TODO: Is there something like this in the standard libraries?
|
||||
type connectionManager struct {
|
||||
connections []io.Closer
|
||||
}
|
||||
|
||||
// Add a connection to be cleaned up
|
||||
// addConnection adds a managed connection.
|
||||
func (m *connectionManager) addConnection(c io.Closer) {
|
||||
m.connections = append(m.connections, c)
|
||||
}
|
||||
|
||||
// Close all managed connections
|
||||
// cleanUp closes all managed connections.
|
||||
func (m *connectionManager) cleanUp() {
|
||||
for _, v := range m.connections {
|
||||
// Close them all even if there is a panic with one
|
||||
@ -235,7 +251,7 @@ func (m *connectionManager) cleanUp() {
|
||||
}
|
||||
}
|
||||
|
||||
// Get a new connectionmanager instance
|
||||
// Get a new connectionmanager instance.
|
||||
func newConnectionManager() *connectionManager {
|
||||
return &connectionManager{}
|
||||
}
|
||||
|
@ -1,3 +1,12 @@
|
||||
// Package postgres contains the postgres zgrab2 Module implementation.
|
||||
// The Scan does three (or four -- see below) consecutive connections to
|
||||
// the server, using different StartupMessages each time, and adds the
|
||||
// server's response to each to the output.
|
||||
// If any of database/user/application-name are specified on the command
|
||||
// line, the fourth StartupMessage is sent with the provided data. This
|
||||
// may allow additional data, such as detailed server parameters, to be
|
||||
// collected. Absent these, version information must be inferred from
|
||||
// the values in the results (e.g. line numbers in error strings).
|
||||
package postgres
|
||||
|
||||
import (
|
||||
@ -16,63 +25,100 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
// KeyUnknownErrorTag is the key into the error table denoting an
|
||||
// unrecognized error type.
|
||||
KeyUnknownErrorTag = "_unknown_error_tag"
|
||||
KeyBadParameters = "_bad_parameters"
|
||||
// KeyBadParameters is the key into the ServerParameters table
|
||||
// denoting an invalid parameter.
|
||||
KeyBadParameters = "_bad_parameters"
|
||||
)
|
||||
|
||||
// PostgresResults is the information returned by the scanner to the caller.
|
||||
// Results is the information returned by the scanner to the caller.
|
||||
// https://raw.githubusercontent.com/nmap/nmap/master/nmap-service-probes uses the line number of the error response (e.g. StartupError["line"]) to infer the version number
|
||||
type PostgresResults struct {
|
||||
TLSLog *zgrab2.TLSLog `json:"tls,omitempty"`
|
||||
SupportedVersions string `json:"supported_versions,omitempty"`
|
||||
ProtocolError *PostgresError `json:"protocol_error,omitempty"`
|
||||
StartupError *PostgresError `json:"startup_error,omitempty"`
|
||||
UserStartupError *PostgresError `json:"user_startup_error,omitempty"`
|
||||
IsSSL bool `json:"is_ssl"`
|
||||
type Results struct {
|
||||
// TLSLog is the standard TLS log for the first connection.
|
||||
TLSLog *zgrab2.TLSLog `json:"tls,omitempty"`
|
||||
|
||||
// SupportedVersions is the string returned by the server in response
|
||||
// to a StartupMessage with ProtocolVersion = 0.0.
|
||||
SupportedVersions string `json:"supported_versions,omitempty"`
|
||||
|
||||
// ProtocolError is the string returned by the server in response to
|
||||
// a StartupMessage with ProtocolVersion = 255.255.
|
||||
ProtocolError *PostgresError `json:"protocol_error,omitempty"`
|
||||
|
||||
// StartupError is the error returned by the server in response to the
|
||||
// StartupMessage with no user provided.
|
||||
StartupError *PostgresError `json:"startup_error,omitempty"`
|
||||
|
||||
// UserStartupError is the error returned by the server in response to
|
||||
// the final StartupMessage when the user/database/application-name is
|
||||
// set.
|
||||
UserStartupError *PostgresError `json:"user_startup_error,omitempty"`
|
||||
|
||||
// IsSSL is true if the client was able to set up an SSL connection
|
||||
// with the server.
|
||||
IsSSL bool `json:"is_ssl"`
|
||||
|
||||
// AuthenticationMode is the value of the R-type packet returned after
|
||||
// the final StartupMessage.
|
||||
AuthenticationMode *AuthenticationMode `json:"authentication_mode,omitempty"`
|
||||
ServerParameters *ServerParameters `json:"server_parameters,omitempty"`
|
||||
BackendKeyData *BackendKeyData `json:"backend_key_data,omitempty", zgrab:"debug"`
|
||||
TransactionStatus string `json:"transaction_status,omitempty"`
|
||||
|
||||
// ServerParameters is a map of the key/value pairs returned after the
|
||||
// final StartupMessage.
|
||||
ServerParameters *ServerParameters `json:"server_parameters,omitempty"`
|
||||
|
||||
// BackendKeyData is the value of the 'K'-type packet returned by the
|
||||
// server after the final StartupMessage.
|
||||
BackendKeyData *BackendKeyData `json:"backend_key_data,omitempty" zgrab:"debug"`
|
||||
|
||||
// TransactionStatus is the value of the 'Z'-type packet returned by
|
||||
// the server after the final StartupMessage.
|
||||
TransactionStatus string `json:"transaction_status,omitempty"`
|
||||
}
|
||||
|
||||
// PostgresError is parsed the payload of an 'E'-type packet, mapping the friendly names of the various fields to the values returned by the server
|
||||
// PostgresError is parsed the payload of an 'E'-type packet, mapping
|
||||
// the friendly names of the various fields to the values returned by
|
||||
// the server.
|
||||
type PostgresError map[string]string
|
||||
|
||||
// After authentication, the server sends a series of 'S' packets with key/value pairs.
|
||||
// ServerParameters is a map of key/value pairs sent by the server after
|
||||
// authentication. These are 'S'-type packets.
|
||||
// We keep track of them all -- but the golang postgres library only stores the server_version and TimeZone.
|
||||
type ServerParameters map[string]string
|
||||
|
||||
// BackendKeyData is the data returned by the 'K'-type packet
|
||||
// BackendKeyData is the data returned by the 'K'-type packet.
|
||||
type BackendKeyData struct {
|
||||
ProcessID uint32 `json:"process_id"`
|
||||
SecretKey uint32 `json:"secret_key"`
|
||||
}
|
||||
|
||||
// AuthenticationMode abstracts the various 'R'-type packets
|
||||
// AuthenticationMode abstracts the various 'R'-type packets.
|
||||
type AuthenticationMode struct {
|
||||
Mode string `json:"mode"`
|
||||
Payload []byte `json:"payload,omitempty"'`
|
||||
Payload []byte `json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
// PostgresFlags sets the module-specific flags that can be passed in from the command line
|
||||
type PostgresFlags struct {
|
||||
// Flags sets the module-specific flags that can be passed in from the
|
||||
// command line.
|
||||
type Flags struct {
|
||||
zgrab2.BaseFlags
|
||||
zgrab2.TLSFlags
|
||||
SkipSSL bool `long:"skip-ssl" description:"If set, do not attempt to negotiate an SSL connection"`
|
||||
Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
|
||||
ProtocolVersion string `long:"protocol_version" description:"The protocol to use in the StartupPacket" default:"3.0"`
|
||||
ProtocolVersion string `long:"protocol-version" description:"The protocol to use in the StartupPacket" default:"3.0"`
|
||||
User string `long:"user" description:"Username to pass to StartupMessage. If omitted, no user will be sent." default:""`
|
||||
Database string `long:"database" description:"Database to pass to StartupMessage. If omitted, none will be sent." default:""`
|
||||
ApplicationName string `long:"application_name" description:"application_name value to pass in StartupMessage. If omitted, none will be sent." default:""`
|
||||
ApplicationName string `long:"application-name" description:"application_name value to pass in StartupMessage. If omitted, none will be sent." default:""`
|
||||
}
|
||||
|
||||
// PostgresScanner is the zgrab2 scanner type for the postgres protocol
|
||||
type PostgresScanner struct {
|
||||
Config *PostgresFlags
|
||||
// Scanner is the zgrab2 scanner type for the postgres protocol
|
||||
type Scanner struct {
|
||||
Config *Flags
|
||||
}
|
||||
|
||||
// PostgresModule is the zgrab2 module for the postgres protocol
|
||||
type PostgresModule struct {
|
||||
// Module is the zgrab2 module for the postgres protocol
|
||||
type Module struct {
|
||||
}
|
||||
|
||||
// decodeAuthMode() decodes the body of an 'R'-type packet and returns a friendlier description of it
|
||||
@ -94,10 +140,10 @@ func decodeAuthMode(buf []byte) *AuthenticationMode {
|
||||
12: "sasl-final",
|
||||
}
|
||||
|
||||
modeId := binary.BigEndian.Uint32(buf[0:4])
|
||||
mode, ok := modeMap[modeId]
|
||||
modeID := binary.BigEndian.Uint32(buf[0:4])
|
||||
mode, ok := modeMap[modeID]
|
||||
if !ok {
|
||||
mode = fmt.Sprintf("unknown (0x%x)", modeId)
|
||||
mode = fmt.Sprintf("unknown (0x%x)", modeID)
|
||||
}
|
||||
return &AuthenticationMode{
|
||||
Mode: mode,
|
||||
@ -148,9 +194,8 @@ func decodeError(buf []byte) *PostgresError {
|
||||
func appendStringList(dest string, val string) string {
|
||||
if dest == "" {
|
||||
return val
|
||||
} else {
|
||||
return dest + "; " + val
|
||||
}
|
||||
return dest + "; " + val
|
||||
}
|
||||
|
||||
// ServerParameters.appendBadParam() adds a packet to the list of bad/unexpected parameters
|
||||
@ -158,8 +203,8 @@ func (p *ServerParameters) appendBadParam(packet *ServerPacket) {
|
||||
(*p)[KeyBadParameters] = appendStringList((*p)[KeyBadParameters], packet.ToString())
|
||||
}
|
||||
|
||||
// PostgresResults.decodeServerResponse() fills out the results object with packets returned by the server.
|
||||
func (results *PostgresResults) decodeServerResponse(packets []*ServerPacket) {
|
||||
// Results.decodeServerResponse() fills out the results object with packets returned by the server.
|
||||
func (results *Results) decodeServerResponse(packets []*ServerPacket) {
|
||||
// Note: The only parameters the golang postgres library pays attention to are the server_version and the TimeZone.
|
||||
serverParams := make(ServerParameters)
|
||||
for _, packet := range packets {
|
||||
@ -211,42 +256,50 @@ func (results *PostgresResults) decodeServerResponse(packets []*ServerPacket) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *PostgresModule) NewFlags() interface{} {
|
||||
return new(PostgresFlags)
|
||||
// NewFlags returns a default Flags instance.
|
||||
func (m *Module) NewFlags() interface{} {
|
||||
return new(Flags)
|
||||
}
|
||||
|
||||
func (m *PostgresModule) NewScanner() zgrab2.Scanner {
|
||||
return new(PostgresScanner)
|
||||
// NewScanner returns the module's zgrab2.Scanner implementation.
|
||||
func (m *Module) NewScanner() zgrab2.Scanner {
|
||||
return new(Scanner)
|
||||
}
|
||||
|
||||
func (f *PostgresFlags) Validate(args []string) error {
|
||||
// Validate checks the arguments; on success, returns nil.
|
||||
func (f *Flags) Validate(args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *PostgresFlags) Help() string {
|
||||
// Help returns the module's help string.
|
||||
func (f *Flags) Help() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *PostgresScanner) Init(flags zgrab2.ScanFlags) error {
|
||||
f, _ := flags.(*PostgresFlags)
|
||||
// Init initializes the scanner with the given flags.
|
||||
func (s *Scanner) Init(flags zgrab2.ScanFlags) error {
|
||||
f, _ := flags.(*Flags)
|
||||
s.Config = f
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PostgresScanner) InitPerSender(senderID int) error {
|
||||
// InitPerSender does nothing in this module.
|
||||
func (s *Scanner) InitPerSender(senderID int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PostgresScanner) GetName() string {
|
||||
// GetName returns the name from the parameters.
|
||||
func (s *Scanner) GetName() string {
|
||||
return s.Config.Name
|
||||
}
|
||||
|
||||
func (s *PostgresScanner) GetPort() uint {
|
||||
// GetPort returns the port being scanned.
|
||||
func (s *Scanner) GetPort() uint {
|
||||
return s.Config.Port
|
||||
}
|
||||
|
||||
// PostgresScanner.DoSSL() attempts to upgrade the connection to SSL, returning an error on failure.
|
||||
func (s *PostgresScanner) DoSSL(sql *Connection) error {
|
||||
// DoSSL attempts to upgrade the connection to SSL, returning an error on failure.
|
||||
func (s *Scanner) DoSSL(sql *Connection) error {
|
||||
var conn *zgrab2.TLSConnection
|
||||
var err error
|
||||
if conn, err = s.Config.TLSFlags.GetTLSConnection(sql.Connection); err != nil {
|
||||
@ -260,8 +313,8 @@ func (s *PostgresScanner) DoSSL(sql *Connection) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostgresScanner.newConnection() opens up a new connection to the ScanTarget, and if necessary, attempts to update the connection to SSL
|
||||
func (s *PostgresScanner) newConnection(t *zgrab2.ScanTarget, mgr *connectionManager, nossl bool) (*Connection, *zgrab2.ScanError) {
|
||||
// newConnection opens up a new connection to the ScanTarget, and if necessary, attempts to update the connection to SSL
|
||||
func (s *Scanner) newConnection(t *zgrab2.ScanTarget, mgr *connectionManager, nossl bool) (*Connection, *zgrab2.ScanError) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
// Open a managed connection to the ScanTarget, register it for automatic cleanup
|
||||
@ -287,18 +340,33 @@ func (s *PostgresScanner) newConnection(t *zgrab2.ScanTarget, mgr *connectionMan
|
||||
}
|
||||
|
||||
// Return the default KVPs used for all Startup messages
|
||||
func (s *PostgresScanner) getDefaultKVPs() map[string]string {
|
||||
func (s *Scanner) getDefaultKVPs() map[string]string {
|
||||
return map[string]string{
|
||||
"client_encoding": "UTF8",
|
||||
"datestyle": "ISO, MDY",
|
||||
}
|
||||
}
|
||||
|
||||
// PostgresScanner.Scan() does the actual scanning. It opens two connections:
|
||||
// With the first it sends a bogus protocol version in hopes of getting a list of supported protcols back.
|
||||
// With the second, it sends a standard StartupMessage, but without the required "user" field.
|
||||
func (s *PostgresScanner) Scan(t zgrab2.ScanTarget) (status zgrab2.ScanStatus, result interface{}, thrown error) {
|
||||
var results PostgresResults
|
||||
// Scan does the actual scanning. It opens up to four connections:
|
||||
// 1. Sends a bogus protocol version in hopes of getting a list of
|
||||
// supported protcols back. Results here are supported_versions and
|
||||
// and tls (* if applicable).
|
||||
// 2. Send a too-high protocol version (255.255) to get full error
|
||||
// message, including line numbers, which could be useful for probing
|
||||
// server version. This is where it gets the protcol_error result.
|
||||
// 3. Send a StartupMessage with a valid protocol version (by default
|
||||
// 3.0, but this can be overridden on the command line), but omit the
|
||||
// user field. This is where it gets the startup_error result.
|
||||
// 4. Only sent if at least one of user/database/application-name
|
||||
// command line flags are provided. Does the same as #3, but includes
|
||||
// any/all of user/database/application-name. This is where it gets
|
||||
// backend_key_data, server_parameters, authentication_mode,
|
||||
// transaction_status and user_startup_error.
|
||||
//
|
||||
// * NOTE: TLS is only used for the first connection, and then only if
|
||||
// both client and server support it.
|
||||
func (s *Scanner) Scan(t zgrab2.ScanTarget) (status zgrab2.ScanStatus, result interface{}, thrown error) {
|
||||
var results Results
|
||||
|
||||
mgr := newConnectionManager()
|
||||
defer mgr.cleanUp()
|
||||
@ -376,27 +444,29 @@ func (s *PostgresScanner) Scan(t zgrab2.ScanTarget) (status zgrab2.ScanStatus, r
|
||||
|
||||
// Send a StartupMessage with a valid protocol version number, but omit the user field
|
||||
{
|
||||
var err error
|
||||
var response *ServerPacket
|
||||
var readErr *zgrab2.ScanError
|
||||
sql, connectErr := s.newConnection(&t, mgr, true)
|
||||
if connectErr != nil {
|
||||
return connectErr.Unpack(&results)
|
||||
}
|
||||
if err := sql.SendStartupMessage(s.Config.ProtocolVersion, s.getDefaultKVPs()); err != nil {
|
||||
if err = sql.SendStartupMessage(s.Config.ProtocolVersion, s.getDefaultKVPs()); err != nil {
|
||||
return zgrab2.SCAN_PROTOCOL_ERROR, &results, err
|
||||
}
|
||||
if response, err := sql.ReadPacket(); err != nil {
|
||||
if response, readErr = sql.ReadPacket(); err != nil {
|
||||
log.Debugf("Error reading response after StartupMessage: %v", err)
|
||||
return err.Unpack(&results)
|
||||
return readErr.Unpack(&results)
|
||||
}
|
||||
if response.Type == 'E' {
|
||||
results.StartupError = decodeError(response.Body)
|
||||
} else {
|
||||
if response.Type == 'E' {
|
||||
results.StartupError = decodeError(response.Body)
|
||||
} else {
|
||||
// No server should allow a missing User field -- but if it does, log and continue
|
||||
log.Debugf("Unexpected response from server: %s", response.ToString())
|
||||
}
|
||||
// No server should allow a missing User field -- but if it does, log and continue
|
||||
log.Debugf("Unexpected response from server: %s", response.ToString())
|
||||
}
|
||||
// TODO: use any packets returned to fill out results? There probably won't be any, and they will probably be overwritten if Config.User etc is set...
|
||||
if _, err := sql.ReadAll(); err != nil {
|
||||
return err.Unpack(&results)
|
||||
if _, readErr = sql.ReadAll(); err != nil {
|
||||
return readErr.Unpack(&results)
|
||||
}
|
||||
sql.Close()
|
||||
}
|
||||
@ -432,9 +502,10 @@ func (s *PostgresScanner) Scan(t zgrab2.ScanTarget) (status zgrab2.ScanStatus, r
|
||||
return zgrab2.SCAN_SUCCESS, &results, thrown
|
||||
}
|
||||
|
||||
// Called by modules/postgres.go's init()
|
||||
// RegisterModule is called by modules/postgres.go's init(), to register
|
||||
// the postgres module with the zgrab2 framework.
|
||||
func RegisterModule() {
|
||||
var module PostgresModule
|
||||
var module Module
|
||||
_, err := zgrab2.AddCommand("postgres", "Postgres", "Grab a Postgres handshake", 5432, &module)
|
||||
log.SetLevel(log.DebugLevel)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user