2018-02-28 20:42:03 +00:00
// Package oracle provides the zgrab2 scanner module for Oracle's TNS protocol.
// Default Port: 1521 (TCP)
//
// The scan does the first part of a TNS handshake, prior to the point where
// any actual authentication is required; the happy case goes
2018-03-26 15:25:04 +00:00
// 1. client-to-server: Connect(--client-version, --min-server-version, --connect-descriptor)
// 2. server-to-client: Resend
// 3. client-to-server: Connect(exact same data)
// 4. server-to-client: Accept(server_version)
// 5. client-to-server: Data: Native Service Negotiation
// 6. server-to-client: Data: Native Service Negotiation(component release versions)
2018-02-28 20:42:03 +00:00
//
// The default scan uses a generic connect descriptor with no explicit connect
// data / service name, so it relies on the server to choose the destination.
//
// Sending an intentionally invalid --connect-descriptor can force a Refuse
// response, which should include a version number.
//
// The output includes the server's protocol version and any component release
// versions that are returned.
2018-02-19 16:19:19 +00:00
package oracle
import (
2018-02-27 21:27:09 +00:00
"fmt"
"strconv"
2018-02-19 16:19:19 +00:00
log "github.com/sirupsen/logrus"
"github.com/zmap/zgrab2"
)
// ScanResults instances are returned by the module's Scan function.
type ScanResults struct {
2018-02-26 21:05:44 +00:00
// Handshake is the log of the TNS handshake between client and server.
Handshake * HandshakeLog ` json:"handshake,omitempty" `
2018-02-19 16:19:19 +00:00
2018-02-26 21:05:44 +00:00
// TLSLog contains the log of the TLS handshake (and any additional
// configured TLS scan operations).
TLSLog * zgrab2 . TLSLog ` json:"tls,omitempty" `
2018-02-19 16:19:19 +00:00
}
// Flags holds the command-line configuration for the HTTP scan module.
// Populated by the framework.
type Flags struct {
zgrab2 . BaseFlags
2018-02-26 21:05:44 +00:00
zgrab2 . TLSFlags
2018-02-27 21:27:09 +00:00
// Version is the client version number sent to the server in the Connect
// packet. TODO: Find version number mappings.
Version uint16 ` long:"client-version" description:"The client version number to send." default:"312" `
// MinVersion is the minimum protocol version that the client claims support
// for in the Connect packet. Same format as Version above.
MinVersion uint16 ` long:"min-server-version" description:"The minimum supported client version to send in the connect packet." default:"300" `
// ReleaseVersion is the five-component dotted-decimal release version
// string the client should send during native Native Security Negotiation.
ReleaseVersion string ` long:"release-version" description:"The dotted-decimal release version used during the NSN negoatiation. Must contain five components (e.g. 1.2.3.4.5)." default:"11.2.0.4.0" `
// GlobalServiceOptions sets the ServiceOptions flags the client will send
// to the server in the Connect packet. 16 bits.
GlobalServiceOptions string ` long:"global-service-options" description:"The Global Service Options flags to send in the connect packet." default:"0x0C41" `
// SDU sets the requested Session Data Unit size value the client sends in
// the Connect packet. 16 bits.
SDU string ` long:"sdu" description:"The SDU value to send in the connect packet." default:"0x2000" `
// TDU sets the request Transport Data Unit size value the client sends in
// the Connect packet. 16 bits.
TDU string ` long:"tdu" description:"The TDU value to send in the connect packet." default:"0xFFFF" `
// ProtocolCharacteristics sets the protocol characteristics flags the
// client sends to the server in the Connect packet. 16 bits.
2018-02-21 14:25:33 +00:00
ProtocolCharacterisics string ` long:"protocol-characteristics" description:"The Protocol Characteristics flags to send in the connect packet." default:"0x7F08" `
2018-02-27 21:27:09 +00:00
// ConnectFlags sets the connect flags the client sends to the server in the
// Connect packet. The upper 16 bits give the first byte, the lower 16 bits
// the second byte.
ConnectFlags string ` long:"connect-flags" description:"The connect flags for the connect packet." default:"0x4141" `
// ConnectDescriptor sets the connect descriptor the client sends in the
// data payload of the Connect packet.
// See https://docs.oracle.com/cd/E11882_01/network.112/e41945/glossary.htm#BGBEAGEA
ConnectDescriptor string ` long:"connect-descriptor" description:"The connect descriptor to use in the connect packet." `
// TCPS determines whether the connection starts with a TLS handshake.
TCPS bool ` long:"tcps" description:"Wrap the connection with a TLS handshake." `
// NewTNS causes the client to use the newer TNS header format with 32-bit
// lengths.
NewTNS bool ` long:"new-tns" description:"If set, use new-style TNS headers" `
// Verbose causes more verbose logging, and includes debug fields inthe scan
// results.
Verbose bool ` long:"verbose" description:"More verbose logging, include debug fields in the scan results" `
2018-02-19 16:19:19 +00:00
}
// Module implements the zgrab2.Module interface.
type Module struct {
}
// Scanner implements the zgrab2.Scanner interface.
type Scanner struct {
config * Flags
}
2018-02-27 21:27:09 +00:00
// RegisterModule registers the zgrab2 module.
2018-02-19 16:19:19 +00:00
func RegisterModule ( ) {
var module Module
_ , err := zgrab2 . AddCommand ( "oracle" , "oracle" , "Probe for oracle" , 1521 , & module )
if err != nil {
log . Fatal ( err )
}
}
// NewFlags returns a default Flags object.
func ( module * Module ) NewFlags ( ) interface { } {
return new ( Flags )
}
// NewScanner returns a new Scanner instance.
func ( module * Module ) NewScanner ( ) zgrab2 . Scanner {
return new ( Scanner )
}
// Validate checks that the flags are valid.
// On success, returns nil.
// On failure, returns an error instance describing the error.
func ( flags * Flags ) Validate ( args [ ] string ) error {
2018-02-27 21:27:09 +00:00
u16Strings := map [ string ] string {
"global-service-options" : flags . GlobalServiceOptions ,
"protocol-characteristics" : flags . ProtocolCharacterisics ,
"connect-flags" : flags . ConnectFlags ,
"sdu" : flags . SDU ,
"tdu" : flags . TDU ,
}
for name , value := range u16Strings {
v , err := strconv . ParseUint ( value , 0 , 32 )
if err != nil {
return fmt . Errorf ( "%s: %s is not a valid 16-bit integer: %v" , name , value , err )
}
if v > 0xffff {
return fmt . Errorf ( "%s: %s is larger than 16 bits" , name , value )
}
}
if _ , err := EncodeReleaseVersion ( flags . ReleaseVersion ) ; err != nil {
return fmt . Errorf ( "release-version: %s is not a valid five-component dotted-decimal number" , flags . ReleaseVersion )
}
2018-02-19 16:19:19 +00:00
return nil
}
// Help returns the module's help string.
func ( flags * Flags ) Help ( ) string {
return ""
}
// Init initializes the Scanner.
func ( scanner * Scanner ) Init ( flags zgrab2 . ScanFlags ) error {
f , _ := flags . ( * Flags )
scanner . config = f
2018-05-11 15:43:08 +00:00
if f . Verbose {
2018-05-11 15:52:08 +00:00
log . SetLevel ( log . DebugLevel )
2018-05-11 15:43:08 +00:00
}
2018-02-19 16:19:19 +00:00
return nil
}
// InitPerSender initializes the scanner for a given sender.
func ( scanner * Scanner ) InitPerSender ( senderID int ) error {
return nil
}
// GetName returns the Scanner name defined in the Flags.
func ( scanner * Scanner ) GetName ( ) string {
return scanner . config . Name
}
2018-06-26 17:51:10 +00:00
// GetTrigger returns the Trigger defined in the Flags.
func ( scanner * Scanner ) GetTrigger ( ) string {
return scanner . config . Trigger
}
2018-03-26 15:46:27 +00:00
// Protocol returns the protocol identifier of the scan.
func ( scanner * Scanner ) Protocol ( ) string {
return "oracle"
}
2018-02-27 21:27:09 +00:00
func ( scanner * Scanner ) getTNSDriver ( ) * TNSDriver {
mode := TNSModeOld
if scanner . config . NewTNS {
mode = TNSMode12c
}
return & TNSDriver { Mode : mode }
}
// Scan does the following:
// 1. Make a TCP connection to the target
// 2. If --tcps is set, do a TLS handshake and use the wrapped socket in future
// calls.
// 3. Instantiate the TNS driver (TNSMode12c if --new-tns is set, otherwise
// TNSModeOld)
// 4. Send the Connect packet to the server with the provided options and
// connect descriptor
// 5. If the server responds with a valid TNS packet, an Oracle server has been
// detected. If not, fail.
// 6. If the response is...
// a. ...a Resend packet, then set result.DidResend and re-send the packet.
// b. ...a Refused packet, then set the result.RefuseReason and RefuseError,
// then exit.
// c. ...a Redirect packet, then set result.RedirectTarget and exit.
// d. ...an Accept packet, go to 7
// e. ...anything else: exit with SCAN_APPLICATION_ERROR
// 7. Pull the server protocol version and other flags from the Accept packet
// into the results, then send a Native Security Negotiation Data packet.
// 8. If the response is not a Data packet, exit with SCAN_APPLICATION_ERROR.
// 9. Pull the versions out of the response and exit with SCAN_SUCCESS.
2018-02-26 21:05:44 +00:00
func ( scanner * Scanner ) Scan ( t zgrab2 . ScanTarget ) ( zgrab2 . ScanStatus , interface { } , error ) {
2018-02-27 21:27:09 +00:00
var results * ScanResults
2018-02-26 21:05:44 +00:00
2018-02-21 14:25:33 +00:00
sock , err := t . Open ( & scanner . config . BaseFlags )
if err != nil {
return zgrab2 . TryGetScanStatus ( err ) , nil , err
}
2018-02-26 21:05:44 +00:00
if scanner . config . TCPS {
tlsConn , err := scanner . config . TLSFlags . GetTLSConnection ( sock )
if err != nil {
// GetTLSConnection can only fail if the input flags are bad
panic ( err )
}
results = new ( ScanResults )
results . TLSLog = tlsConn . GetLog ( )
err = tlsConn . Handshake ( )
if err != nil {
return zgrab2 . TryGetScanStatus ( err ) , nil , err
}
sock = tlsConn
}
2018-02-27 21:27:09 +00:00
2018-02-21 14:25:33 +00:00
conn := Connection {
2018-02-27 21:27:09 +00:00
conn : sock ,
scanner : scanner ,
target : & t ,
tnsDriver : scanner . getTNSDriver ( ) ,
2018-02-21 14:25:33 +00:00
}
2018-02-26 21:05:44 +00:00
connectDescriptor := scanner . config . ConnectDescriptor
if connectDescriptor == "" {
// In local testing, omitting the SERVICE_NAME allowed the server to
// choose an appropriate default. CID.PROGRAM added strictly for logging
// purposes.
connectDescriptor = "(DESCRIPTION=(CONNECT_DATA=(CID=(PROGRAM=zgrab2))))"
}
handshakeLog , err := conn . Connect ( connectDescriptor )
if handshakeLog != nil {
// Ensure that any handshake logs, even if incomplete, get returned.
if results == nil {
// If the results were not created previously to store the TLS log,
// create it now
results = new ( ScanResults )
}
results . Handshake = handshakeLog
}
2018-02-21 14:25:33 +00:00
if err != nil {
2018-02-27 21:27:09 +00:00
switch err {
case ErrUnexpectedResponse :
return zgrab2 . SCAN_APPLICATION_ERROR , results , err
default :
return zgrab2 . TryGetScanStatus ( err ) , results , err
}
2018-02-21 14:25:33 +00:00
}
2018-02-26 21:05:44 +00:00
return zgrab2 . SCAN_SUCCESS , results , nil
2018-02-19 16:19:19 +00:00
}