2018-02-21 15:04:25 +00:00
// Package mssql provides the zgrab2 scanner module for the MSSQL protocol.
// Default Port: 1433 (TCP)
//
// The --encrypt-mode flag allows setting an explicit client encryption mode
// (the default is ENCRYPT_ON). Note: only ENCRYPT_NOT_SUP will skip the TLS
// handshake, since even ENCRYPT_OFF uses TLS for the login step.
//
// The scan performs a PRELOGIN and if possible does a TLS handshake.
//
// The output is the the server version and instance name, and if applicable the
// TLS output.
2018-02-02 19:52:03 +00:00
package mssql
import (
log "github.com/sirupsen/logrus"
"github.com/zmap/zgrab2"
)
2018-02-21 15:04:25 +00:00
// ScanResults contains detailed information about each step of the
2018-02-02 19:52:03 +00:00
// MySQL handshake, and can be encoded to JSON.
2018-02-21 15:04:25 +00:00
type ScanResults struct {
// Version is the version returned by the server in the PRELOGIN response.
// Its format is "MAJOR.MINOR.BUILD_NUMBER".
Version string ` json:"version,omitempty" `
// InstanceName is the value of the INSTANCE field returned by the server
// in the PRELOGIN response.
InstanceName string ` json:"instance_name,omitempty" `
// PreloginOptions are the raw key-value pairs returned by the server in
// response to the PRELOGIN call. Debug only.
PreloginOptions * PreloginOptions ` json:"prelogin_options,omitempty" zgrab:"debug" `
// TLSLog is the shared TLS handshake/scan log.
TLSLog * zgrab2 . TLSLog ` json:"tls,omitempty" `
2018-02-02 19:52:03 +00:00
}
2018-02-21 15:04:25 +00:00
// Flags defines the command-line configuration options for the module.
type Flags struct {
2018-02-02 19:52:03 +00:00
zgrab2 . BaseFlags
zgrab2 . TLSFlags
2018-02-21 15:04:25 +00:00
EncryptMode string ` long:"encrypt-mode" description:"The type of encryption to request in the pre-login step. One of ENCRYPT_ON, ENCRYPT_OFF, ENCRYPT_NOT_SUP." default:"ENCRYPT_ON" `
2018-02-02 19:52:03 +00:00
Verbose bool ` long:"verbose" description:"More verbose logging, include debug fields in the scan results" `
}
2018-02-21 15:04:25 +00:00
// Module is the implementation of zgrab2.Module for the MSSQL protocol.
type Module struct {
2018-02-02 19:52:03 +00:00
}
2018-02-21 15:04:25 +00:00
// Scanner is the implementation of zgrab2.Scanner for the MSSQL protocol.
type Scanner struct {
config * Flags
2018-02-02 19:52:03 +00:00
}
2018-02-21 15:04:25 +00:00
// NewFlags returns a default Flags instance to be populated by the command
// line flags.
func ( module * Module ) NewFlags ( ) interface { } {
return new ( Flags )
2018-02-02 19:52:03 +00:00
}
2018-02-21 15:04:25 +00:00
// NewScanner returns a new Scanner instance.
func ( module * Module ) NewScanner ( ) zgrab2 . Scanner {
return new ( Scanner )
2018-02-02 19:52:03 +00:00
}
2018-02-21 15:04:25 +00:00
// Validate does nothing in this module.
func ( flags * Flags ) Validate ( args [ ] string ) error {
2018-02-02 19:52:03 +00:00
return nil
}
2018-02-21 15:04:25 +00:00
// Help returns the help string for this module.
func ( flags * Flags ) Help ( ) string {
2018-02-02 19:52:03 +00:00
return ""
}
2018-02-21 15:04:25 +00:00
// Init initializes the Scanner instance with the given command-line flags.
func ( scanner * Scanner ) Init ( flags zgrab2 . ScanFlags ) error {
f , _ := flags . ( * Flags )
2018-02-02 19:52:03 +00:00
scanner . config = f
return nil
}
2018-02-21 15:04:25 +00:00
// InitPerSender does nothing in this module.
func ( scanner * Scanner ) InitPerSender ( senderID int ) error {
2018-02-02 19:52:03 +00:00
return nil
}
2018-03-12 17:36:11 +00:00
// Protocol returns the protocol identifer for the scanner.
func ( s * Scanner ) Protocol ( ) string {
return "mssql"
}
2018-02-21 15:04:25 +00:00
// GetName returns the configured scanner name.
func ( scanner * Scanner ) GetName ( ) string {
2018-02-02 19:52:03 +00:00
return scanner . config . Name
}
2018-02-21 15:04:25 +00:00
// GetPort returns the configured scanner port.
func ( scanner * Scanner ) GetPort ( ) uint {
2018-02-02 19:52:03 +00:00
return scanner . config . Port
}
2018-02-21 15:04:25 +00:00
// Scan performs the MSSQL scan.
// 1. Open a TCP connection to the target port (default 1433).
// 2. Send a PRELOGIN packet to the server.
// 3. Read the PRELOGIN response from the server.
// 4. If the server encrypt mode is EncryptModeNotSupported, break.
// 5. Perform a TLS handshake, with the packets wrapped in TDS headers.
// 6. Decode the Version and InstanceName from the PRELOGIN response
func ( scanner * Scanner ) Scan ( target zgrab2 . ScanTarget ) ( zgrab2 . ScanStatus , interface { } , error ) {
2018-02-02 19:52:03 +00:00
conn , err := target . Open ( & scanner . config . BaseFlags )
if err != nil {
return zgrab2 . TryGetScanStatus ( err ) , nil , err
}
sql := NewConnection ( conn )
defer sql . Close ( )
2018-02-21 15:04:25 +00:00
result := & ScanResults { }
2018-02-02 19:52:03 +00:00
_ , err = sql . Handshake ( scanner . config )
if sql . tlsConn != nil {
result . TLSLog = sql . tlsConn . GetLog ( )
}
2018-02-21 15:04:25 +00:00
if sql . PreloginOptions != nil {
result . PreloginOptions = sql . PreloginOptions
version := sql . PreloginOptions . GetVersion ( )
2018-02-02 19:52:03 +00:00
if version != nil {
2018-02-21 15:04:25 +00:00
result . Version = version . String ( )
2018-02-02 19:52:03 +00:00
}
2018-02-21 15:04:25 +00:00
result . InstanceName = string ( ( * sql . PreloginOptions ) [ PreloginInstance ] )
2018-02-02 19:52:03 +00:00
}
if err != nil {
2018-02-21 15:04:25 +00:00
if sql . PreloginOptions == nil && sql . readValidTDSPacket == false {
// If we received no PreloginOptions and none of the packets we've
// read appeared to be a valid TDS header, then the inference is
// that we found no MSSQL service on the target.
// NOTE: In the case where PreloginOptions == nil but
// readValidTDSPacket == true, the result will be empty, but not
// nil.
result = nil
}
2018-02-02 19:52:03 +00:00
switch err {
2018-02-21 15:04:25 +00:00
case ErrNoServerEncryption :
return zgrab2 . SCAN_APPLICATION_ERROR , result , err
case ErrServerRequiresEncryption :
return zgrab2 . SCAN_APPLICATION_ERROR , result , err
2018-02-02 19:52:03 +00:00
default :
2018-02-21 15:04:25 +00:00
return zgrab2 . TryGetScanStatus ( err ) , result , err
2018-02-02 19:52:03 +00:00
}
}
return zgrab2 . SCAN_SUCCESS , result , nil
}
// RegisterModule is called by modules/mssql.go's init()
func RegisterModule ( ) {
2018-02-21 15:04:25 +00:00
var module Module
2018-02-02 19:52:03 +00:00
_ , err := zgrab2 . AddCommand ( "mssql" , "MSSQL" , "Grab a mssql handshake" , 1433 , & module )
log . SetLevel ( log . DebugLevel )
if err != nil {
log . Fatal ( err )
}
}