mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/master' into topic/seth/smb
# Conflicts: # scripts/base/protocols/dce-rpc/main.bro # scripts/base/protocols/ntlm/main.bro # scripts/policy/protocols/smb/smb1-main.bro # src/analyzer/protocol/smb/smb-common.pac # src/analyzer/protocol/smb/smb-strings.pac # src/analyzer/protocol/smb/smb1-com-locking-andx.pac # src/analyzer/protocol/smb/smb1-com-logoff-andx.pac # src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac # src/analyzer/protocol/smb/smb1-com-open-andx.pac # src/analyzer/protocol/smb/smb1-com-read-andx.pac # src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac # src/analyzer/protocol/smb/smb1-com-transaction-secondary.pac # src/analyzer/protocol/smb/smb1-com-transaction.pac # src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac # src/analyzer/protocol/smb/smb1-com-write-andx.pac # src/analyzer/protocol/smb/smb1-protocol.pac
This commit is contained in:
parent
203e63416e
commit
520ac8d92c
162 changed files with 12058 additions and 3781 deletions
15
NEWS
15
NEWS
|
@ -52,6 +52,21 @@ Log Changes
|
||||||
New Functionality
|
New Functionality
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- SMB analyzer. This is the rewrite that has been in development for
|
||||||
|
several years. The scripts are currently not loaded by default and
|
||||||
|
must be loaded manually by loading policy/protocols/smb. The next
|
||||||
|
release will load the smb scripts by default.
|
||||||
|
|
||||||
|
- Implements SMB1+2.
|
||||||
|
- Fully integrated with the file analysis framework so that files
|
||||||
|
transferred over SMB can be analyzed.
|
||||||
|
- Includes GSSAPI and NTLM analyzer and reimplements the DCE-RPC
|
||||||
|
analyzer.
|
||||||
|
- New logs: smb_files.log, smb_mapping.log, ntlm.log, and dce_rpc.log
|
||||||
|
- Not every possible SMB command or functionality is implemented, but
|
||||||
|
generally, file handling should work whenever files are transferred.
|
||||||
|
Please speak up on the mailing list if there is an obvious oversight.
|
||||||
|
|
||||||
- Bro now includes the NetControl framework. The framework allows for easy
|
- Bro now includes the NetControl framework. The framework allows for easy
|
||||||
interaction of Bro with hard- and software switches, firewalls, etc.
|
interaction of Bro with hard- and software switches, firewalls, etc.
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ signature file-ini {
|
||||||
# Microsoft LNK files
|
# Microsoft LNK files
|
||||||
signature file-lnk {
|
signature file-lnk {
|
||||||
file-mime "application/x-ms-shortcut", 49
|
file-mime "application/x-ms-shortcut", 49
|
||||||
file-magic /^\x4C\x00\x00\x00\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x10\x00\x00\x00\x46/
|
file-magic /^\x4c\x00\x00\x00\x01\x14\x02\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46/
|
||||||
}
|
}
|
||||||
|
|
||||||
# Microsoft Registry policies
|
# Microsoft Registry policies
|
||||||
|
|
|
@ -2380,83 +2380,508 @@ type ntp_msg: record {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
## Maps SMB command numbers to descriptive names.
|
module NTLM;
|
||||||
global samba_cmds: table[count] of string &redef
|
|
||||||
&default = function(c: count): string
|
|
||||||
{ return fmt("samba-unknown-%d", c); };
|
|
||||||
|
|
||||||
## An SMB command header.
|
export {
|
||||||
##
|
type NTLM::Version: record {
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
## The major version of the Windows operating system in use
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
major : count;
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
## The minor version of the Windows operating system in use
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction
|
minor : count;
|
||||||
## smb_com_transaction2 smb_com_tree_connect_andx smb_com_tree_disconnect
|
## The build number of the Windows operating system in use
|
||||||
## smb_com_write_andx smb_error smb_get_dfs_referral smb_message
|
build : count;
|
||||||
type smb_hdr : record {
|
## The current revision of NTLMSSP in use
|
||||||
command: count; ##< The command number (see :bro:see:`samba_cmds`).
|
ntlmssp : count;
|
||||||
status: count; ##< The status code.
|
};
|
||||||
flags: count; ##< Flag set 1.
|
|
||||||
flags2: count; ##< Flag set 2.
|
|
||||||
tid: count; ##< TODO.
|
|
||||||
pid: count; ##< Process ID.
|
|
||||||
uid: count; ##< User ID.
|
|
||||||
mid: count; ##< TODO.
|
|
||||||
};
|
|
||||||
|
|
||||||
## An SMB transaction.
|
type NTLM::NegotiateFlags: record {
|
||||||
##
|
## If set, requires 56-bit encryption
|
||||||
## .. bro:see:: smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
negotiate_56 : bool;
|
||||||
## smb_com_transaction smb_com_transaction2
|
## If set, requests an explicit key exchange
|
||||||
type smb_trans : record {
|
negotiate_key_exch : bool;
|
||||||
word_count: count; ##< TODO.
|
## If set, requests 128-bit session key negotiation
|
||||||
total_param_count: count; ##< TODO.
|
negotiate_128 : bool;
|
||||||
total_data_count: count; ##< TODO.
|
## If set, requests the protocol version number
|
||||||
max_param_count: count; ##< TODO.
|
negotiate_version : bool;
|
||||||
max_data_count: count; ##< TODO.
|
## If set, indicates that the TargetInfo fields in the
|
||||||
max_setup_count: count; ##< TODO.
|
## CHALLENGE_MESSAGE are populated
|
||||||
# flags: count;
|
negotiate_target_info : bool;
|
||||||
# timeout: count;
|
## If set, requests the usage of the LMOWF function
|
||||||
param_count: count; ##< TODO.
|
request_non_nt_session_key : bool;
|
||||||
param_offset: count; ##< TODO.
|
## If set, requests and identify level token
|
||||||
data_count: count; ##< TODO.
|
negotiate_identify : bool;
|
||||||
data_offset: count; ##< TODO.
|
## If set, requests usage of NTLM v2 session security
|
||||||
setup_count: count; ##< TODO.
|
## Note: NTML v2 session security is actually NTLM v1
|
||||||
setup0: count; ##< TODO.
|
negotiate_extended_sessionsecurity : bool;
|
||||||
setup1: count; ##< TODO.
|
## If set, TargetName must be a server name
|
||||||
setup2: count; ##< TODO.
|
target_type_server : bool;
|
||||||
setup3: count; ##< TODO.
|
## If set, TargetName must be a domain name
|
||||||
byte_count: count; ##< TODO.
|
target_type_domain : bool;
|
||||||
parameters: string; ##< TODO.
|
|
||||||
};
|
## If set, requests the presence of a signature block
|
||||||
|
## on all messages
|
||||||
|
negotiate_always_sign : bool;
|
||||||
|
## If set, the workstation name is provided
|
||||||
|
negotiate_oem_workstation_supplied : bool;
|
||||||
|
## If set, the domain name is provided
|
||||||
|
negotiate_oem_domain_supplied : bool;
|
||||||
|
## If set, the connection should be anonymous
|
||||||
|
negotiate_anonymous_connection : bool;
|
||||||
|
## If set, requests usage of NTLM v1
|
||||||
|
negotiate_ntlm : bool;
|
||||||
|
|
||||||
|
## If set, requests LAN Manager session key computation
|
||||||
|
negotiate_lm_key : bool;
|
||||||
|
## If set, requests connectionless authentication
|
||||||
|
negotiate_datagram : bool;
|
||||||
|
## If set, requests session key negotiation for message
|
||||||
|
## confidentiality
|
||||||
|
negotiate_seal : bool;
|
||||||
|
## If set, requests session key negotiation for message
|
||||||
|
## signatures
|
||||||
|
negotiate_sign : bool;
|
||||||
|
## If set, the TargetName field is present
|
||||||
|
request_target : bool;
|
||||||
|
|
||||||
|
## If set, requests OEM character set encoding
|
||||||
|
negotiate_oem : bool;
|
||||||
|
## If set, requests Unicode character set encoding
|
||||||
|
negotiate_unicode : bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM::Negotiate: record {
|
||||||
|
## The negotiate flags
|
||||||
|
flags : NTLM::NegotiateFlags;
|
||||||
|
## The domain name of the client, if known
|
||||||
|
domain_name : string &optional;
|
||||||
|
## The machine name of the client, if known
|
||||||
|
workstation : string &optional;
|
||||||
|
## The Windows version information, if supplied
|
||||||
|
version : NTLM::Version &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM::AVs: record {
|
||||||
|
## The server's NetBIOS computer name
|
||||||
|
nb_computer_name : string;
|
||||||
|
## The server's NetBIOS domain name
|
||||||
|
nb_domain_name : string;
|
||||||
|
## The FQDN of the computer
|
||||||
|
dns_computer_name : string &optional;
|
||||||
|
## The FQDN of the domain
|
||||||
|
dns_domain_name : string &optional;
|
||||||
|
## The FQDN of the forest
|
||||||
|
dns_tree_name : string &optional;
|
||||||
|
|
||||||
|
## Indicates to the client that the account
|
||||||
|
## authentication is constrained
|
||||||
|
constrained_auth : bool &optional;
|
||||||
|
## The associated timestamp, if present
|
||||||
|
timestamp : time &optional;
|
||||||
|
## Indicates that the client is providing
|
||||||
|
## a machine ID created at computer startup to
|
||||||
|
## identify the calling machine
|
||||||
|
single_host_id : count &optional;
|
||||||
|
|
||||||
|
## The SPN of the target server
|
||||||
|
target_name : string &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM::Challenge: record {
|
||||||
|
## The negotiate flags
|
||||||
|
flags : NTLM::NegotiateFlags;
|
||||||
|
## The server authentication realm. If the server is
|
||||||
|
## domain-joined, the name of the domain. Otherwise
|
||||||
|
## the server name. See flags.target_type_domain
|
||||||
|
## and flags.target_type_server
|
||||||
|
target_name : string &optional;
|
||||||
|
## The Windows version information, if supplied
|
||||||
|
version : NTLM::Version &optional;
|
||||||
|
## Attribute-value pairs specified by the server
|
||||||
|
target_info : NTLM::AVs &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM::Authenticate: record {
|
||||||
|
## The negotiate flags
|
||||||
|
flags : NTLM::NegotiateFlags;
|
||||||
|
## The domain or computer name hosting the account
|
||||||
|
domain_name : string;
|
||||||
|
## The name of the user to be authenticated.
|
||||||
|
user_name : string;
|
||||||
|
## The name of the computer to which the user was logged on.
|
||||||
|
workstation : string;
|
||||||
|
## The Windows version information, if supplied
|
||||||
|
version : NTLM::Version &optional;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module SMB;
|
||||||
|
|
||||||
|
export {
|
||||||
|
## MAC times for a file.
|
||||||
|
type SMB::MACTimes: record {
|
||||||
|
modified : time &log;
|
||||||
|
accessed : time &log;
|
||||||
|
created : time &log;
|
||||||
|
changed : time &log;
|
||||||
|
} &log;
|
||||||
|
}
|
||||||
|
|
||||||
|
module SMB1;
|
||||||
|
|
||||||
|
export {
|
||||||
|
## An SMB1 header.
|
||||||
|
##
|
||||||
|
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
||||||
|
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
||||||
|
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
||||||
|
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction
|
||||||
|
## smb_com_transaction2 smb_com_tree_connect_andx smb_com_tree_disconnect
|
||||||
|
## smb_com_write_andx smb_error smb_get_dfs_referral smb_message
|
||||||
|
type SMB1::Header : record {
|
||||||
|
command: count; ##< The command number
|
||||||
|
status: count; ##< The status code.
|
||||||
|
flags: count; ##< Flag set 1.
|
||||||
|
flags2: count; ##< Flag set 2.
|
||||||
|
tid: count; ##< Tree ID.
|
||||||
|
pid: count; ##< Process ID.
|
||||||
|
uid: count; ##< User ID.
|
||||||
|
mid: count; ##< Multiplex ID.
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateRawMode: record {
|
||||||
|
## Read raw supported
|
||||||
|
read_raw : bool;
|
||||||
|
## Write raw supported
|
||||||
|
write_raw : bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateCapabilities: record {
|
||||||
|
## The server supports SMB_COM_READ_RAW and SMB_COM_WRITE_RAW
|
||||||
|
raw_mode : bool;
|
||||||
|
## The server supports SMB_COM_READ_MPX and SMB_COM_WRITE_MPX
|
||||||
|
mpx_mode : bool;
|
||||||
|
## The server supports unicode strings
|
||||||
|
unicode : bool;
|
||||||
|
## The server supports large files with 64 bit offsets
|
||||||
|
large_files : bool;
|
||||||
|
## The server supports the SMBs particilar to the NT LM 0.12 dialect. Implies nt_find.
|
||||||
|
nt_smbs : bool;
|
||||||
|
|
||||||
|
## The server supports remote admin API requests via DCE-RPC
|
||||||
|
rpc_remote_apis : bool;
|
||||||
|
## The server can respond with 32 bit status codes in Status.Status
|
||||||
|
status32 : bool;
|
||||||
|
## The server supports level 2 oplocks
|
||||||
|
level_2_oplocks : bool;
|
||||||
|
## The server supports SMB_COM_LOCK_AND_READ
|
||||||
|
lock_and_read : bool;
|
||||||
|
## Reserved
|
||||||
|
nt_find : bool;
|
||||||
|
|
||||||
|
## The server is DFS aware
|
||||||
|
dfs : bool;
|
||||||
|
## The server supports NT information level requests passing through
|
||||||
|
infolevel_passthru : bool;
|
||||||
|
## The server supports large SMB_COM_READ_ANDX (up to 64k)
|
||||||
|
large_readx : bool;
|
||||||
|
## The server supports large SMB_COM_WRITE_ANDX (up to 64k)
|
||||||
|
large_writex : bool;
|
||||||
|
## The server supports CIFS Extensions for UNIX
|
||||||
|
unix : bool;
|
||||||
|
|
||||||
|
## The server supports SMB_BULK_READ, SMB_BULK_WRITE
|
||||||
|
## Note: No known implementations support this
|
||||||
|
bulk_transfer : bool;
|
||||||
|
## The server supports compressed data transfer. Requires bulk_transfer.
|
||||||
|
## Note: No known implementations support this
|
||||||
|
compressed_data : bool;
|
||||||
|
## The server supports extended security exchanges
|
||||||
|
extended_security : bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateResponseSecurity: record {
|
||||||
|
## This indicates whether the server, as a whole, is operating under
|
||||||
|
## Share Level or User Level security.
|
||||||
|
user_level : bool;
|
||||||
|
## This indicates whether or not the server supports Challenge/Response
|
||||||
|
## authentication. If the bit is false, then plaintext passwords must
|
||||||
|
## be used.
|
||||||
|
challenge_response: bool;
|
||||||
|
## This indicates if the server is capable of performing MAC message
|
||||||
|
## signing. Note: Requires NT LM 0.12 or later.
|
||||||
|
signatures_enabled: bool &optional;
|
||||||
|
## This indicates if the server is requiring the use of a MAC in each
|
||||||
|
## packet. If false, message signing is optional. Note: Requires NT LM 0.12
|
||||||
|
## or later.
|
||||||
|
signatures_required: bool &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateResponseCore: record {
|
||||||
|
## Index of selected dialect
|
||||||
|
dialect_index : count;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateResponseLANMAN: record {
|
||||||
|
## Count of parameter words (should be 13)
|
||||||
|
word_count : count;
|
||||||
|
## Index of selected dialect
|
||||||
|
dialect_index : count;
|
||||||
|
## Security mode
|
||||||
|
security_mode : SMB1::NegotiateResponseSecurity;
|
||||||
|
## Max transmit buffer size (>= 1024)
|
||||||
|
max_buffer_size : count;
|
||||||
|
## Max pending multiplexed requests
|
||||||
|
max_mpx_count : count;
|
||||||
|
|
||||||
|
## Max number of virtual circuits (VCs - transport-layer connections)
|
||||||
|
## between client and server
|
||||||
|
max_number_vcs : count;
|
||||||
|
## Raw mode
|
||||||
|
raw_mode : SMB1::NegotiateRawMode;
|
||||||
|
## Unique token identifying this session
|
||||||
|
session_key : count;
|
||||||
|
## Current date and time at server
|
||||||
|
server_time : time;
|
||||||
|
## The challenge encryption key
|
||||||
|
encryption_key : string;
|
||||||
|
|
||||||
|
## The server's primary domain
|
||||||
|
primary_domain : string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateResponseNTLM: record {
|
||||||
|
## Count of parameter words (should be 17)
|
||||||
|
word_count : count;
|
||||||
|
## Index of selected dialect
|
||||||
|
dialect_index : count;
|
||||||
|
## Security mode
|
||||||
|
security_mode : SMB1::NegotiateResponseSecurity;
|
||||||
|
## Max transmit buffer size
|
||||||
|
max_buffer_size : count;
|
||||||
|
## Max pending multiplexed requests
|
||||||
|
max_mpx_count : count;
|
||||||
|
|
||||||
|
## Max number of virtual circuits (VCs - transport-layer connections)
|
||||||
|
## between client and server
|
||||||
|
max_number_vcs : count;
|
||||||
|
## Max raw buffer size
|
||||||
|
max_raw_size : count;
|
||||||
|
## Unique token identifying this session
|
||||||
|
session_key : count;
|
||||||
|
## Server capabilities
|
||||||
|
capabilities : SMB1::NegotiateCapabilities;
|
||||||
|
## Current date and time at server
|
||||||
|
server_time : time;
|
||||||
|
|
||||||
|
## The challenge encryption key.
|
||||||
|
## Present only for non-extended security (i.e. capabilities$extended_security = F)
|
||||||
|
encryption_key : string &optional;
|
||||||
|
## The name of the domain.
|
||||||
|
## Present only for non-extended security (i.e. capabilities$extended_security = F)
|
||||||
|
domain_name : string &optional;
|
||||||
|
## A globally unique identifier assigned to the server.
|
||||||
|
## Present only for extended security (i.e. capabilities$extended_security = T)
|
||||||
|
guid : string &optional;
|
||||||
|
## Opaque security blob associated with the security package if capabilities$extended_security = T
|
||||||
|
## Otherwise, the challenge for challenge/response authentication.
|
||||||
|
security_blob : string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::NegotiateResponse: record {
|
||||||
|
## If the server does not understand any of the dialect strings, or if
|
||||||
|
## PC NETWORK PROGRAM 1.0 is the chosen dialect.
|
||||||
|
core : SMB1::NegotiateResponseCore &optional;
|
||||||
|
## If the chosen dialect is greater than core up to and including
|
||||||
|
## LANMAN 2.1.
|
||||||
|
lanman : SMB1::NegotiateResponseLANMAN &optional;
|
||||||
|
## If the chosen dialect is NT LM 0.12.
|
||||||
|
ntlm : SMB1::NegotiateResponseNTLM &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::SessionSetupAndXCapabilities: record {
|
||||||
|
## The client can use unicode strings
|
||||||
|
unicode : bool;
|
||||||
|
## The client can deal with files having 64 bit offsets
|
||||||
|
large_files : bool;
|
||||||
|
## The client understands the SMBs introduced with NT LM 0.12
|
||||||
|
## Implies nt_find
|
||||||
|
nt_smbs : bool;
|
||||||
|
## The client can receive 32 bit errors encoded in Status.Status
|
||||||
|
status32 : bool;
|
||||||
|
## The client understands Level II oplocks
|
||||||
|
level_2_oplocks : bool;
|
||||||
|
## Reserved. Implied by nt_smbs.
|
||||||
|
nt_find : bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::SessionSetupAndXRequest: record {
|
||||||
|
## Count of parameter words
|
||||||
|
## - 10 for pre NT LM 0.12
|
||||||
|
## - 12 for NT LM 0.12 with extended security
|
||||||
|
## - 13 for NT LM 0.12 without extended security
|
||||||
|
word_count : count;
|
||||||
|
## Client maximum buffer size
|
||||||
|
max_buffer_size : count;
|
||||||
|
## Actual maximum multiplexed pending request
|
||||||
|
max_mpx_count : count;
|
||||||
|
## Virtual circuit number. First VC == 0
|
||||||
|
vc_number : count;
|
||||||
|
## Session key (valid iff vc_number > 0)
|
||||||
|
session_key : count;
|
||||||
|
|
||||||
|
## Client's native operating system
|
||||||
|
native_os : string;
|
||||||
|
## Client's native LAN Manager type
|
||||||
|
native_lanman : string;
|
||||||
|
## Account name
|
||||||
|
## Note: not set for NT LM 0.12 with extended security
|
||||||
|
account_name : string &optional;
|
||||||
|
## If challenge/response auth is not being used, this is the password.
|
||||||
|
## Otherwise, it's the response to the server's challenge.
|
||||||
|
## Note: Only set for pre NT LM 0.12
|
||||||
|
account_password : string &optional;
|
||||||
|
## Client's primary domain, if known
|
||||||
|
## Note: not set for NT LM 0.12 with extended security
|
||||||
|
primary_domain : string &optional;
|
||||||
|
|
||||||
|
## Case insensitive password
|
||||||
|
## Note: only set for NT LM 0.12 without extended security
|
||||||
|
case_insensitive_password : string &optional;
|
||||||
|
## Case sensitive password
|
||||||
|
## Note: only set for NT LM 0.12 without extended security
|
||||||
|
case_sensitive_password : string &optional;
|
||||||
|
## Security blob
|
||||||
|
## Note: only set for NT LM 0.12 with extended security
|
||||||
|
security_blob : string &optional;
|
||||||
|
## Client capabilities
|
||||||
|
## Note: only set for NT LM 0.12
|
||||||
|
capabilities : SMB1::SessionSetupAndXCapabilities &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::SessionSetupAndXResponse: record {
|
||||||
|
## Count of parameter words (should be 3 for pre NT LM 0.12 and 4 for NT LM 0.12)
|
||||||
|
word_count : count;
|
||||||
|
## Were we logged in as a guest user?
|
||||||
|
is_guest : bool &optional;
|
||||||
|
## Server's native operating system
|
||||||
|
native_os : string &optional;
|
||||||
|
## Server's native LAN Manager type
|
||||||
|
native_lanman : string &optional;
|
||||||
|
## Server's primary domain
|
||||||
|
primary_domain : string &optional;
|
||||||
|
## Security blob if NTLM
|
||||||
|
security_blob : string &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::Find_First2_Request_Args: record {
|
||||||
|
## File attributes to apply as a constraint to the search
|
||||||
|
search_attrs : count;
|
||||||
|
## Max search results
|
||||||
|
search_count : count;
|
||||||
|
## Misc. flags for how the server should manage the transaction
|
||||||
|
## once results are returned
|
||||||
|
flags : count;
|
||||||
|
## How detailed the information returned in the results should be
|
||||||
|
info_level : count;
|
||||||
|
## Specify whether to search for directories or files
|
||||||
|
search_storage_type : count;
|
||||||
|
## The string to serch for (note: may contain wildcards)
|
||||||
|
file_name : string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1::Find_First2_Response_Args: record {
|
||||||
|
## The server generated search identifier
|
||||||
|
sid : count;
|
||||||
|
## Number of results returned by the search
|
||||||
|
search_count : count;
|
||||||
|
## Whether or not the search can be continued using
|
||||||
|
## the TRANS2_FIND_NEXT2 transaction
|
||||||
|
end_of_search : bool;
|
||||||
|
## An extended attribute name that couldn't be retrieved
|
||||||
|
ext_attr_error : string &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
## SMB transaction data.
|
}
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2
|
|
||||||
##
|
|
||||||
## .. todo:: Should this really be a record type?
|
|
||||||
type smb_trans_data : record {
|
|
||||||
data : string; ##< The transaction's data.
|
|
||||||
};
|
|
||||||
|
|
||||||
## Deprecated.
|
module SMB2;
|
||||||
##
|
|
||||||
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere
|
|
||||||
## else.
|
|
||||||
type smb_tree_connect : record {
|
|
||||||
flags: count;
|
|
||||||
password: string;
|
|
||||||
path: string;
|
|
||||||
service: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
## Deprecated.
|
export {
|
||||||
##
|
type SMB2::Header: record {
|
||||||
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere
|
credit_charge: count;
|
||||||
## else.
|
status: count;
|
||||||
type smb_negotiate : table[count] of string;
|
command: count;
|
||||||
|
credits: count;
|
||||||
|
flags: count;
|
||||||
|
message_id: count;
|
||||||
|
process_id: count;
|
||||||
|
tree_id: count;
|
||||||
|
session_id: count;
|
||||||
|
signature: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::GUID: record {
|
||||||
|
persistent: count;
|
||||||
|
volatile: count;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::FileAttrs: record {
|
||||||
|
read_only: bool;
|
||||||
|
hidden: bool;
|
||||||
|
system: bool;
|
||||||
|
directory: bool;
|
||||||
|
archive: bool;
|
||||||
|
normal: bool;
|
||||||
|
temporary: bool;
|
||||||
|
sparse_file: bool;
|
||||||
|
reparse_point: bool;
|
||||||
|
compressed: bool;
|
||||||
|
offline: bool;
|
||||||
|
not_content_indexed: bool;
|
||||||
|
encrypted: bool;
|
||||||
|
integrity_stream: bool;
|
||||||
|
no_scrub_data: bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::CloseResponse: record {
|
||||||
|
alloc_size : count;
|
||||||
|
eof : count;
|
||||||
|
times : SMB::MACTimes;
|
||||||
|
attrs : SMB2::FileAttrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::NegotiateResponse: record {
|
||||||
|
dialect_revision : count;
|
||||||
|
security_mode : count;
|
||||||
|
server_guid : string;
|
||||||
|
system_time : time;
|
||||||
|
server_start_time : time;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::SessionSetupRequest: record {
|
||||||
|
security_mode: count;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::SessionSetupFlags: record {
|
||||||
|
guest: bool;
|
||||||
|
anonymous: bool;
|
||||||
|
encrypt: bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::SessionSetupResponse: record {
|
||||||
|
flags: SMB2::SessionSetupFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::SetInfoRequest: record {
|
||||||
|
eof: count;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2::TreeConnectResponse: record {
|
||||||
|
share_type: count;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module GLOBAL;
|
||||||
|
|
||||||
## A list of router addresses offered by a DHCP server.
|
## A list of router addresses offered by a DHCP server.
|
||||||
##
|
##
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
@load base/frameworks/netcontrol
|
@load base/frameworks/netcontrol
|
||||||
|
|
||||||
@load base/protocols/conn
|
@load base/protocols/conn
|
||||||
|
@load base/protocols/dce-rpc
|
||||||
@load base/protocols/dhcp
|
@load base/protocols/dhcp
|
||||||
@load base/protocols/dnp3
|
@load base/protocols/dnp3
|
||||||
@load base/protocols/dns
|
@load base/protocols/dns
|
||||||
|
@ -53,12 +54,16 @@
|
||||||
@load base/protocols/krb
|
@load base/protocols/krb
|
||||||
@load base/protocols/modbus
|
@load base/protocols/modbus
|
||||||
@load base/protocols/mysql
|
@load base/protocols/mysql
|
||||||
|
@load base/protocols/ntlm
|
||||||
@load base/protocols/pop3
|
@load base/protocols/pop3
|
||||||
@load base/protocols/radius
|
@load base/protocols/radius
|
||||||
@load base/protocols/rdp
|
@load base/protocols/rdp
|
||||||
@load base/protocols/rfb
|
@load base/protocols/rfb
|
||||||
@load base/protocols/sip
|
@load base/protocols/sip
|
||||||
@load base/protocols/snmp
|
@load base/protocols/snmp
|
||||||
|
# This DOES NOT enable the SMB analyzer. It's just some base support
|
||||||
|
# for other protocols.
|
||||||
|
@load base/protocols/smb
|
||||||
@load base/protocols/smtp
|
@load base/protocols/smtp
|
||||||
@load base/protocols/socks
|
@load base/protocols/socks
|
||||||
@load base/protocols/ssh
|
@load base/protocols/ssh
|
||||||
|
|
4
scripts/base/protocols/dce-rpc/__load__.bro
Normal file
4
scripts/base/protocols/dce-rpc/__load__.bro
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
@load ./consts
|
||||||
|
@load ./main
|
||||||
|
|
||||||
|
@load-sigs ./dpd.sig
|
1496
scripts/base/protocols/dce-rpc/consts.bro
Normal file
1496
scripts/base/protocols/dce-rpc/consts.bro
Normal file
File diff suppressed because it is too large
Load diff
6
scripts/base/protocols/dce-rpc/dpd.sig
Normal file
6
scripts/base/protocols/dce-rpc/dpd.sig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
signature dpd_dce_rpc {
|
||||||
|
ip-proto == tcp
|
||||||
|
payload /^\x05[\x00\x01][\x00-\x13]\x03/
|
||||||
|
enable "DCE_RPC"
|
||||||
|
}
|
204
scripts/base/protocols/dce-rpc/main.bro
Normal file
204
scripts/base/protocols/dce-rpc/main.bro
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
@load ./consts
|
||||||
|
|
||||||
|
module DCE_RPC;
|
||||||
|
|
||||||
|
export {
|
||||||
|
redef enum Log::ID += { LOG };
|
||||||
|
|
||||||
|
type Info: record {
|
||||||
|
## Timestamp for when the event happened.
|
||||||
|
ts : time &log;
|
||||||
|
## Unique ID for the connection.
|
||||||
|
uid : string &log;
|
||||||
|
## The connection's 4-tuple of endpoint addresses/ports.
|
||||||
|
id : conn_id &log;
|
||||||
|
## Round trip time from the request to the response.
|
||||||
|
## If either the request or response wasn't seen,
|
||||||
|
## this will be null.
|
||||||
|
rtt : interval &log &optional;
|
||||||
|
|
||||||
|
## Remote pipe name.
|
||||||
|
named_pipe : string &log &optional;
|
||||||
|
## Endpoint name looked up from the uuid.
|
||||||
|
endpoint : string &log &optional;
|
||||||
|
## Operation seen in the call.
|
||||||
|
operation : string &log &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
## These are DCE-RPC operations that are ignored, typically due
|
||||||
|
## the operations being noisy and low valueon most networks.
|
||||||
|
const ignored_operations: table[string] of set[string] = {
|
||||||
|
["winreg"] = set("BaseRegCloseKey", "BaseRegGetVersion", "BaseRegOpenKey", "BaseRegQueryValue", "BaseRegDeleteKeyEx", "OpenLocalMachine", "BaseRegEnumKey", "OpenClassesRoot"),
|
||||||
|
["spoolss"] = set("RpcSplOpenPrinter", "RpcClosePrinter"),
|
||||||
|
["wkssvc"] = set("NetrWkstaGetInfo"),
|
||||||
|
} &redef;
|
||||||
|
}
|
||||||
|
|
||||||
|
type State: record {
|
||||||
|
uuid : string &optional;
|
||||||
|
named_pipe : string &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
# This is to store the log and state information
|
||||||
|
# for multiple DCE/RPC bindings over a single TCP connection (named pipes).
|
||||||
|
type BackingState: record {
|
||||||
|
info: Info;
|
||||||
|
state: State;
|
||||||
|
};
|
||||||
|
|
||||||
|
redef record connection += {
|
||||||
|
dce_rpc: Info &optional;
|
||||||
|
dce_rpc_state: State &optional;
|
||||||
|
dce_rpc_backing: table[count] of BackingState &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ports = { 135/tcp };
|
||||||
|
redef likely_server_ports += { ports };
|
||||||
|
|
||||||
|
event bro_init() &priority=5
|
||||||
|
{
|
||||||
|
Log::create_stream(DCE_RPC::LOG, [$columns=Info, $path="dce_rpc"]);
|
||||||
|
Analyzer::register_for_ports(Analyzer::ANALYZER_DCE_RPC, ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalize_named_pipe_name(pn: string): string
|
||||||
|
{
|
||||||
|
local parts = split_string(pn, /\\[pP][iI][pP][eE]\\/);
|
||||||
|
if ( 1 in parts )
|
||||||
|
return to_lower(parts[1]);
|
||||||
|
else
|
||||||
|
return to_lower(pn);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_state(c: connection, state_x: BackingState)
|
||||||
|
{
|
||||||
|
c$dce_rpc = state_x$info;
|
||||||
|
c$dce_rpc_state = state_x$state;
|
||||||
|
|
||||||
|
if ( c$dce_rpc_state?$uuid )
|
||||||
|
c$dce_rpc$endpoint = uuid_endpoint_map[c$dce_rpc_state$uuid];
|
||||||
|
if ( c$dce_rpc_state?$named_pipe )
|
||||||
|
c$dce_rpc$named_pipe = c$dce_rpc_state$named_pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_session(c: connection, fid: count)
|
||||||
|
{
|
||||||
|
if ( ! c?$dce_rpc_backing )
|
||||||
|
{
|
||||||
|
c$dce_rpc_backing = table();
|
||||||
|
}
|
||||||
|
if ( fid !in c$dce_rpc_backing )
|
||||||
|
{
|
||||||
|
local info = Info($ts=network_time(),$id=c$id,$uid=c$uid);
|
||||||
|
c$dce_rpc_backing[fid] = BackingState($info=info, $state=State());
|
||||||
|
}
|
||||||
|
|
||||||
|
local state_x = c$dce_rpc_backing[fid];
|
||||||
|
set_state(c, state_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
event dce_rpc_bind(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count) &priority=5
|
||||||
|
{
|
||||||
|
set_session(c, fid);
|
||||||
|
|
||||||
|
local uuid_str = uuid_to_string(uuid);
|
||||||
|
c$dce_rpc_state$uuid = uuid_str;
|
||||||
|
c$dce_rpc$endpoint = uuid_endpoint_map[uuid_str];
|
||||||
|
}
|
||||||
|
|
||||||
|
event dce_rpc_bind_ack(c: connection, fid: count, sec_addr: string) &priority=5
|
||||||
|
{
|
||||||
|
set_session(c, fid);
|
||||||
|
|
||||||
|
if ( sec_addr != "" )
|
||||||
|
{
|
||||||
|
c$dce_rpc_state$named_pipe = sec_addr;
|
||||||
|
c$dce_rpc$named_pipe = sec_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) &priority=5
|
||||||
|
{
|
||||||
|
set_session(c, fid);
|
||||||
|
|
||||||
|
if ( c?$dce_rpc )
|
||||||
|
{
|
||||||
|
c$dce_rpc$ts = network_time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=5
|
||||||
|
{
|
||||||
|
set_session(c, fid);
|
||||||
|
|
||||||
|
# In the event that the binding wasn't seen, but the pipe
|
||||||
|
# name is known, go ahead and see if we have a pipe name to
|
||||||
|
# uuid mapping...
|
||||||
|
if ( ! c$dce_rpc?$endpoint && c$dce_rpc?$named_pipe )
|
||||||
|
{
|
||||||
|
local npn = normalize_named_pipe_name(c$dce_rpc$named_pipe);
|
||||||
|
if ( npn in pipe_name_to_common_uuid )
|
||||||
|
{
|
||||||
|
c$dce_rpc_state$uuid = pipe_name_to_common_uuid[npn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( c?$dce_rpc && c$dce_rpc?$endpoint )
|
||||||
|
{
|
||||||
|
c$dce_rpc$operation = operations[c$dce_rpc_state$uuid, opnum];
|
||||||
|
if ( c$dce_rpc$ts != network_time() )
|
||||||
|
c$dce_rpc$rtt = network_time() - c$dce_rpc$ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=-5
|
||||||
|
{
|
||||||
|
if ( c?$dce_rpc )
|
||||||
|
{
|
||||||
|
# If there is not an endpoint, there isn't much reason to log.
|
||||||
|
# This can happen if the request isn't seen.
|
||||||
|
if ( (c$dce_rpc?$endpoint && c$dce_rpc$endpoint !in ignored_operations)
|
||||||
|
||
|
||||||
|
(c$dce_rpc?$endpoint && c$dce_rpc?$operation &&
|
||||||
|
c$dce_rpc$operation !in ignored_operations[c$dce_rpc$endpoint] &&
|
||||||
|
"*" !in ignored_operations[c$dce_rpc$endpoint]) )
|
||||||
|
{
|
||||||
|
Log::write(LOG, c$dce_rpc);
|
||||||
|
}
|
||||||
|
delete c$dce_rpc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event connection_state_remove(c: connection)
|
||||||
|
{
|
||||||
|
if ( ! c?$dce_rpc )
|
||||||
|
return;
|
||||||
|
|
||||||
|
# TODO: Go through any remaining dce_rpc requests that haven't been processed with replies.
|
||||||
|
for ( i in c$dce_rpc_backing )
|
||||||
|
{
|
||||||
|
local x = c$dce_rpc_backing[i];
|
||||||
|
set_state(c, x);
|
||||||
|
|
||||||
|
# In the event that the binding wasn't seen, but the pipe
|
||||||
|
# name is known, go ahead and see if we have a pipe name to
|
||||||
|
# uuid mapping...
|
||||||
|
if ( ! c$dce_rpc?$endpoint && c$dce_rpc?$named_pipe )
|
||||||
|
{
|
||||||
|
local npn = normalize_named_pipe_name(c$dce_rpc$named_pipe);
|
||||||
|
if ( npn in pipe_name_to_common_uuid )
|
||||||
|
{
|
||||||
|
c$dce_rpc_state$uuid = pipe_name_to_common_uuid[npn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (c$dce_rpc?$endpoint && c$dce_rpc$endpoint !in ignored_operations)
|
||||||
|
||
|
||||||
|
(c$dce_rpc?$endpoint && c$dce_rpc?$operation &&
|
||||||
|
c$dce_rpc$operation !in ignored_operations[c$dce_rpc$endpoint] &&
|
||||||
|
"*" !in ignored_operations[c$dce_rpc$endpoint]) )
|
||||||
|
{
|
||||||
|
Log::write(LOG, c$dce_rpc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
scripts/base/protocols/ntlm/__load__.bro
Normal file
1
scripts/base/protocols/ntlm/__load__.bro
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@load ./main
|
127
scripts/base/protocols/ntlm/main.bro
Normal file
127
scripts/base/protocols/ntlm/main.bro
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
@load base/protocols/smb
|
||||||
|
|
||||||
|
module NTLM;
|
||||||
|
|
||||||
|
export {
|
||||||
|
redef enum Log::ID += { LOG };
|
||||||
|
|
||||||
|
type Info: record {
|
||||||
|
## Timestamp for when the event happened.
|
||||||
|
ts : time &log;
|
||||||
|
## Unique ID for the connection.
|
||||||
|
uid : string &log;
|
||||||
|
## The connection's 4-tuple of endpoint addresses/ports.
|
||||||
|
id : conn_id &log;
|
||||||
|
|
||||||
|
## Username given by the client.
|
||||||
|
username : string &log &optional;
|
||||||
|
## Hostname given by the client.
|
||||||
|
hostname : string &log &optional;
|
||||||
|
## Domainname given by the client.
|
||||||
|
domainname : string &log &optional;
|
||||||
|
|
||||||
|
## Indicate whether or not the authentication was successful.
|
||||||
|
success : bool &log &optional;
|
||||||
|
## A string representation of the status code that was
|
||||||
|
## returned in response to the authentication attempt.
|
||||||
|
status : string &log &optional;
|
||||||
|
|
||||||
|
## Internally used field to indicate if the login attempt
|
||||||
|
## has already been logged.
|
||||||
|
done: bool &default=F;
|
||||||
|
};
|
||||||
|
|
||||||
|
## DOS and NT status codes that indicate authentication failure.
|
||||||
|
const auth_failure_statuses: set[count] = {
|
||||||
|
0x052e0001, # logonfailure
|
||||||
|
0x08c00002, # badClient
|
||||||
|
0x08c10002, # badLogonTime
|
||||||
|
0x08c20002, # passwordExpired
|
||||||
|
0xC0000022, # ACCESS_DENIED
|
||||||
|
0xC000006A, # WRONG_PASSWORD
|
||||||
|
0xC000006F, # INVALID_LOGON_HOURS
|
||||||
|
0xC0000070, # INVALID_WORKSTATION
|
||||||
|
0xC0000071, # PASSWORD_EXPIRED
|
||||||
|
0xC0000072, # ACCOUNT_DISABLED
|
||||||
|
} &redef;
|
||||||
|
}
|
||||||
|
|
||||||
|
redef record connection += {
|
||||||
|
ntlm: Info &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
event bro_init() &priority=5
|
||||||
|
{
|
||||||
|
Log::create_stream(NTLM::LOG, [$columns=Info, $path="ntlm"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
event ntlm_negotiate(c: connection, request: NTLM::Negotiate) &priority=5
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
event ntlm_challenge(c: connection, challenge: NTLM::Challenge) &priority=5
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
event ntlm_authenticate(c: connection, request: NTLM::Authenticate) &priority=5
|
||||||
|
{
|
||||||
|
c$ntlm = NTLM::Info($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
if ( request?$domain_name )
|
||||||
|
c$ntlm$domainname = request$domain_name;
|
||||||
|
if ( request?$workstation )
|
||||||
|
c$ntlm$hostname = request$workstation;
|
||||||
|
if ( request?$user_name )
|
||||||
|
c$ntlm$username = request$user_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event gssapi_neg_result(c: connection, state: count) &priority=3
|
||||||
|
{
|
||||||
|
if ( c?$ntlm )
|
||||||
|
c$ntlm$success = (state == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
event gssapi_neg_result(c: connection, state: count) &priority=-3
|
||||||
|
{
|
||||||
|
if ( c?$ntlm && ! c$ntlm$done )
|
||||||
|
{
|
||||||
|
if ( c$ntlm?$username || c$ntlm?$hostname )
|
||||||
|
{
|
||||||
|
Log::write(NTLM::LOG, c$ntlm);
|
||||||
|
c$ntlm$done = T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=3
|
||||||
|
{
|
||||||
|
if ( c?$ntlm && ! c$ntlm$done &&
|
||||||
|
( c$ntlm?$username || c$ntlm?$hostname ) )
|
||||||
|
{
|
||||||
|
c$ntlm$success = (hdr$status !in auth_failure_statuses);
|
||||||
|
c$ntlm$status = SMB::statuses[hdr$status]$id;
|
||||||
|
|
||||||
|
Log::write(NTLM::LOG, c$ntlm);
|
||||||
|
c$ntlm$done = T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=3
|
||||||
|
{
|
||||||
|
if ( c?$ntlm && ! c$ntlm$done &&
|
||||||
|
( c$ntlm?$username || c$ntlm?$hostname ) )
|
||||||
|
{
|
||||||
|
c$ntlm$success = (hdr$status !in auth_failure_statuses);
|
||||||
|
c$ntlm$status = SMB::statuses[hdr$status]$id;
|
||||||
|
|
||||||
|
Log::write(NTLM::LOG, c$ntlm);
|
||||||
|
c$ntlm$done = T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event connection_state_remove(c: connection) &priority=-5
|
||||||
|
{
|
||||||
|
if ( c?$ntlm && ! c$ntlm$done )
|
||||||
|
{
|
||||||
|
Log::write(NTLM::LOG, c$ntlm);
|
||||||
|
}
|
||||||
|
}
|
3
scripts/base/protocols/smb/__load__.bro
Normal file
3
scripts/base/protocols/smb/__load__.bro
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@load ./consts
|
||||||
|
@load ./const-dos-error
|
||||||
|
@load ./const-nt-status
|
132
scripts/base/protocols/smb/const-dos-error.bro
Normal file
132
scripts/base/protocols/smb/const-dos-error.bro
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
# DOS error codes.
|
||||||
|
@load ./consts
|
||||||
|
|
||||||
|
module SMB;
|
||||||
|
|
||||||
|
redef SMB::statuses += {
|
||||||
|
[0x00010001] = [$id="badfunc", $desc="Incorrect function."],
|
||||||
|
[0x00010002] = [$id="error", $desc="Incorrect function."],
|
||||||
|
[0x00020001] = [$id="badfile", $desc="The system cannot find the file specified."],
|
||||||
|
[0x00020002] = [$id="badpw", $desc="Bad password."],
|
||||||
|
[0x00030001] = [$id="badpath", $desc="The system cannot find the path specified."],
|
||||||
|
[0x00030002] = [$id="badtype", $desc="reserved"],
|
||||||
|
[0x00040001] = [$id="nofids", $desc="The system cannot open the file."],
|
||||||
|
[0x00040002] = [$id="access", $desc="The client does not have the necessary access rights to perform the requested function."],
|
||||||
|
[0x00050001] = [$id="noaccess", $desc="Access is denied."],
|
||||||
|
[0x00050002] = [$id="invnid", $desc="The TID specified was invalid."],
|
||||||
|
[0x00060001] = [$id="badfid", $desc="The handle is invalid."],
|
||||||
|
[0x00060002] = [$id="invnetname", $desc="The network name cannot be found."],
|
||||||
|
[0x00070001] = [$id="badmcb", $desc="The storage control blocks were destroyed."],
|
||||||
|
[0x00070002] = [$id="invdevice", $desc="The device specified is invalid."],
|
||||||
|
[0x00080001] = [$id="nomem", $desc="Not enough storage is available to process this command."],
|
||||||
|
[0x00090001] = [$id="badmem", $desc="The storage control block address is invalid."],
|
||||||
|
[0x000a0001] = [$id="badenv", $desc="The environment is incorrect."],
|
||||||
|
[0x000c0001] = [$id="badaccess", $desc="The access code is invalid."],
|
||||||
|
[0x000d0001] = [$id="baddata", $desc="The data is invalid."],
|
||||||
|
[0x000e0001] = [$id="res", $desc="reserved"],
|
||||||
|
[0x000f0001] = [$id="baddrive", $desc="The system cannot find the drive specified."],
|
||||||
|
[0x00100001] = [$id="remcd", $desc="The directory cannot be removed."],
|
||||||
|
[0x00110001] = [$id="diffdevice", $desc="The system cannot move the file to a different disk drive."],
|
||||||
|
[0x00120001] = [$id="nofiles", $desc="There are no more files."],
|
||||||
|
[0x00130003] = [$id="nowrite", $desc="The media is write protected."],
|
||||||
|
[0x00140003] = [$id="badunit", $desc="The system cannot find the device specified."],
|
||||||
|
[0x00150003] = [$id="notready", $desc="The device is not ready."],
|
||||||
|
[0x00160002] = [$id="unknownsmb", $desc="The device does not recognize the command."],
|
||||||
|
[0x00160003] = [$id="badcmd", $desc="The device does not recognize the command."],
|
||||||
|
[0x00170003] = [$id="data", $desc="Data error (cyclic redundancy check)."],
|
||||||
|
[0x00180003] = [$id="badreq", $desc="The program issued a command but the command length is incorrect."],
|
||||||
|
[0x00190003] = [$id="seek", $desc="The drive cannot locate a specific area or track on the disk."],
|
||||||
|
[0x001a0003] = [$id="badmedia", $desc="The specified disk or diskette cannot be accessed."],
|
||||||
|
[0x001b0003] = [$id="badsector", $desc="The drive cannot find the sector requested."],
|
||||||
|
[0x001c0003] = [$id="nopaper", $desc="The printer is out of paper."],
|
||||||
|
[0x001d0003] = [$id="write", $desc="The system cannot write to the specified device."],
|
||||||
|
[0x001e0003] = [$id="read", $desc="The system cannot read from the specified device."],
|
||||||
|
[0x001f0001] = [$id="general", $desc="A device attached to the system is not functioning."],
|
||||||
|
[0x001f0003] = [$id="general", $desc="A device attached to the system is not functioning."],
|
||||||
|
[0x00200001] = [$id="badshare", $desc="The process cannot access the file because it is being used by another process."],
|
||||||
|
[0x00200003] = [$id="badshare", $desc="The process cannot access the file because it is being used by another process."],
|
||||||
|
[0x00210001] = [$id="lock", $desc="The process cannot access the file because another process has locked a portion of the file."],
|
||||||
|
[0x00210003] = [$id="lock", $desc="The process cannot access the file because another process has locked a portion of the file."],
|
||||||
|
[0x00220003] = [$id="wrongdisk", $desc="The wrong diskette is in the drive."],
|
||||||
|
[0x00230003] = [$id="FCBunavail", $desc="No FCBs are available to process the request."],
|
||||||
|
[0x00240003] = [$id="sharebufexc", $desc="A sharing buffer has been exceeded."],
|
||||||
|
[0x00270003] = [$id="diskfull", $desc="The disk is full."],
|
||||||
|
[0x00310002] = [$id="qfull", $desc="The print queue is full."],
|
||||||
|
[0x00320001] = [$id="unsup", $desc="The network request is not supported."],
|
||||||
|
[0x00320002] = [$id="qtoobig", $desc="The queued item too big."],
|
||||||
|
[0x00340002] = [$id="invpfid", $desc="The print file FID is invalid."],
|
||||||
|
[0x00340001] = [$id="dupname", $desc="A duplicate name exists on the network."],
|
||||||
|
[0x00400001] = [$id="netnamedel", $desc="The specified network name is no longer available."],
|
||||||
|
[0x00400002] = [$id="smbcmd", $desc="The server did not recognize the command received."],
|
||||||
|
[0x00410002] = [$id="srverror", $desc="The server encountered an internal error."],
|
||||||
|
[0x00420001] = [$id="noipc", $desc="The network resource type is not correct."],
|
||||||
|
[0x00430001] = [$id="nosuchshare", $desc="The network name cannot be found."],
|
||||||
|
[0x00430002] = [$id="filespecs", $desc="The specified FID and pathname combination is invalid."],
|
||||||
|
[0x00440002] = [$id="badlink", $desc="reserved"],
|
||||||
|
[0x00450002] = [$id="badpermits", $desc="The access permissions specified for a file or directory are not a valid combination."],
|
||||||
|
[0x00460002] = [$id="badpid", $desc="reserved"],
|
||||||
|
[0x00470001] = [$id="nomoreconn", $desc="nomoreconn."],
|
||||||
|
[0x00470002] = [$id="setattrmode", $desc="The attribute mode specified is invalid."],
|
||||||
|
[0x00500001] = [$id="filexists", $desc="The file exists."],
|
||||||
|
[0x00510002] = [$id="paused", $desc="The message server is paused."],
|
||||||
|
[0x00520002] = [$id="msgoff", $desc="Not receiving messages."],
|
||||||
|
[0x00530002] = [$id="noroom", $desc="No room to buffer message."],
|
||||||
|
[0x00570001] = [$id="invalidparam", $desc="The parameter is incorrect."],
|
||||||
|
[0x00570002] = [$id="rmuns", $desc="Too many remote usernames."],
|
||||||
|
[0x00580002] = [$id="timeout", $desc="Operation timed out."],
|
||||||
|
[0x00590002] = [$id="noresource", $desc="No resources currently available for request."],
|
||||||
|
[0x005a0002] = [$id="toomanyuids", $desc="Too many Uids active on this session."],
|
||||||
|
[0x005b0002] = [$id="baduid", $desc="The Uid is not known as a valid user identifier on this session."],
|
||||||
|
[0x006d0001] = [$id="brokenpipe", $desc="The pipe has been ended."],
|
||||||
|
[0x006e0001] = [$id="cannotopen", $desc="The system cannot open the device or file specified."],
|
||||||
|
[0x007a0001] = [$id="insufficientbuffer", $desc="The data area passed to a system call is too small."],
|
||||||
|
[0x007b0001] = [$id="invalidname", $desc="The filename, directory name, or volume label syntax is incorrect."],
|
||||||
|
[0x007c0001] = [$id="unknownlevel", $desc="The system call level is not correct."],
|
||||||
|
[0x00910001] = [$id="notempty", $desc="The directory is not empty."],
|
||||||
|
[0x009e0001] = [$id="notlocked", $desc="The segment is already unlocked."],
|
||||||
|
[0x00b70001] = [$id="rename", $desc="Cannot create a file when that file already exists."],
|
||||||
|
[0x00e60001] = [$id="badpipe", $desc="The pipe state is invalid."],
|
||||||
|
[0x00e70001] = [$id="pipebusy", $desc="All pipe instances are busy."],
|
||||||
|
[0x00e80001] = [$id="pipeclosing", $desc="The pipe is being closed."],
|
||||||
|
[0x00e90001] = [$id="notconnected", $desc="No process is on the other end of the pipe."],
|
||||||
|
[0x00ea0001] = [$id="moredata", $desc="More data is available."],
|
||||||
|
[0x00fa0002] = [$id="usempx", $desc="Temporarily unable to support Raw, use Mpx mode."],
|
||||||
|
[0x00fb0002] = [$id="usestd", $desc="Temporarily unable to support Raw, use standard read/write."],
|
||||||
|
[0x00fc0002] = [$id="contmpx", $desc="Continue in MPX mode."],
|
||||||
|
[0x00fe0002] = [$id="badPassword", $desc="reserved"],
|
||||||
|
[0x01030001] = [$id="nomoreitems", $desc="No more data is available."],
|
||||||
|
[0x010b0001] = [$id="baddirectory", $desc="The directory name is invalid."],
|
||||||
|
[0x011a0001] = [$id="easnotsupported", $desc="The mounted file system does not support extended attributes."],
|
||||||
|
[0x04000002] = [$id="_NOTIFY_ENUM_DIR", $desc="Too many files have changed since the last time an NT_TRANSACT_NOTIFY_CHANGE was issued."],
|
||||||
|
[0x052e0001] = [$id="logonfailure", $desc="Logon failure: unknown user name or bad password."],
|
||||||
|
[0x07030001] = [$id="driveralreadyinstalled", $desc="The specified printer driver is already installed."],
|
||||||
|
[0x07040001] = [$id="unknownprinterport", $desc="The specified port is unknown."],
|
||||||
|
[0x07050001] = [$id="unknownprinterdriver", $desc="The printer driver is unknown."],
|
||||||
|
[0x07060001] = [$id="unknownprintprocessor", $desc="The print processor is unknown."],
|
||||||
|
[0x07070001] = [$id="invalidseparatorfile", $desc="The specified separator file is invalid."],
|
||||||
|
[0x07080001] = [$id="invalidjobpriority", $desc="The specified priority is invalid."],
|
||||||
|
[0x07090001] = [$id="invalidprintername", $desc="The printer name is invalid."],
|
||||||
|
[0x070a0001] = [$id="printeralreadyexists", $desc="The printer already exists."],
|
||||||
|
[0x070b0001] = [$id="invalidprintercommand", $desc="The printer command is invalid."],
|
||||||
|
[0x070c0001] = [$id="invaliddatatype", $desc="The specified datatype is invalid."],
|
||||||
|
[0x070d0001] = [$id="invalidenvironment", $desc="The Environment specified is invalid."],
|
||||||
|
[0x084b0001] = [$id="buftoosmall", $desc="The API return buffer is too small."],
|
||||||
|
[0x085e0001] = [$id="unknownipc", $desc="The requested API is not supported on the remote server."],
|
||||||
|
[0x08670001] = [$id="nosuchprintjob", $desc="The print job does not exist."],
|
||||||
|
[0x08bf0002] = [$id="accountExpired", $desc="This user account has expired."],
|
||||||
|
[0x08c00002] = [$id="badClient", $desc="The user is not allowed to log on from this workstation."],
|
||||||
|
[0x08c10002] = [$id="badLogonTime", $desc="The user is not allowed to log on at this time."],
|
||||||
|
[0x08c20002] = [$id="passwordExpired", $desc="The password of this user has expired."],
|
||||||
|
[0x09970001] = [$id="invgroup", $desc="invgroup"],
|
||||||
|
[0x0bb80001] = [$id="unknownprintmonitor", $desc="The specified print monitor is unknown."],
|
||||||
|
[0x0bb90001] = [$id="printerdriverinuse", $desc="The specified printer driver is currently in use."],
|
||||||
|
[0x0bba0001] = [$id="spoolfilenotfound", $desc="The spool file was not found."],
|
||||||
|
[0x0bbb0001] = [$id="nostartdoc", $desc="A StartDocPrinter call was not issued."],
|
||||||
|
[0x0bbc0001] = [$id="noaddjob", $desc="An AddJob call was not issued."],
|
||||||
|
[0x0bbd0001] = [$id="printprocessoralreadyinstalled", $desc="The specified print processor has already been installed."],
|
||||||
|
[0x0bbe0001] = [$id="printmonitoralreadyinstalled", $desc="The specified print monitor has already been installed."],
|
||||||
|
[0x0bbf0001] = [$id="invalidprintmonitor", $desc="The specified print monitor does not have the required functions."],
|
||||||
|
[0x0bc00001] = [$id="printmonitorinuse", $desc="The specified print monitor is currently in use."],
|
||||||
|
[0x0bc10001] = [$id="printerhasjobsqueued", $desc="The requested operation is not allowed when there are jobs queued to the printer."],
|
||||||
|
[0xffff0002] = [$id="nosupport", $desc="Function not supported."],
|
||||||
|
};
|
1793
scripts/base/protocols/smb/const-nt-status.bro
Normal file
1793
scripts/base/protocols/smb/const-nt-status.bro
Normal file
File diff suppressed because it is too large
Load diff
271
scripts/base/protocols/smb/consts.bro
Normal file
271
scripts/base/protocols/smb/consts.bro
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
module SMB;
|
||||||
|
|
||||||
|
export {
|
||||||
|
type StatusCode: record {
|
||||||
|
id: string;
|
||||||
|
desc: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statuses: table[count] of StatusCode = {
|
||||||
|
[0x00000000] = [$id="SUCCESS", $desc="The operation completed successfully."],
|
||||||
|
} &redef &default=function(i: count):StatusCode { local unknown=fmt("unknown-%d", i); return [$id=unknown, $desc=unknown]; };
|
||||||
|
|
||||||
|
## These are files names that are used for special
|
||||||
|
## cases by the file system and would not be
|
||||||
|
## considered "normal" files.
|
||||||
|
const pipe_names: set[string] = {
|
||||||
|
"\\netdfs",
|
||||||
|
"\\spoolss",
|
||||||
|
"\\NETLOGON",
|
||||||
|
"\\winreg",
|
||||||
|
"\\lsarpc",
|
||||||
|
"\\samr",
|
||||||
|
"\\srvsvc",
|
||||||
|
"srvsvc",
|
||||||
|
"MsFteWds",
|
||||||
|
"\\wkssvc",
|
||||||
|
};
|
||||||
|
|
||||||
|
## The UUIDs used by the various RPC endpoints
|
||||||
|
const rpc_uuids: table[string] of string = {
|
||||||
|
["4b324fc8-1670-01d3-1278-5a47bf6ee188"] = "Server Service",
|
||||||
|
["6bffd098-a112-3610-9833-46c3f87e345a"] = "Workstation Service",
|
||||||
|
} &redef &default=function(i: string):string { return fmt("unknown-uuid-%s", i); };
|
||||||
|
|
||||||
|
## Server service sub commands
|
||||||
|
const srv_cmds: table[count] of string = {
|
||||||
|
[8] = "NetrConnectionEnum",
|
||||||
|
[9] = "NetrFileEnum",
|
||||||
|
[10] = "NetrFileGetInfo",
|
||||||
|
[11] = "NetrFileClose",
|
||||||
|
[12] = "NetrSessionEnum",
|
||||||
|
[13] = "NetrSessionDel",
|
||||||
|
[14] = "NetrShareAdd",
|
||||||
|
[15] = "NetrShareEnum",
|
||||||
|
[16] = "NetrShareGetInfo",
|
||||||
|
[17] = "NetrShareSetInfo",
|
||||||
|
[18] = "NetrShareDel",
|
||||||
|
[19] = "NetrShareDelSticky",
|
||||||
|
[20] = "NetrShareCheck",
|
||||||
|
[21] = "NetrServerGetInfo",
|
||||||
|
[22] = "NetrServerSetInfo",
|
||||||
|
[23] = "NetrServerDiskEnum",
|
||||||
|
[24] = "NetrServerStatisticsGet",
|
||||||
|
[25] = "NetrServerTransportAdd",
|
||||||
|
[26] = "NetrServerTransportEnum",
|
||||||
|
[27] = "NetrServerTransportDel",
|
||||||
|
[28] = "NetrRemoteTOD",
|
||||||
|
[30] = "NetprPathType",
|
||||||
|
[31] = "NetprPathCanonicalize",
|
||||||
|
[32] = "NetprPathCompare",
|
||||||
|
[33] = "NetprNameValidate",
|
||||||
|
[34] = "NetprNameCanonicalize",
|
||||||
|
[35] = "NetprNameCompare",
|
||||||
|
[36] = "NetrShareEnumSticky",
|
||||||
|
[37] = "NetrShareDelStart",
|
||||||
|
[38] = "NetrShareDelCommit",
|
||||||
|
[39] = "NetrGetFileSecurity",
|
||||||
|
[40] = "NetrSetFileSecurity",
|
||||||
|
[41] = "NetrServerTransportAddEx",
|
||||||
|
[43] = "NetrDfsGetVersion",
|
||||||
|
[44] = "NetrDfsCreateLocalPartition",
|
||||||
|
[45] = "NetrDfsDeleteLocalPartition",
|
||||||
|
[46] = "NetrDfsSetLocalVolumeState",
|
||||||
|
[48] = "NetrDfsCreateExitPoint",
|
||||||
|
[49] = "NetrDfsDeleteExitPoint",
|
||||||
|
[50] = "NetrDfsModifyPrefix",
|
||||||
|
[51] = "NetrDfsFixLocalVolume",
|
||||||
|
[52] = "NetrDfsManagerReportSiteInfo",
|
||||||
|
[53] = "NetrServerTransportDelEx",
|
||||||
|
[54] = "NetrServerAliasAdd",
|
||||||
|
[55] = "NetrServerAliasEnum",
|
||||||
|
[56] = "NetrServerAliasDel",
|
||||||
|
[57] = "NetrShareDelEx",
|
||||||
|
} &redef &default=function(i: count):string { return fmt("unknown-srv-command-%d", i); };
|
||||||
|
|
||||||
|
## Workstation service sub commands
|
||||||
|
const wksta_cmds: table[count] of string = {
|
||||||
|
[0] = "NetrWkstaGetInfo",
|
||||||
|
[1] = "NetrWkstaSetInfo",
|
||||||
|
[2] = "NetrWkstaUserEnum",
|
||||||
|
[5] = "NetrWkstaTransportEnum",
|
||||||
|
[6] = "NetrWkstaTransportAdd",
|
||||||
|
[7] = "NetrWkstaTransportDel",
|
||||||
|
[8] = "NetrUseAdd",
|
||||||
|
[9] = "NetrUseGetInfo",
|
||||||
|
[10] = "NetrUseDel",
|
||||||
|
[11] = "NetrUseEnum",
|
||||||
|
[13] = "NetrWorkstationStatisticsGet",
|
||||||
|
[20] = "NetrGetJoinInformation",
|
||||||
|
[22] = "NetrJoinDomain2",
|
||||||
|
[23] = "NetrUnjoinDomain2",
|
||||||
|
[24] = "NetrRenameMachineInDomain2",
|
||||||
|
[25] = "NetrValidateName2",
|
||||||
|
[26] = "NetrGetJoinableOUs2",
|
||||||
|
[27] = "NetrAddAlternateComputerName",
|
||||||
|
[28] = "NetrRemoveAlternateComputerName",
|
||||||
|
[29] = "NetrSetPrimaryComputerName",
|
||||||
|
[30] = "NetrEnumerateComputerNames",
|
||||||
|
} &redef &default=function(i: count):string { return fmt("unknown-wksta-command-%d", i); };
|
||||||
|
|
||||||
|
type rpc_cmd_table: table[count] of string;
|
||||||
|
|
||||||
|
## The subcommands for RPC endpoints
|
||||||
|
const rpc_sub_cmds: table[string] of rpc_cmd_table = {
|
||||||
|
["4b324fc8-1670-01d3-1278-5a47bf6ee188"] = srv_cmds,
|
||||||
|
["6bffd098-a112-3610-9833-46c3f87e345a"] = wksta_cmds,
|
||||||
|
} &redef &default=function(i: string):rpc_cmd_table { return table() &default=function(j: string):string { return fmt("unknown-uuid-%s", j); }; };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module SMB1;
|
||||||
|
|
||||||
|
export {
|
||||||
|
const commands: table[count] of string = {
|
||||||
|
[0x00] = "CREATE_DIRECTORY",
|
||||||
|
[0x01] = "DELETE_DIRECTORY",
|
||||||
|
[0x02] = "OPEN",
|
||||||
|
[0x03] = "CREATE",
|
||||||
|
[0x04] = "CLOSE",
|
||||||
|
[0x05] = "FLUSH",
|
||||||
|
[0x06] = "DELETE",
|
||||||
|
[0x07] = "RENAME",
|
||||||
|
[0x08] = "QUERY_INFORMATION",
|
||||||
|
[0x09] = "SET_INFORMATION",
|
||||||
|
[0x0A] = "READ",
|
||||||
|
[0x0B] = "WRITE",
|
||||||
|
[0x0C] = "LOCK_BYTE_RANGE",
|
||||||
|
[0x0D] = "UNLOCK_BYTE_RANGE",
|
||||||
|
[0x0E] = "CREATE_TEMPORARY",
|
||||||
|
[0x0F] = "CREATE_NEW",
|
||||||
|
[0x10] = "CHECK_DIRECTORY",
|
||||||
|
[0x11] = "PROCESS_EXIT",
|
||||||
|
[0x12] = "SEEK",
|
||||||
|
[0x13] = "LOCK_AND_READ",
|
||||||
|
[0x14] = "WRITE_AND_UNLOCK",
|
||||||
|
[0x1A] = "READ_RAW",
|
||||||
|
[0x1B] = "READ_MPX",
|
||||||
|
[0x1C] = "READ_MPX_SECONDARY",
|
||||||
|
[0x1D] = "WRITE_RAW",
|
||||||
|
[0x1E] = "WRITE_MPX",
|
||||||
|
[0x1F] = "WRITE_MPX_SECONDARY",
|
||||||
|
[0x20] = "WRITE_COMPLETE",
|
||||||
|
[0x21] = "QUERY_SERVER",
|
||||||
|
[0x22] = "SET_INFORMATION2",
|
||||||
|
[0x23] = "QUERY_INFORMATION2",
|
||||||
|
[0x24] = "LOCKING_ANDX",
|
||||||
|
[0x25] = "TRANSACTION",
|
||||||
|
[0x26] = "TRANSACTION_SECONDARY",
|
||||||
|
[0x27] = "IOCTL",
|
||||||
|
[0x28] = "IOCTL_SECONDARY",
|
||||||
|
[0x29] = "COPY",
|
||||||
|
[0x2A] = "MOVE",
|
||||||
|
[0x2B] = "ECHO",
|
||||||
|
[0x2C] = "WRITE_AND_CLOSE",
|
||||||
|
[0x2D] = "OPEN_ANDX",
|
||||||
|
[0x2E] = "READ_ANDX",
|
||||||
|
[0x2F] = "WRITE_ANDX",
|
||||||
|
[0x30] = "NEW_FILE_SIZE",
|
||||||
|
[0x31] = "CLOSE_AND_TREE_DISC",
|
||||||
|
[0x32] = "TRANSACTION2",
|
||||||
|
[0x33] = "TRANSACTION2_SECONDARY",
|
||||||
|
[0x34] = "FIND_CLOSE2",
|
||||||
|
[0x35] = "FIND_NOTIFY_CLOSE",
|
||||||
|
[0x70] = "TREE_CONNECT",
|
||||||
|
[0x71] = "TREE_DISCONNECT",
|
||||||
|
[0x72] = "NEGOTIATE",
|
||||||
|
[0x73] = "SESSION_SETUP_ANDX",
|
||||||
|
[0x74] = "LOGOFF_ANDX",
|
||||||
|
[0x75] = "TREE_CONNECT_ANDX",
|
||||||
|
[0x80] = "QUERY_INFORMATION_DISK",
|
||||||
|
[0x81] = "SEARCH",
|
||||||
|
[0x82] = "FIND",
|
||||||
|
[0x83] = "FIND_UNIQUE",
|
||||||
|
[0x84] = "FIND_CLOSE",
|
||||||
|
[0xA0] = "NT_TRANSACT",
|
||||||
|
[0xA1] = "NT_TRANSACT_SECONDARY",
|
||||||
|
[0xA2] = "NT_CREATE_ANDX",
|
||||||
|
[0xA4] = "NT_CANCEL",
|
||||||
|
[0xA5] = "NT_RENAME",
|
||||||
|
[0xC0] = "OPEN_PRINT_FILE",
|
||||||
|
[0xC1] = "WRITE_PRINT_FILE",
|
||||||
|
[0xC2] = "CLOSE_PRINT_FILE",
|
||||||
|
[0xC3] = "GET_PRINT_QUEUE",
|
||||||
|
[0xD8] = "READ_BULK",
|
||||||
|
[0xD9] = "WRITE_BULK",
|
||||||
|
[0xDA] = "WRITE_BULK_DATA",
|
||||||
|
} &default=function(i: count):string { return fmt("unknown-%d", i); };
|
||||||
|
|
||||||
|
const trans2_sub_commands: table[count] of string = {
|
||||||
|
[0x00] = "OPEN2",
|
||||||
|
[0x01] = "FIND_FIRST2",
|
||||||
|
[0x02] = "FIND_NEXT2",
|
||||||
|
[0x03] = "QUERY_FS_INFORMATION",
|
||||||
|
[0x04] = "SET_FS_INFORMATION",
|
||||||
|
[0x05] = "QUERY_PATH_INFORMATION",
|
||||||
|
[0x06] = "SET_PATH_INFORMATION",
|
||||||
|
[0x07] = "QUERY_FILE_INFORMATION",
|
||||||
|
[0x08] = "SET_FILE_INFORMATION",
|
||||||
|
[0x09] = "FSCTL",
|
||||||
|
[0x0A] = "IOCTL",
|
||||||
|
[0x0B] = "FIND_NOTIFY_FIRST",
|
||||||
|
[0x0C] = "FIND_NOTIFY_NEXT",
|
||||||
|
[0x0D] = "CREATE_DIRECTORY",
|
||||||
|
[0x0E] = "SESSION_SETUP",
|
||||||
|
[0x10] = "GET_DFS_REFERRAL",
|
||||||
|
[0x11] = "REPORT_DFS_INCONSISTENCY",
|
||||||
|
} &default=function(i: count):string { return fmt("unknown-trans2-sub-cmd-%d", i); };
|
||||||
|
|
||||||
|
const trans_sub_commands: table[count] of string = {
|
||||||
|
[0x01] = "SET_NMPIPE_STATE",
|
||||||
|
[0x11] = "RAW_READ_NMPIPE",
|
||||||
|
[0x21] = "QUERY_NMPIPE_STATE",
|
||||||
|
[0x22] = "QUERY_NMPIPE_INFO",
|
||||||
|
[0x23] = "PEEK_NMPIPE",
|
||||||
|
[0x26] = "TRANSACT_NMPIPE",
|
||||||
|
[0x31] = "RAW_WRITE_NMPIPE",
|
||||||
|
[0x36] = "READ_NMPIPE",
|
||||||
|
[0x37] = "WRITE_NMPIPE",
|
||||||
|
[0x53] = "WAIT_NMPIPE",
|
||||||
|
[0x54] = "CALL_NMPIPE",
|
||||||
|
} &default=function(i: count):string { return fmt("unknown-trans-sub-cmd-%d", i); };
|
||||||
|
}
|
||||||
|
|
||||||
|
module SMB2;
|
||||||
|
|
||||||
|
export {
|
||||||
|
const commands: table[count] of string = {
|
||||||
|
[0] = "NEGOTIATE_PROTOCOL",
|
||||||
|
[1] = "SESSION_SETUP",
|
||||||
|
[2] = "LOGOFF",
|
||||||
|
[3] = "TREE_CONNECT",
|
||||||
|
[4] = "TREE_DISCONNECT",
|
||||||
|
[5] = "CREATE",
|
||||||
|
[6] = "CLOSE",
|
||||||
|
[7] = "FLUSH",
|
||||||
|
[8] = "READ",
|
||||||
|
[9] = "WRITE",
|
||||||
|
[10] = "LOCK",
|
||||||
|
[11] = "IOCTL",
|
||||||
|
[12] = "CANCEL",
|
||||||
|
[13] = "ECHO",
|
||||||
|
[14] = "QUERY_DIRECTORY",
|
||||||
|
[15] = "CHANGE_NOTIFY",
|
||||||
|
[16] = "QUERY_INFO",
|
||||||
|
[17] = "SET_INFO",
|
||||||
|
[18] = "OPLOCK_BREAK"
|
||||||
|
} &default=function(i: count): string { return fmt("unknown-%d", i); };
|
||||||
|
|
||||||
|
const dialects: table[count] of string = {
|
||||||
|
[0x0202] = "2.002",
|
||||||
|
[0x0210] = "2.1",
|
||||||
|
[0x0300] = "3.0",
|
||||||
|
[0x0302] = "3.02",
|
||||||
|
} &default=function(i: count): string { return fmt("unknown-%d", i); };
|
||||||
|
|
||||||
|
const share_types: table[count] of string = {
|
||||||
|
[1] = "DISK",
|
||||||
|
[2] = "PIPE",
|
||||||
|
[3] = "PRINT",
|
||||||
|
} &default=function(i: count): string { return fmt("unknown-%d", i); };
|
||||||
|
}
|
8
scripts/policy/protocols/smb/__load__.bro
Normal file
8
scripts/policy/protocols/smb/__load__.bro
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
@load base/protocols/smb
|
||||||
|
|
||||||
|
@load ./main
|
||||||
|
@load ./smb1-main
|
||||||
|
@load ./smb2-main
|
||||||
|
@load ./files
|
||||||
|
|
||||||
|
@load-sigs ./dpd.sig
|
5
scripts/policy/protocols/smb/dpd.sig
Normal file
5
scripts/policy/protocols/smb/dpd.sig
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
signature dpd_smb {
|
||||||
|
ip-proto == tcp
|
||||||
|
payload /^....[\xfe\xff]SMB/
|
||||||
|
enable "smb"
|
||||||
|
}
|
69
scripts/policy/protocols/smb/files.bro
Normal file
69
scripts/policy/protocols/smb/files.bro
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
@load base/frameworks/files
|
||||||
|
@load ./main
|
||||||
|
|
||||||
|
module SMB;
|
||||||
|
|
||||||
|
export {
|
||||||
|
## Default file handle provider for SMB.
|
||||||
|
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||||
|
|
||||||
|
## Default file describer for SMB.
|
||||||
|
global describe_file: function(f: fa_file): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_file_handle(c: connection, is_orig: bool): string
|
||||||
|
{
|
||||||
|
if ( ! (c$smb_state?$current_file &&
|
||||||
|
(c$smb_state$current_file?$name ||
|
||||||
|
c$smb_state$current_file?$path)) )
|
||||||
|
{
|
||||||
|
# TODO - figure out what are the cases where this happens.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
local current_file = c$smb_state$current_file;
|
||||||
|
local path_name = current_file?$path ? current_file$path : "";
|
||||||
|
local file_name = current_file?$name ? current_file$name : "";
|
||||||
|
# Include last_mod time if available because if a file has been modified it
|
||||||
|
# should be considered a new file.
|
||||||
|
local last_mod = cat(current_file?$times ? current_file$times$modified : double_to_time(0.0));
|
||||||
|
# TODO: This is doing hexdump to avoid problems due to file analysis handling
|
||||||
|
# using CheckString which is not immune to encapsulated null bytes.
|
||||||
|
# This needs to be fixed lower in the file analysis code later.
|
||||||
|
return hexdump(cat(Analyzer::ANALYZER_SMB, c$id$orig_h, c$id$resp_h, path_name, file_name, last_mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
function describe_file(f: fa_file): string
|
||||||
|
{
|
||||||
|
# This shouldn't be needed, but just in case...
|
||||||
|
if ( f$source != "SMB" )
|
||||||
|
return "";
|
||||||
|
|
||||||
|
for ( cid in f$conns )
|
||||||
|
{
|
||||||
|
local info = f$conns[cid];
|
||||||
|
if ( info?$smb_state && info$smb_state?$current_file && info$smb_state$current_file?$name )
|
||||||
|
return info$smb_state$current_file$name;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
event bro_init() &priority=5
|
||||||
|
{
|
||||||
|
Files::register_protocol(Analyzer::ANALYZER_SMB,
|
||||||
|
[$get_file_handle = SMB::get_file_handle,
|
||||||
|
$describe = SMB::describe_file]);
|
||||||
|
}
|
||||||
|
|
||||||
|
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
|
||||||
|
{
|
||||||
|
if ( c?$smb_state && c$smb_state?$current_file )
|
||||||
|
{
|
||||||
|
c$smb_state$current_file$fuid = f$id;
|
||||||
|
|
||||||
|
if ( c$smb_state$current_file$size > 0 )
|
||||||
|
f$total_bytes = c$smb_state$current_file$size;
|
||||||
|
|
||||||
|
if ( c$smb_state$current_file?$name )
|
||||||
|
f$info$filename = c$smb_state$current_file$name;
|
||||||
|
}
|
||||||
|
}
|
269
scripts/policy/protocols/smb/main.bro
Normal file
269
scripts/policy/protocols/smb/main.bro
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
@load base/protocols/smb
|
||||||
|
|
||||||
|
module SMB;
|
||||||
|
|
||||||
|
export {
|
||||||
|
redef enum Log::ID += {
|
||||||
|
CMD_LOG,
|
||||||
|
AUTH_LOG,
|
||||||
|
MAPPING_LOG,
|
||||||
|
FILES_LOG
|
||||||
|
};
|
||||||
|
|
||||||
|
## Abstracted actions for SMB file actions.
|
||||||
|
type Action: enum {
|
||||||
|
FILE_READ,
|
||||||
|
FILE_WRITE,
|
||||||
|
FILE_OPEN,
|
||||||
|
FILE_CLOSE,
|
||||||
|
FILE_DELETE,
|
||||||
|
FILE_RENAME,
|
||||||
|
|
||||||
|
PIPE_READ,
|
||||||
|
PIPE_WRITE,
|
||||||
|
PIPE_OPEN,
|
||||||
|
PIPE_CLOSE,
|
||||||
|
|
||||||
|
PRINT_READ,
|
||||||
|
PRINT_WRITE,
|
||||||
|
PRINT_OPEN,
|
||||||
|
PRINT_CLOSE,
|
||||||
|
|
||||||
|
UNKNOWN_READ,
|
||||||
|
UNKNOWN_WRITE,
|
||||||
|
UNKNOWN_OPEN,
|
||||||
|
UNKNOWN_CLOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
## The file actions which are logged.
|
||||||
|
const logged_file_actions: set[Action] = {
|
||||||
|
FILE_OPEN,
|
||||||
|
FILE_RENAME,
|
||||||
|
FILE_DELETE,
|
||||||
|
|
||||||
|
PRINT_OPEN,
|
||||||
|
PRINT_CLOSE,
|
||||||
|
|
||||||
|
UNKNOWN_OPEN,
|
||||||
|
} &redef;
|
||||||
|
|
||||||
|
## The server response statuses which are *not* logged.
|
||||||
|
const ignored_command_statuses: set[string] = {
|
||||||
|
"MORE_PROCESSING_REQUIRED",
|
||||||
|
} &redef;
|
||||||
|
|
||||||
|
## This record is for the smb_files.log
|
||||||
|
type FileInfo: record {
|
||||||
|
## Time when the file was first discovered.
|
||||||
|
ts : time &log;
|
||||||
|
## Unique ID of the connection the file was sent over.
|
||||||
|
uid : string &log;
|
||||||
|
## ID of the connection the file was sent over.
|
||||||
|
id : conn_id &log;
|
||||||
|
## Unique ID of the file.
|
||||||
|
fuid : string &log &optional;
|
||||||
|
|
||||||
|
## Action this log record represents.
|
||||||
|
action : Action &log &optional;
|
||||||
|
## Path pulled from the tree this file was transferred to or from.
|
||||||
|
path : string &log &optional;
|
||||||
|
## Filename if one was seen.
|
||||||
|
name : string &log &optional;
|
||||||
|
## Total size of the file.
|
||||||
|
size : count &log &default=0;
|
||||||
|
## If the rename action was seen, this will
|
||||||
|
## the file's previous name.
|
||||||
|
prev_name : string &log &optional;
|
||||||
|
## Last time this file was modified.
|
||||||
|
times : SMB::MACTimes &log &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
## This record is for the smb_mapping.log
|
||||||
|
type TreeInfo: record {
|
||||||
|
## Time when the tree was mapped.
|
||||||
|
ts : time &log &optional;
|
||||||
|
## Unique ID of the connection the tree was mapped over.
|
||||||
|
uid : string &log;
|
||||||
|
## ID of the connection the tree was mapped over.
|
||||||
|
id : conn_id &log;
|
||||||
|
|
||||||
|
## Name of the tree path.
|
||||||
|
path : string &log &optional;
|
||||||
|
## The type of resource of the tree (disk share, printer share, named pipe, etc.)
|
||||||
|
service : string &log &optional;
|
||||||
|
## File system of the tree.
|
||||||
|
native_file_system : string &log &optional;
|
||||||
|
## If this is SMB2, a share type will be included. For SMB1,
|
||||||
|
## the type of share will be deduced and included as well.
|
||||||
|
share_type : string &log &default="DISK";
|
||||||
|
};
|
||||||
|
|
||||||
|
## This record is for the smb_cmd.log
|
||||||
|
type CmdInfo: record {
|
||||||
|
## Timestamp of the command request
|
||||||
|
ts : time &log;
|
||||||
|
## Unique ID of the connection the request was sent over
|
||||||
|
uid : string &log;
|
||||||
|
## ID of the connection the request was sent over
|
||||||
|
id : conn_id &log;
|
||||||
|
|
||||||
|
## The command sent by the client
|
||||||
|
command : string &log;
|
||||||
|
## The subcommand sent by the client, if present
|
||||||
|
sub_command : string &log &optional;
|
||||||
|
## Command argument sent by the client, if any
|
||||||
|
argument : string &log &optional;
|
||||||
|
|
||||||
|
## Server reply to the client's command
|
||||||
|
status : string &log &optional;
|
||||||
|
## Round trip time from the request to the response.
|
||||||
|
rtt : interval &log &optional;
|
||||||
|
## Version of SMB for the command
|
||||||
|
version : string &log;
|
||||||
|
|
||||||
|
## Authenticated username, if available
|
||||||
|
username : string &log &optional;
|
||||||
|
|
||||||
|
## If this is related to a tree, this is the tree
|
||||||
|
## that was used for the current command.
|
||||||
|
tree : string &log &optional;
|
||||||
|
## The type of tree (disk share, printer share, named pipe, etc.)
|
||||||
|
tree_service : string &log &optional;
|
||||||
|
|
||||||
|
## If the command referenced a file, store it here.
|
||||||
|
referenced_file : FileInfo &log &optional;
|
||||||
|
## If the command referenced a tree, store it here.
|
||||||
|
referenced_tree : TreeInfo &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
## This record stores the SMB state of in-flight commands,
|
||||||
|
## the file and tree map of the connection.
|
||||||
|
type State: record {
|
||||||
|
## A reference to the current command.
|
||||||
|
current_cmd : CmdInfo &optional;
|
||||||
|
## A reference to the current file.
|
||||||
|
current_file : FileInfo &optional;
|
||||||
|
## A reference to the current tree.
|
||||||
|
current_tree : TreeInfo &optional;
|
||||||
|
|
||||||
|
## Indexed on MID to map responses to requests.
|
||||||
|
pending_cmds : table[count] of CmdInfo &optional;
|
||||||
|
## File map to retrieve file information based on the file ID.
|
||||||
|
fid_map : table[count] of FileInfo &optional;
|
||||||
|
## Tree map to retrieve tree information based on the tree ID.
|
||||||
|
tid_map : table[count] of TreeInfo &optional;
|
||||||
|
## User map to retrieve user name based on the user ID.
|
||||||
|
uid_map : table[count] of string &optional;
|
||||||
|
## Pipe map to retrieve UUID based on the file ID of a pipe.
|
||||||
|
pipe_map : table[count] of string &optional;
|
||||||
|
|
||||||
|
## A set of recent files to avoid logging the same
|
||||||
|
## files over and over in the smb files log.
|
||||||
|
## This only applies to files seen in a single connection.
|
||||||
|
recent_files : set[string] &default=string_set() &read_expire=3min;
|
||||||
|
};
|
||||||
|
|
||||||
|
## Optionally write out the SMB commands log. This is
|
||||||
|
## primarily useful for debugging so is disabled by default.
|
||||||
|
const write_cmd_log = F &redef;
|
||||||
|
|
||||||
|
## Everything below here is used internally in the SMB scripts.
|
||||||
|
|
||||||
|
redef record connection += {
|
||||||
|
smb_state : State &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
## Internal use only
|
||||||
|
## Some commands shouldn't be logged by the smb1_message event
|
||||||
|
const deferred_logging_cmds: set[string] = {
|
||||||
|
"NEGOTIATE",
|
||||||
|
"READ_ANDX",
|
||||||
|
"SESSION_SETUP_ANDX",
|
||||||
|
"TREE_CONNECT_ANDX",
|
||||||
|
};
|
||||||
|
|
||||||
|
## This is an internally used function.
|
||||||
|
const set_current_file: function(smb_state: State, file_id: count) &redef;
|
||||||
|
|
||||||
|
## This is an internally used function.
|
||||||
|
const write_file_log: function(state: State) &redef;
|
||||||
|
}
|
||||||
|
|
||||||
|
redef record FileInfo += {
|
||||||
|
## ID referencing this file.
|
||||||
|
fid : count &optional;
|
||||||
|
|
||||||
|
## UUID referencing this file if DCE/RPC
|
||||||
|
uuid : string &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ports = { 139/tcp, 445/tcp };
|
||||||
|
redef likely_server_ports += { ports };
|
||||||
|
|
||||||
|
event bro_init() &priority=5
|
||||||
|
{
|
||||||
|
Log::create_stream(SMB::CMD_LOG, [$columns=SMB::CmdInfo]);
|
||||||
|
Log::create_stream(SMB::FILES_LOG, [$columns=SMB::FileInfo]);
|
||||||
|
Log::create_stream(SMB::MAPPING_LOG, [$columns=SMB::TreeInfo]);
|
||||||
|
|
||||||
|
Analyzer::register_for_ports(Analyzer::ANALYZER_SMB, ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_current_file(smb_state: State, file_id: count)
|
||||||
|
{
|
||||||
|
if ( file_id !in smb_state$fid_map )
|
||||||
|
{
|
||||||
|
smb_state$fid_map[file_id] = smb_state$current_cmd$referenced_file;
|
||||||
|
smb_state$fid_map[file_id]$fid = file_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
smb_state$current_cmd$referenced_file = smb_state$fid_map[file_id];
|
||||||
|
smb_state$current_file = smb_state$current_cmd$referenced_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
function write_file_log(state: State)
|
||||||
|
{
|
||||||
|
local f = state$current_file;
|
||||||
|
if ( f?$name &&
|
||||||
|
f$name !in pipe_names &&
|
||||||
|
f$action in logged_file_actions )
|
||||||
|
{
|
||||||
|
# Everything in this if statement is to avoid overlogging
|
||||||
|
# of the same data from a single connection based on recently
|
||||||
|
# seen files in the SMB::State $recent_files field.
|
||||||
|
if ( f?$times )
|
||||||
|
{
|
||||||
|
local file_ident = cat(f$action,
|
||||||
|
f?$fuid ? f$fuid : "",
|
||||||
|
f?$name ? f$name : "",
|
||||||
|
f?$path ? f$path : "",
|
||||||
|
f$size,
|
||||||
|
f$times);
|
||||||
|
if ( file_ident in state$recent_files )
|
||||||
|
{
|
||||||
|
# We've already seen this file and don't want to log it again.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
add state$recent_files[file_ident];
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::write(FILES_LOG, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event file_state_remove(f: fa_file) &priority=-5
|
||||||
|
{
|
||||||
|
if ( f$source != "SMB" )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for ( id in f$conns )
|
||||||
|
{
|
||||||
|
local c = f$conns[id];
|
||||||
|
if ( c?$smb_state && c$smb_state?$current_file)
|
||||||
|
{
|
||||||
|
write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
362
scripts/policy/protocols/smb/smb1-main.bro
Normal file
362
scripts/policy/protocols/smb/smb1-main.bro
Normal file
|
@ -0,0 +1,362 @@
|
||||||
|
@load ./main
|
||||||
|
|
||||||
|
module SMB1;
|
||||||
|
|
||||||
|
redef record SMB::CmdInfo += {
|
||||||
|
## Dialects offered by the client
|
||||||
|
smb1_offered_dialects: string_vec &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=5
|
||||||
|
{
|
||||||
|
if ( ! c?$smb_state )
|
||||||
|
{
|
||||||
|
local state: SMB::State;
|
||||||
|
state$fid_map = table();
|
||||||
|
state$tid_map = table();
|
||||||
|
state$uid_map = table();
|
||||||
|
state$pipe_map = table();
|
||||||
|
state$pending_cmds = table();
|
||||||
|
c$smb_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
local smb_state = c$smb_state;
|
||||||
|
local tid = hdr$tid;
|
||||||
|
local uid = hdr$uid;
|
||||||
|
local pid = hdr$pid;
|
||||||
|
local mid = hdr$mid;
|
||||||
|
|
||||||
|
if ( uid in smb_state$uid_map )
|
||||||
|
{
|
||||||
|
smb_state$current_cmd$username = smb_state$uid_map[uid];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( tid !in smb_state$tid_map )
|
||||||
|
{
|
||||||
|
smb_state$tid_map[tid] = SMB::TreeInfo($uid=c$uid, $id=c$id);
|
||||||
|
}
|
||||||
|
smb_state$current_tree = smb_state$tid_map[tid];
|
||||||
|
if ( smb_state$current_tree?$path )
|
||||||
|
{
|
||||||
|
smb_state$current_cmd$tree = smb_state$current_tree$path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( smb_state$current_tree?$service )
|
||||||
|
{
|
||||||
|
smb_state$current_cmd$tree_service = smb_state$current_tree$service;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mid !in smb_state$pending_cmds )
|
||||||
|
{
|
||||||
|
local tmp_cmd = SMB::CmdInfo($ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB1", $command = SMB1::commands[hdr$command]);
|
||||||
|
|
||||||
|
local tmp_file = SMB::FileInfo($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
tmp_cmd$referenced_file = tmp_file;
|
||||||
|
tmp_cmd$referenced_tree = smb_state$current_tree;
|
||||||
|
|
||||||
|
smb_state$pending_cmds[mid] = tmp_cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
smb_state$current_cmd = smb_state$pending_cmds[mid];
|
||||||
|
|
||||||
|
if ( !is_orig )
|
||||||
|
{
|
||||||
|
smb_state$current_cmd$rtt = network_time() - smb_state$current_cmd$ts;
|
||||||
|
smb_state$current_cmd$status = SMB::statuses[hdr$status]$id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=-5
|
||||||
|
{
|
||||||
|
# Is this a response?
|
||||||
|
if ( !is_orig )
|
||||||
|
{
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses &&
|
||||||
|
c$smb_state$current_cmd$command !in SMB::deferred_logging_cmds )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
delete c$smb_state$pending_cmds[hdr$mid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
event smb1_transaction2_request(c: connection, hdr: SMB1::Header, sub_cmd: count)
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$sub_command = SMB1::trans2_sub_commands[sub_cmd];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
event smb1_negotiate_request(c: connection, hdr: SMB1::Header, dialects: string_vec) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$smb1_offered_dialects = dialects;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=5
|
||||||
|
{
|
||||||
|
if ( c$smb_state$current_cmd?$smb1_offered_dialects )
|
||||||
|
{
|
||||||
|
if ( response?$ntlm )
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$argument = c$smb_state$current_cmd$smb1_offered_dialects[response$ntlm$dialect_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete c$smb_state$current_cmd$smb1_offered_dialects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=-5
|
||||||
|
{
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_tree_connect_andx_request(c: connection, hdr: SMB1::Header, path: string, service: string) &priority=5
|
||||||
|
{
|
||||||
|
local tmp_tree = SMB::TreeInfo($ts=network_time(), $uid=c$uid, $id=c$id, $path=path, $service=service);
|
||||||
|
|
||||||
|
c$smb_state$current_cmd$referenced_tree = tmp_tree;
|
||||||
|
c$smb_state$current_cmd$argument = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$referenced_tree$service = service;
|
||||||
|
if ( service == "IPC" )
|
||||||
|
c$smb_state$current_cmd$referenced_tree$share_type = "PIPE";
|
||||||
|
|
||||||
|
c$smb_state$current_cmd$tree_service = service;
|
||||||
|
|
||||||
|
if ( native_file_system != "" )
|
||||||
|
c$smb_state$current_cmd$referenced_tree$native_file_system = native_file_system;
|
||||||
|
|
||||||
|
c$smb_state$current_tree = c$smb_state$current_cmd$referenced_tree;
|
||||||
|
c$smb_state$tid_map[hdr$tid] = c$smb_state$current_tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=-5
|
||||||
|
{
|
||||||
|
Log::write(SMB::MAPPING_LOG, c$smb_state$current_tree);
|
||||||
|
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_nt_create_andx_request(c: connection, hdr: SMB1::Header, name: string) &priority=5
|
||||||
|
{
|
||||||
|
local tmp_file = SMB::FileInfo($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
c$smb_state$current_cmd$referenced_file = tmp_file;
|
||||||
|
|
||||||
|
c$smb_state$current_cmd$referenced_file$name = name;
|
||||||
|
c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN;
|
||||||
|
c$smb_state$current_file = c$smb_state$current_cmd$referenced_file;
|
||||||
|
c$smb_state$current_cmd$argument = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_nt_create_andx_response(c: connection, hdr: SMB1::Header, file_id: count, file_size: count, times: SMB::MACTimes) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN;
|
||||||
|
c$smb_state$current_cmd$referenced_file$fid = file_id;
|
||||||
|
c$smb_state$current_cmd$referenced_file$size = file_size;
|
||||||
|
|
||||||
|
# I'm seeing negative data from IPC tree transfers
|
||||||
|
if ( time_to_double(times$modified) > 0.0 )
|
||||||
|
c$smb_state$current_cmd$referenced_file$times = times;
|
||||||
|
|
||||||
|
# We can identify the file by its file id now so let's stick it
|
||||||
|
# in the file map.
|
||||||
|
c$smb_state$fid_map[file_id] = c$smb_state$current_cmd$referenced_file;
|
||||||
|
|
||||||
|
c$smb_state$current_file = c$smb_state$fid_map[file_id];
|
||||||
|
|
||||||
|
SMB::write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id);
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_READ;
|
||||||
|
if ( c$smb_state$current_file?$name )
|
||||||
|
c$smb_state$current_cmd$argument = c$smb_state$current_file$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=-5
|
||||||
|
{
|
||||||
|
if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path )
|
||||||
|
c$smb_state$current_file$path = c$smb_state$current_tree$path;
|
||||||
|
|
||||||
|
# We don't even try to log reads and writes to the files log.
|
||||||
|
#write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5
|
||||||
|
{
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id);
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_WRITE;
|
||||||
|
if ( !c$smb_state$current_cmd?$argument &&
|
||||||
|
# TODO: figure out why name isn't getting set sometimes.
|
||||||
|
c$smb_state$current_file?$name )
|
||||||
|
c$smb_state$current_cmd$argument = c$smb_state$current_file$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=-5
|
||||||
|
{
|
||||||
|
if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path )
|
||||||
|
c$smb_state$current_file$path = c$smb_state$current_tree$path;
|
||||||
|
|
||||||
|
# We don't even try to log reads and writes to the files log.
|
||||||
|
#write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#event smb1_write_andx_response(c: connection, hdr: SMB1::Header, written_bytes: count) &priority=5
|
||||||
|
# {
|
||||||
|
# # TODO - determine what to do here
|
||||||
|
# }
|
||||||
|
|
||||||
|
event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id);
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=-5
|
||||||
|
{
|
||||||
|
if ( file_id in c$smb_state$fid_map )
|
||||||
|
{
|
||||||
|
local fl = c$smb_state$fid_map[file_id];
|
||||||
|
# Need to check for existence of path in case tree connect message wasn't seen.
|
||||||
|
if ( c$smb_state$current_tree?$path )
|
||||||
|
fl$path = c$smb_state$current_tree$path;
|
||||||
|
|
||||||
|
if ( fl?$name )
|
||||||
|
c$smb_state$current_cmd$argument = fl$name;
|
||||||
|
|
||||||
|
delete c$smb_state$fid_map[file_id];
|
||||||
|
|
||||||
|
SMB::write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# TODO - Determine correct action
|
||||||
|
# A reporter message is not right...
|
||||||
|
#Reporter::warning("attempting to close an unknown file!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_trans2_get_dfs_referral_request(c: connection, hdr: SMB1::Header, file_name: string)
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$argument = file_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_trans2_query_path_info_request(c: connection, hdr: SMB1::Header, file_name: string)
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$argument = file_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_trans2_find_first2_request(c: connection, hdr: SMB1::Header, args: SMB1::Find_First2_Request_Args)
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$argument = args$file_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_session_setup_andx_response(c: connection, hdr: SMB1::Header, response: SMB1::SessionSetupAndXResponse) &priority=-5
|
||||||
|
{
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_transaction_request(c: connection, hdr: SMB1::Header, name: string, sub_cmd: count)
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$sub_command = SMB1::trans_sub_commands[sub_cmd];
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count)
|
||||||
|
{
|
||||||
|
if ( ! c$smb_state?$current_file || ! c$smb_state$current_file?$uuid )
|
||||||
|
{
|
||||||
|
# TODO: figure out why the uuid isn't getting set sometimes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c$smb_state$pipe_map[file_id] = c$smb_state$current_file$uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_pipe_bind_ack_response(c: connection, hdr: SMB1::Header)
|
||||||
|
{
|
||||||
|
if ( ! c$smb_state?$current_file || ! c$smb_state$current_file?$uuid )
|
||||||
|
{
|
||||||
|
# TODO: figure out why the uuid isn't getting set sometimes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c$smb_state$current_cmd$sub_command = "RPC_BIND_ACK";
|
||||||
|
c$smb_state$current_cmd$argument = SMB::rpc_uuids[c$smb_state$current_file$uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_pipe_bind_request(c: connection, hdr: SMB1::Header, uuid: string, version: string)
|
||||||
|
{
|
||||||
|
if ( ! c$smb_state?$current_file || ! c$smb_state$current_file?$uuid )
|
||||||
|
{
|
||||||
|
# TODO: figure out why the current_file isn't getting set sometimes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c$smb_state$current_cmd$sub_command = "RPC_BIND";
|
||||||
|
c$smb_state$current_file$uuid = uuid;
|
||||||
|
c$smb_state$current_cmd$argument = fmt("%s v%s", SMB::rpc_uuids[uuid], version);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_pipe_request(c: connection, hdr: SMB1::Header, op_num: count)
|
||||||
|
{
|
||||||
|
if ( ! c$smb_state?$current_file )
|
||||||
|
{
|
||||||
|
# TODO: figure out why the current file isn't being set sometimes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local f = c$smb_state$current_file;
|
||||||
|
if ( ! f?$uuid )
|
||||||
|
{
|
||||||
|
# TODO: figure out why this is happening.
|
||||||
|
event conn_weird("smb_pipe_request_missing_uuid", c, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
local arg = fmt("%s: %s",
|
||||||
|
SMB::rpc_uuids[f$uuid],
|
||||||
|
SMB::rpc_sub_cmds[f$uuid][op_num]);
|
||||||
|
|
||||||
|
c$smb_state$current_cmd$argument = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb1_error(c: connection, hdr: SMB1::Header, is_orig: bool)
|
||||||
|
{
|
||||||
|
if ( ! is_orig )
|
||||||
|
{
|
||||||
|
# This is for deferred commands only.
|
||||||
|
# The more specific messages won't fire for errors
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses &&
|
||||||
|
c$smb_state$current_cmd$command in SMB::deferred_logging_cmds )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
314
scripts/policy/protocols/smb/smb2-main.bro
Normal file
314
scripts/policy/protocols/smb/smb2-main.bro
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
@load ./main
|
||||||
|
|
||||||
|
module SMB2;
|
||||||
|
|
||||||
|
redef record SMB::CmdInfo += {
|
||||||
|
## Dialects offered by the client
|
||||||
|
smb2_offered_dialects: index_vec &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=5
|
||||||
|
{
|
||||||
|
if ( ! c?$smb_state )
|
||||||
|
{
|
||||||
|
local state: SMB::State;
|
||||||
|
state$fid_map = table();
|
||||||
|
state$tid_map = table();
|
||||||
|
state$pending_cmds = table();
|
||||||
|
c$smb_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
local smb_state = c$smb_state;
|
||||||
|
local tid = hdr$tree_id;
|
||||||
|
local pid = hdr$process_id;
|
||||||
|
local mid = hdr$message_id;
|
||||||
|
local sid = hdr$session_id;
|
||||||
|
|
||||||
|
if ( mid !in smb_state$pending_cmds )
|
||||||
|
{
|
||||||
|
local tmp_file = SMB::FileInfo($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
local tmp_cmd = SMB::CmdInfo($ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB2", $command = SMB2::commands[hdr$command]);
|
||||||
|
tmp_cmd$referenced_file = tmp_file;
|
||||||
|
smb_state$pending_cmds[mid] = tmp_cmd;
|
||||||
|
}
|
||||||
|
smb_state$current_cmd = smb_state$pending_cmds[mid];
|
||||||
|
|
||||||
|
if ( tid > 0 )
|
||||||
|
{
|
||||||
|
if ( smb_state$current_cmd?$referenced_tree )
|
||||||
|
{
|
||||||
|
smb_state$tid_map[tid] = smb_state$current_cmd$referenced_tree;
|
||||||
|
}
|
||||||
|
else if ( tid !in smb_state$tid_map )
|
||||||
|
{
|
||||||
|
local tmp_tree = SMB::TreeInfo($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
smb_state$tid_map[tid] = tmp_tree;
|
||||||
|
}
|
||||||
|
smb_state$current_cmd$referenced_tree = smb_state$tid_map[tid];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
smb_state$current_cmd$referenced_tree = SMB::TreeInfo($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
}
|
||||||
|
|
||||||
|
smb_state$current_file = smb_state$current_cmd$referenced_file;
|
||||||
|
smb_state$current_tree = smb_state$current_cmd$referenced_tree;
|
||||||
|
|
||||||
|
if ( !is_orig )
|
||||||
|
{
|
||||||
|
smb_state$current_cmd$rtt = network_time() - smb_state$current_cmd$ts;
|
||||||
|
smb_state$current_cmd$status = SMB::statuses[hdr$status]$id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=-5
|
||||||
|
{
|
||||||
|
# Is this a response?
|
||||||
|
if ( !is_orig )
|
||||||
|
{
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses &&
|
||||||
|
c$smb_state$current_cmd$command !in SMB::deferred_logging_cmds )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
delete c$smb_state$pending_cmds[hdr$message_id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_negotiate_request(c: connection, hdr: SMB2::Header, dialects: index_vec) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$smb2_offered_dialects = dialects;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) &priority=5
|
||||||
|
{
|
||||||
|
if ( c$smb_state$current_cmd?$smb2_offered_dialects )
|
||||||
|
{
|
||||||
|
for ( i in c$smb_state$current_cmd$smb2_offered_dialects )
|
||||||
|
{
|
||||||
|
if ( response$dialect_revision == c$smb_state$current_cmd$smb2_offered_dialects[i] )
|
||||||
|
{
|
||||||
|
c$smb_state$current_cmd$argument = SMB2::dialects[response$dialect_revision];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete c$smb_state$current_cmd$smb2_offered_dialects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) &priority=5
|
||||||
|
{
|
||||||
|
if ( SMB::write_cmd_log &&
|
||||||
|
c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
|
||||||
|
{
|
||||||
|
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_tree_connect_request(c: connection, hdr: SMB2::Header, path: string) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_tree$path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_tree$share_type = SMB2::share_types[response$share_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=-5
|
||||||
|
{
|
||||||
|
Log::write(SMB::MAPPING_LOG, c$smb_state$current_tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_create_request(c: connection, hdr: SMB2::Header, name: string) &priority=5
|
||||||
|
{
|
||||||
|
if ( name == "")
|
||||||
|
name = "<share_root>";
|
||||||
|
|
||||||
|
c$smb_state$current_file$name = name;
|
||||||
|
|
||||||
|
switch ( c$smb_state$current_tree$share_type )
|
||||||
|
{
|
||||||
|
case "DISK":
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_OPEN;
|
||||||
|
break;
|
||||||
|
case "PIPE":
|
||||||
|
c$smb_state$current_file$action = SMB::PIPE_OPEN;
|
||||||
|
break;
|
||||||
|
case "PRINT":
|
||||||
|
c$smb_state$current_file$action = SMB::PRINT_OPEN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#c$smb_state$current_file$action = SMB::UNKNOWN_OPEN;
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_OPEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_create_response(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, file_size: count, times: SMB::MACTimes, attrs: SMB2::FileAttrs) &priority=5
|
||||||
|
{
|
||||||
|
c$smb_state$current_file$fid = file_id$persistent+file_id$volatile;
|
||||||
|
c$smb_state$current_file$size = file_size;
|
||||||
|
|
||||||
|
if ( c$smb_state$current_tree?$path )
|
||||||
|
c$smb_state$current_file$path = c$smb_state$current_tree$path;
|
||||||
|
|
||||||
|
# I'm seeing negative data from IPC tree transfers
|
||||||
|
if ( time_to_double(times$modified) > 0.0 )
|
||||||
|
c$smb_state$current_file$times = times;
|
||||||
|
|
||||||
|
# We can identify the file by its file id now so let's stick it
|
||||||
|
# in the file map.
|
||||||
|
c$smb_state$fid_map[file_id$persistent+file_id$volatile] = c$smb_state$current_file;
|
||||||
|
|
||||||
|
c$smb_state$current_file = c$smb_state$fid_map[file_id$persistent+file_id$volatile];
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_create_response(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, file_size: count, times: SMB::MACTimes, attrs: SMB2::FileAttrs) &priority=-5
|
||||||
|
{
|
||||||
|
SMB::write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
|
||||||
|
|
||||||
|
switch ( c$smb_state$current_tree$share_type )
|
||||||
|
{
|
||||||
|
case "DISK":
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_READ;
|
||||||
|
break;
|
||||||
|
case "PIPE":
|
||||||
|
c$smb_state$current_file$action = SMB::PIPE_READ;
|
||||||
|
break;
|
||||||
|
case "PRINT":
|
||||||
|
c$smb_state$current_file$action = SMB::PRINT_READ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_OPEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
|
||||||
|
|
||||||
|
switch ( c$smb_state$current_tree$share_type )
|
||||||
|
{
|
||||||
|
case "DISK":
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_WRITE;
|
||||||
|
break;
|
||||||
|
case "PIPE":
|
||||||
|
c$smb_state$current_file$action = SMB::PIPE_WRITE;
|
||||||
|
break;
|
||||||
|
case "PRINT":
|
||||||
|
c$smb_state$current_file$action = SMB::PRINT_WRITE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#c$smb_state$current_file$action = SMB::UNKNOWN_WRITE;
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_WRITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_file_rename(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, dst_filename: string) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
|
||||||
|
|
||||||
|
if ( c$smb_state$current_file?$name )
|
||||||
|
c$smb_state$current_file$prev_name = c$smb_state$current_file$name;
|
||||||
|
|
||||||
|
c$smb_state$current_file$name = dst_filename;
|
||||||
|
|
||||||
|
switch ( c$smb_state$current_tree$share_type )
|
||||||
|
{
|
||||||
|
case "DISK":
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_RENAME;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_RENAME;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_file_rename(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, dst_filename: string) &priority=-5
|
||||||
|
{
|
||||||
|
SMB::write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_file_delete(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, delete_pending: bool) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
|
||||||
|
|
||||||
|
if ( ! delete_pending )
|
||||||
|
{
|
||||||
|
print "huh...";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( c$smb_state$current_tree$share_type )
|
||||||
|
{
|
||||||
|
case "DISK":
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_DELETE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_DELETE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_file_delete(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, delete_pending: bool) &priority=-5
|
||||||
|
{
|
||||||
|
SMB::write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=5
|
||||||
|
{
|
||||||
|
SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
|
||||||
|
|
||||||
|
switch ( c$smb_state$current_tree$share_type )
|
||||||
|
{
|
||||||
|
case "DISK":
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_CLOSE;
|
||||||
|
break;
|
||||||
|
case "PIPE":
|
||||||
|
c$smb_state$current_file$action = SMB::PIPE_CLOSE;
|
||||||
|
break;
|
||||||
|
case "PRINT":
|
||||||
|
c$smb_state$current_file$action = SMB::PRINT_CLOSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#c$smb_state$current_file$action = SMB::UNKNOWN_CLOSE;
|
||||||
|
c$smb_state$current_file$action = SMB::FILE_CLOSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=-5
|
||||||
|
{
|
||||||
|
if ( file_id$persistent+file_id$volatile in c$smb_state$fid_map )
|
||||||
|
{
|
||||||
|
local fl = c$smb_state$fid_map[file_id$persistent+file_id$volatile];
|
||||||
|
# Need to check for existence of path in case tree connect message wasn't seen.
|
||||||
|
if ( c$smb_state$current_tree?$path )
|
||||||
|
fl$path = c$smb_state$current_tree$path;
|
||||||
|
delete c$smb_state$fid_map[file_id$persistent+file_id$volatile];
|
||||||
|
|
||||||
|
SMB::write_file_log(c$smb_state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# TODO - Determine correct action
|
||||||
|
# A reporter message is not right...
|
||||||
|
#Reporter::warning("attempting to close an unknown file!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -88,3 +88,7 @@
|
||||||
# Uncomment the following line to enable logging of link-layer addresses. Enabling
|
# Uncomment the following line to enable logging of link-layer addresses. Enabling
|
||||||
# this adds the link-layer address for each connection endpoint to the conn.log file.
|
# this adds the link-layer address for each connection endpoint to the conn.log file.
|
||||||
# @load policy/protocols/conn/mac-logging
|
# @load policy/protocols/conn/mac-logging
|
||||||
|
|
||||||
|
# Uncomment the following line to enable the SMB analyzer. The analyzer
|
||||||
|
# is currently considered a preview and therefore not loaded by default.
|
||||||
|
# @load policy/protocols/smb
|
||||||
|
|
|
@ -76,6 +76,11 @@
|
||||||
@load protocols/modbus/track-memmap.bro
|
@load protocols/modbus/track-memmap.bro
|
||||||
@load protocols/mysql/software.bro
|
@load protocols/mysql/software.bro
|
||||||
@load protocols/rdp/indicate_ssl.bro
|
@load protocols/rdp/indicate_ssl.bro
|
||||||
|
@load protocols/smb/__load__.bro
|
||||||
|
@load protocols/smb/files.bro
|
||||||
|
@load protocols/smb/main.bro
|
||||||
|
@load protocols/smb/smb1-main.bro
|
||||||
|
@load protocols/smb/smb2-main.bro
|
||||||
@load protocols/smtp/blocklists.bro
|
@load protocols/smtp/blocklists.bro
|
||||||
@load protocols/smtp/detect-suspicious-orig.bro
|
@load protocols/smtp/detect-suspicious-orig.bro
|
||||||
@load protocols/smtp/entities-excerpt.bro
|
@load protocols/smtp/entities-excerpt.bro
|
||||||
|
|
|
@ -23,6 +23,7 @@ TableType* string_set;
|
||||||
TableType* string_array;
|
TableType* string_array;
|
||||||
TableType* count_set;
|
TableType* count_set;
|
||||||
VectorType* string_vec;
|
VectorType* string_vec;
|
||||||
|
VectorType* index_vec;
|
||||||
VectorType* mime_matches;
|
VectorType* mime_matches;
|
||||||
RecordType* mime_match;
|
RecordType* mime_match;
|
||||||
|
|
||||||
|
@ -105,13 +106,6 @@ RecordType* pm_callit_request;
|
||||||
|
|
||||||
RecordType* ntp_msg;
|
RecordType* ntp_msg;
|
||||||
|
|
||||||
TableVal* samba_cmds;
|
|
||||||
RecordType* smb_hdr;
|
|
||||||
RecordType* smb_trans;
|
|
||||||
RecordType* smb_trans_data;
|
|
||||||
RecordType* smb_tree_connect;
|
|
||||||
TableType* smb_negotiate;
|
|
||||||
|
|
||||||
RecordType* geo_location;
|
RecordType* geo_location;
|
||||||
|
|
||||||
RecordType* entropy_test_result;
|
RecordType* entropy_test_result;
|
||||||
|
@ -331,6 +325,7 @@ void init_net_var()
|
||||||
string_set = internal_type("string_set")->AsTableType();
|
string_set = internal_type("string_set")->AsTableType();
|
||||||
string_array = internal_type("string_array")->AsTableType();
|
string_array = internal_type("string_array")->AsTableType();
|
||||||
string_vec = internal_type("string_vec")->AsVectorType();
|
string_vec = internal_type("string_vec")->AsVectorType();
|
||||||
|
index_vec = internal_type("index_vec")->AsVectorType();
|
||||||
mime_match = internal_type("mime_match")->AsRecordType();
|
mime_match = internal_type("mime_match")->AsRecordType();
|
||||||
mime_matches = internal_type("mime_matches")->AsVectorType();
|
mime_matches = internal_type("mime_matches")->AsVectorType();
|
||||||
|
|
||||||
|
@ -427,13 +422,6 @@ void init_net_var()
|
||||||
|
|
||||||
ntp_msg = internal_type("ntp_msg")->AsRecordType();
|
ntp_msg = internal_type("ntp_msg")->AsRecordType();
|
||||||
|
|
||||||
samba_cmds = internal_val("samba_cmds")->AsTableVal();
|
|
||||||
smb_hdr = internal_type("smb_hdr")->AsRecordType();
|
|
||||||
smb_trans = internal_type("smb_trans")->AsRecordType();
|
|
||||||
smb_trans_data = internal_type("smb_trans_data")->AsRecordType();
|
|
||||||
smb_tree_connect = internal_type("smb_tree_connect")->AsRecordType();
|
|
||||||
smb_negotiate = internal_type("smb_negotiate")->AsTableType();
|
|
||||||
|
|
||||||
geo_location = internal_type("geo_location")->AsRecordType();
|
geo_location = internal_type("geo_location")->AsRecordType();
|
||||||
|
|
||||||
entropy_test_result = internal_type("entropy_test_result")->AsRecordType();
|
entropy_test_result = internal_type("entropy_test_result")->AsRecordType();
|
||||||
|
|
|
@ -26,6 +26,7 @@ extern TableType* string_set;
|
||||||
extern TableType* string_array;
|
extern TableType* string_array;
|
||||||
extern TableType* count_set;
|
extern TableType* count_set;
|
||||||
extern VectorType* string_vec;
|
extern VectorType* string_vec;
|
||||||
|
extern VectorType* index_vec;
|
||||||
extern VectorType* mime_matches;
|
extern VectorType* mime_matches;
|
||||||
extern RecordType* mime_match;
|
extern RecordType* mime_match;
|
||||||
|
|
||||||
|
@ -108,13 +109,6 @@ extern RecordType* pm_callit_request;
|
||||||
|
|
||||||
extern RecordType* ntp_msg;
|
extern RecordType* ntp_msg;
|
||||||
|
|
||||||
extern TableVal* samba_cmds;
|
|
||||||
extern RecordType* smb_hdr;
|
|
||||||
extern RecordType* smb_trans;
|
|
||||||
extern RecordType* smb_trans_data;
|
|
||||||
extern RecordType* smb_tree_connect;
|
|
||||||
extern TableType* smb_negotiate;
|
|
||||||
|
|
||||||
extern RecordType* geo_location;
|
extern RecordType* geo_location;
|
||||||
|
|
||||||
extern RecordType* entropy_test_result;
|
extern RecordType* entropy_test_result;
|
||||||
|
|
|
@ -12,6 +12,7 @@ add_subdirectory(file)
|
||||||
add_subdirectory(finger)
|
add_subdirectory(finger)
|
||||||
add_subdirectory(ftp)
|
add_subdirectory(ftp)
|
||||||
add_subdirectory(gnutella)
|
add_subdirectory(gnutella)
|
||||||
|
add_subdirectory(gssapi)
|
||||||
add_subdirectory(gtpv1)
|
add_subdirectory(gtpv1)
|
||||||
add_subdirectory(http)
|
add_subdirectory(http)
|
||||||
add_subdirectory(icmp)
|
add_subdirectory(icmp)
|
||||||
|
@ -26,6 +27,7 @@ add_subdirectory(modbus)
|
||||||
add_subdirectory(mysql)
|
add_subdirectory(mysql)
|
||||||
add_subdirectory(ncp)
|
add_subdirectory(ncp)
|
||||||
add_subdirectory(netbios)
|
add_subdirectory(netbios)
|
||||||
|
add_subdirectory(ntlm)
|
||||||
add_subdirectory(ntp)
|
add_subdirectory(ntp)
|
||||||
add_subdirectory(pia)
|
add_subdirectory(pia)
|
||||||
add_subdirectory(pop3)
|
add_subdirectory(pop3)
|
||||||
|
|
|
@ -5,8 +5,14 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI
|
||||||
|
|
||||||
bro_plugin_begin(Bro DCE_RPC)
|
bro_plugin_begin(Bro DCE_RPC)
|
||||||
bro_plugin_cc(DCE_RPC.cc Plugin.cc)
|
bro_plugin_cc(DCE_RPC.cc Plugin.cc)
|
||||||
bro_plugin_bif(events.bif)
|
bro_plugin_bif(types.bif events.bif)
|
||||||
bro_plugin_pac(dce_rpc.pac dce_rpc-protocol.pac dce_rpc-analyzer.pac epmapper.pac)
|
bro_plugin_pac(
|
||||||
bro_plugin_pac(dce_rpc_simple.pac dce_rpc-protocol.pac epmapper.pac)
|
dce_rpc.pac
|
||||||
|
dce_rpc-protocol.pac
|
||||||
|
dce_rpc-analyzer.pac
|
||||||
|
dce_rpc-auth.pac
|
||||||
|
endpoint-atsvc.pac
|
||||||
|
endpoint-epmapper.pac
|
||||||
|
)
|
||||||
bro_plugin_end()
|
bro_plugin_end()
|
||||||
|
|
||||||
|
|
|
@ -9,580 +9,52 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include "DCE_RPC.h"
|
#include "DCE_RPC.h"
|
||||||
#include "Sessions.h"
|
|
||||||
|
|
||||||
#include "analyzer/Manager.h"
|
|
||||||
|
|
||||||
#include "events.bif.h"
|
|
||||||
|
|
||||||
using namespace analyzer::dce_rpc;
|
using namespace analyzer::dce_rpc;
|
||||||
|
|
||||||
#define xbyte(b, n) (((const u_char*) (b))[n])
|
|
||||||
|
|
||||||
#define extract_uint16(little_endian, bytes) \
|
DCE_RPC_Analyzer::DCE_RPC_Analyzer(Connection *conn)
|
||||||
((little_endian) ? \
|
|
||||||
uint16(xbyte(bytes, 0)) | ((uint16(xbyte(bytes, 1))) << 8) : \
|
|
||||||
uint16(xbyte(bytes, 1)) | ((uint16(xbyte(bytes, 0))) << 8))
|
|
||||||
|
|
||||||
static int uuid_index[] = {
|
|
||||||
3, 2, 1, 0,
|
|
||||||
5, 4, 7, 6,
|
|
||||||
8, 9, 10, 11,
|
|
||||||
12, 13, 14, 15
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* analyzer::dce_rpc::uuid_to_string(const u_char* uuid_data)
|
|
||||||
{
|
|
||||||
static char s[1024];
|
|
||||||
char* sp = s;
|
|
||||||
|
|
||||||
for ( int i = 0; i < 16; ++i )
|
|
||||||
{
|
|
||||||
if ( i == 4 || i == 6 || i == 8 || i == 10 )
|
|
||||||
sp += snprintf(sp, s + sizeof(s) - sp, "-");
|
|
||||||
|
|
||||||
int j = uuid_index[i];
|
|
||||||
sp += snprintf(sp, s + sizeof(s) - sp, "%02x", uuid_data[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID::UUID()
|
|
||||||
{
|
|
||||||
memset(data, 0, 16);
|
|
||||||
s = uuid_to_string(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID::UUID(const u_char d[16])
|
|
||||||
{
|
|
||||||
memcpy(data, d, 16);
|
|
||||||
s = uuid_to_string(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID::UUID(const binpac::bytestring& uuid)
|
|
||||||
{
|
|
||||||
if ( uuid.length() != 16 )
|
|
||||||
reporter->InternalError("UUID length error");
|
|
||||||
memcpy(data, uuid.begin(), 16);
|
|
||||||
s = uuid_to_string(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID::UUID(const char* str)
|
|
||||||
{
|
|
||||||
s = string(str);
|
|
||||||
const char* sp = str;
|
|
||||||
int i;
|
|
||||||
for ( i = 0; i < 16; ++i )
|
|
||||||
{
|
|
||||||
if ( *sp == '-' )
|
|
||||||
++sp;
|
|
||||||
if ( ! *sp || ! *(sp+1) )
|
|
||||||
break;
|
|
||||||
|
|
||||||
data[uuid_index[i]] =
|
|
||||||
(u_char) (decode_hex(*sp) * 16 + decode_hex(*(sp+1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( i != 16 )
|
|
||||||
reporter->InternalError("invalid UUID string: %s", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef map<UUID, BifEnum::dce_rpc_if_id> uuid_map_t;
|
|
||||||
|
|
||||||
static uuid_map_t& well_known_uuid_map()
|
|
||||||
{
|
|
||||||
static uuid_map_t the_map;
|
|
||||||
static bool initialized = false;
|
|
||||||
|
|
||||||
if ( initialized )
|
|
||||||
return the_map;
|
|
||||||
|
|
||||||
using namespace BifEnum;
|
|
||||||
|
|
||||||
the_map[UUID("e1af8308-5d1f-11c9-91a4-08002b14a0fa")] = DCE_RPC_epmapper;
|
|
||||||
|
|
||||||
the_map[UUID("afa8bd80-7d8a-11c9-bef4-08002b102989")] = DCE_RPC_mgmt;
|
|
||||||
|
|
||||||
// It's said that the following interfaces are merely aliases.
|
|
||||||
the_map[UUID("12345778-1234-abcd-ef00-0123456789ab")] = DCE_RPC_lsarpc;
|
|
||||||
the_map[UUID("12345678-1234-abcd-ef00-01234567cffb")] = DCE_RPC_netlogon;
|
|
||||||
the_map[UUID("12345778-1234-abcd-ef00-0123456789ac")] = DCE_RPC_samr;
|
|
||||||
|
|
||||||
// The next group of aliases.
|
|
||||||
the_map[UUID("4b324fc8-1670-01d3-1278-5a47bf6ee188")] = DCE_RPC_srvsvc;
|
|
||||||
the_map[UUID("12345678-1234-abcd-ef00-0123456789ab")] = DCE_RPC_spoolss;
|
|
||||||
the_map[UUID("45f52c28-7f9f-101a-b52b-08002b2efabe")] = DCE_RPC_winspipe;
|
|
||||||
the_map[UUID("6bffd098-a112-3610-9833-46c3f87e345a")] = DCE_RPC_wkssvc;
|
|
||||||
|
|
||||||
// DRS - NT directory replication service.
|
|
||||||
the_map[UUID("e3514235-4b06-11d1-ab04-00c04fc2dcd2")] = DCE_RPC_drs;
|
|
||||||
|
|
||||||
// "The IOXIDResolver RPC interface (formerly known as
|
|
||||||
// IObjectExporter) is remotely used to reach the local object
|
|
||||||
// resolver (OR)."
|
|
||||||
the_map[UUID("99fcfec4-5260-101b-bbcb-00aa0021347a")] = DCE_RPC_oxid;
|
|
||||||
|
|
||||||
the_map[UUID("3919286a-b10c-11d0-9ba8-00c04fd92ef5")] = DCE_RPC_lsa_ds;
|
|
||||||
|
|
||||||
the_map[UUID("000001a0-0000-0000-c000-000000000046")] = DCE_RPC_ISCMActivator;
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
return the_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to remember mapped DCE/RPC endpoints and parse the follow-up
|
|
||||||
// connections as DCE/RPC sessions.
|
|
||||||
map<dce_rpc_endpoint_addr, UUID> dce_rpc_endpoints;
|
|
||||||
|
|
||||||
static bool is_mapped_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr)
|
|
||||||
{
|
|
||||||
return dce_rpc_endpoints.find(addr) != dce_rpc_endpoints.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_mapped_dce_rpc_endpoint(const ConnID* id, TransportProto proto)
|
|
||||||
{
|
|
||||||
if ( id->dst_addr.GetFamily() == IPv6 )
|
|
||||||
// TODO: Does the protocol support v6 addresses? #773
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dce_rpc_endpoint_addr addr;
|
|
||||||
addr.addr = id->dst_addr;
|
|
||||||
addr.port = ntohs(id->dst_port);
|
|
||||||
addr.proto = proto;
|
|
||||||
|
|
||||||
return is_mapped_dce_rpc_endpoint(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr,
|
|
||||||
const UUID& uuid)
|
|
||||||
{
|
|
||||||
DEBUG_MSG("Adding endpoint %s @ %s\n",
|
|
||||||
uuid.to_string(), addr.to_string().c_str());
|
|
||||||
dce_rpc_endpoints[addr] = uuid;
|
|
||||||
|
|
||||||
// FIXME: Once we can pass the cookie to the analyzer, we can get rid
|
|
||||||
// of the dce_rpc_endpoints table.
|
|
||||||
// FIXME: Don't hard-code the timeout.
|
|
||||||
|
|
||||||
analyzer_mgr->ScheduleAnalyzer(IPAddr(), addr.addr, addr.port, addr.proto,
|
|
||||||
"DCE_RPC", 5 * 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCE_RPC_Header::DCE_RPC_Header(analyzer::Analyzer* a, const u_char* b)
|
|
||||||
{
|
|
||||||
analyzer = a;
|
|
||||||
bytes = b;
|
|
||||||
|
|
||||||
// This checks whether it's both the first fragment *and*
|
|
||||||
// the last fragment.
|
|
||||||
if ( (bytes[3] & 0x3) != 0x3 )
|
|
||||||
{
|
|
||||||
fragmented = 1;
|
|
||||||
Weird("Fragmented DCE/RPC message");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fragmented = 0;
|
|
||||||
|
|
||||||
ptype = (BifEnum::dce_rpc_ptype) bytes[2];
|
|
||||||
frag_len = extract_uint16(LittleEndian(), bytes + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCE_RPC_Session::DCE_RPC_Session(analyzer::Analyzer* a)
|
|
||||||
: analyzer(a),
|
|
||||||
if_uuid("00000000-0000-0000-0000-000000000000"),
|
|
||||||
if_id(BifEnum::DCE_RPC_unknown_if)
|
|
||||||
{
|
|
||||||
opnum = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DCE_RPC_Session::LooksLikeRPC(int len, const u_char* msg)
|
|
||||||
{
|
|
||||||
// if ( ! is_IPC )
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::DCE_RPC_Header h;
|
|
||||||
h.Parse(msg, msg + len);
|
|
||||||
if ( h.rpc_vers() == 5 && h.rpc_vers_minor() == 0 )
|
|
||||||
{
|
|
||||||
if ( h.frag_length() == len )
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_MSG("length mismatch: %d != %d\n",
|
|
||||||
h.frag_length(), len);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( const binpac::Exception& )
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverPDU(int is_orig, int len, const u_char* data)
|
|
||||||
{
|
|
||||||
if ( dce_rpc_message )
|
|
||||||
{
|
|
||||||
val_list* vl = new val_list;
|
|
||||||
vl->append(analyzer->BuildConnVal());
|
|
||||||
vl->append(new Val(is_orig, TYPE_BOOL));
|
|
||||||
vl->append(new EnumVal(data[2], BifType::Enum::dce_rpc_ptype));
|
|
||||||
vl->append(new StringVal(len, (const char*) data));
|
|
||||||
|
|
||||||
analyzer->ConnectionEvent(dce_rpc_message, vl);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// TODO: handle incremental input
|
|
||||||
binpac::DCE_RPC_Simple::DCE_RPC_PDU pdu;
|
|
||||||
pdu.Parse(data, data + len);
|
|
||||||
|
|
||||||
switch ( pdu.header()->PTYPE() ) {
|
|
||||||
case binpac::DCE_RPC_Simple::DCE_RPC_BIND:
|
|
||||||
case binpac::DCE_RPC_Simple::DCE_RPC_ALTER_CONTEXT:
|
|
||||||
DeliverBind(&pdu);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case binpac::DCE_RPC_Simple::DCE_RPC_REQUEST:
|
|
||||||
DeliverRequest(&pdu);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case binpac::DCE_RPC_Simple::DCE_RPC_RESPONSE:
|
|
||||||
DeliverResponse(&pdu);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( const binpac::Exception& e )
|
|
||||||
{
|
|
||||||
analyzer->Weird(e.msg().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverBind(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu)
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::DCE_RPC_Bind* bind = pdu->body()->bind();
|
|
||||||
|
|
||||||
for ( int i = 0; i < bind->p_context_elem()->n_context_elem(); ++i )
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::p_cont_elem_t* elem =
|
|
||||||
(*bind->p_context_elem()->p_cont_elem())[i];
|
|
||||||
|
|
||||||
if_uuid = UUID(elem->abstract_syntax()->if_uuid().begin());
|
|
||||||
uuid_map_t::const_iterator uuid_it =
|
|
||||||
well_known_uuid_map().find(if_uuid);
|
|
||||||
|
|
||||||
if ( uuid_it == well_known_uuid_map().end() )
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
// conn->Weird(fmt("Unknown DCE_RPC interface %s",
|
|
||||||
// if_uuid.to_string()));
|
|
||||||
#endif
|
|
||||||
if_id = BifEnum::DCE_RPC_unknown_if;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if_id = uuid_it->second;
|
|
||||||
|
|
||||||
if ( dce_rpc_bind )
|
|
||||||
{
|
|
||||||
val_list* vl = new val_list;
|
|
||||||
vl->append(analyzer->BuildConnVal());
|
|
||||||
vl->append(new StringVal(if_uuid.to_string()));
|
|
||||||
// vl->append(new EnumVal(if_id, BifType::Enum::dce_rpc_if_id));
|
|
||||||
|
|
||||||
analyzer->ConnectionEvent(dce_rpc_bind, vl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverRequest(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu)
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::DCE_RPC_Request* req = pdu->body()->request();
|
|
||||||
|
|
||||||
opnum = req->opnum();
|
|
||||||
|
|
||||||
if ( dce_rpc_request )
|
|
||||||
{
|
|
||||||
val_list* vl = new val_list;
|
|
||||||
vl->append(analyzer->BuildConnVal());
|
|
||||||
vl->append(new Val(opnum, TYPE_COUNT));
|
|
||||||
vl->append(new StringVal(req->stub().length(),
|
|
||||||
(const char*) req->stub().begin()));
|
|
||||||
|
|
||||||
analyzer->ConnectionEvent(dce_rpc_request, vl);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ( if_id ) {
|
|
||||||
case BifEnum::DCE_RPC_epmapper:
|
|
||||||
DeliverEpmapperRequest(pdu, req);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverResponse(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu)
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::DCE_RPC_Response* resp = pdu->body()->response();
|
|
||||||
|
|
||||||
if ( dce_rpc_response )
|
|
||||||
{
|
|
||||||
val_list* vl = new val_list;
|
|
||||||
vl->append(analyzer->BuildConnVal());
|
|
||||||
vl->append(new Val(opnum, TYPE_COUNT));
|
|
||||||
vl->append(new StringVal(resp->stub().length(),
|
|
||||||
(const char*) resp->stub().begin()));
|
|
||||||
analyzer->ConnectionEvent(dce_rpc_response, vl);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ( if_id ) {
|
|
||||||
case BifEnum::DCE_RPC_epmapper:
|
|
||||||
DeliverEpmapperResponse(pdu, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverEpmapperRequest(
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* /* pdu */,
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_Request* /* req */)
|
|
||||||
{
|
|
||||||
// DEBUG_MSG("Epmapper request opnum = %d\n", req->opnum());
|
|
||||||
// ### TODO(rpang): generate an event on epmapper request
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverEpmapperResponse(
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp)
|
|
||||||
{
|
|
||||||
// DEBUG_MSG("Epmapper request opnum = %d\n", req->opnum());
|
|
||||||
switch ( opnum ) {
|
|
||||||
case 3: // Map
|
|
||||||
DeliverEpmapperMapResponse(pdu, resp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DCE_RPC_Session::DeliverEpmapperMapResponse(
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::epmapper_map_resp epm_resp;
|
|
||||||
|
|
||||||
epm_resp.Parse(resp->stub().begin(), resp->stub().end(),
|
|
||||||
pdu->byteorder());
|
|
||||||
|
|
||||||
for ( unsigned int twr_i = 0;
|
|
||||||
twr_i < epm_resp.towers()->actual_count(); ++twr_i )
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::epm_tower* twr =
|
|
||||||
(*epm_resp.towers()->towers())[twr_i]->tower();
|
|
||||||
|
|
||||||
mapped.addr = dce_rpc_endpoint_addr();
|
|
||||||
mapped.uuid = UUID();
|
|
||||||
|
|
||||||
for ( int floor_i = 0; floor_i < twr->num_floors();
|
|
||||||
++floor_i )
|
|
||||||
{
|
|
||||||
binpac::DCE_RPC_Simple::epm_floor* floor =
|
|
||||||
(*twr->floors())[floor_i];
|
|
||||||
|
|
||||||
switch ( floor->protocol() ) {
|
|
||||||
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_UUID:
|
|
||||||
if ( floor_i == 0 )
|
|
||||||
mapped.uuid = UUID(floor->lhs()->data()->uuid()->if_uuid());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_TCP:
|
|
||||||
mapped.addr.port =
|
|
||||||
floor->rhs()->data()->tcp();
|
|
||||||
mapped.addr.proto = TRANSPORT_TCP;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_UDP:
|
|
||||||
mapped.addr.port =
|
|
||||||
floor->rhs()->data()->udp();
|
|
||||||
mapped.addr.proto = TRANSPORT_UDP;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_IP:
|
|
||||||
uint32 hostip = floor->rhs()->data()->ip();
|
|
||||||
mapped.addr.addr = IPAddr(IPv4, &hostip, IPAddr::Host);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mapped.addr.is_valid_addr() )
|
|
||||||
add_dce_rpc_endpoint(mapped.addr, mapped.uuid);
|
|
||||||
|
|
||||||
if ( epm_map_response )
|
|
||||||
{
|
|
||||||
val_list* vl = new val_list;
|
|
||||||
vl->append(analyzer->BuildConnVal());
|
|
||||||
vl->append(new StringVal(mapped.uuid.to_string()));
|
|
||||||
vl->append(new PortVal(mapped.addr.port, mapped.addr.proto));
|
|
||||||
vl->append(new AddrVal(mapped.addr.addr));
|
|
||||||
|
|
||||||
analyzer->ConnectionEvent(epm_map_response, vl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( const binpac::Exception& e )
|
|
||||||
{
|
|
||||||
analyzer->Weird(e.msg().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Contents_DCE_RPC_Analyzer::Contents_DCE_RPC_Analyzer(Connection* conn,
|
|
||||||
bool orig, DCE_RPC_Session* arg_session, bool speculative)
|
|
||||||
: tcp::TCP_SupportAnalyzer("CONTENTS_DCE_RPC", conn, orig)
|
|
||||||
{
|
|
||||||
session = arg_session;
|
|
||||||
msg_buf = 0;
|
|
||||||
buf_len = 0;
|
|
||||||
speculation = speculative ? 0 : 1;
|
|
||||||
|
|
||||||
InitState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Contents_DCE_RPC_Analyzer::InitState()
|
|
||||||
{
|
|
||||||
// Allocate space for header.
|
|
||||||
if ( ! msg_buf )
|
|
||||||
{
|
|
||||||
buf_len = DCE_RPC_HEADER_LENGTH;
|
|
||||||
msg_buf = new u_char[buf_len];
|
|
||||||
}
|
|
||||||
|
|
||||||
buf_n = 0;
|
|
||||||
msg_len = 0;
|
|
||||||
hdr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Contents_DCE_RPC_Analyzer::~Contents_DCE_RPC_Analyzer()
|
|
||||||
{
|
|
||||||
delete [] msg_buf;
|
|
||||||
delete hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Contents_DCE_RPC_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
|
||||||
{
|
|
||||||
tcp::TCP_SupportAnalyzer::DeliverStream(len, data, orig);
|
|
||||||
|
|
||||||
tcp::TCP_Analyzer* tcp =
|
|
||||||
static_cast<tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
|
|
||||||
|
|
||||||
if ( tcp->HadGap(orig) || tcp->IsPartial() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( speculation == 0 ) // undecided
|
|
||||||
{
|
|
||||||
if ( ! DCE_RPC_Session::LooksLikeRPC(len, data) )
|
|
||||||
speculation = -1;
|
|
||||||
else
|
|
||||||
speculation = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( speculation < 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
ASSERT(buf_len >= DCE_RPC_HEADER_LENGTH);
|
|
||||||
while ( len > 0 )
|
|
||||||
{
|
|
||||||
if ( buf_n < DCE_RPC_HEADER_LENGTH )
|
|
||||||
{
|
|
||||||
while ( buf_n < DCE_RPC_HEADER_LENGTH && len > 0 )
|
|
||||||
{
|
|
||||||
msg_buf[buf_n] = *data;
|
|
||||||
++buf_n; ++data; --len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( buf_n < DCE_RPC_HEADER_LENGTH )
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( ! ParseHeader() )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( buf_n < msg_len && len > 0 )
|
|
||||||
{
|
|
||||||
msg_buf[buf_n] = *data;
|
|
||||||
++buf_n; ++data; --len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( buf_n < msg_len )
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( msg_len > 0 )
|
|
||||||
DeliverPDU(msg_len, msg_buf);
|
|
||||||
// Reset for next message
|
|
||||||
InitState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Contents_DCE_RPC_Analyzer::DeliverPDU(int len, const u_char* data)
|
|
||||||
{
|
|
||||||
session->DeliverPDU(IsOrig(), len, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Contents_DCE_RPC_Analyzer::ParseHeader()
|
|
||||||
{
|
|
||||||
delete hdr;
|
|
||||||
hdr = 0;
|
|
||||||
|
|
||||||
if ( msg_buf[0] != 5 ) // DCE/RPC version
|
|
||||||
{
|
|
||||||
Conn()->Weird("DCE/RPC_version_error (non-DCE/RPC?)");
|
|
||||||
Conn()->SetSkip(1);
|
|
||||||
msg_len = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr = new DCE_RPC_Header(this, msg_buf);
|
|
||||||
|
|
||||||
msg_len = hdr->FragLen();
|
|
||||||
if ( msg_len > buf_len )
|
|
||||||
{
|
|
||||||
u_char* new_msg_buf = new u_char[msg_len];
|
|
||||||
memcpy(new_msg_buf, msg_buf, buf_n);
|
|
||||||
delete [] msg_buf;
|
|
||||||
buf_len = msg_len;
|
|
||||||
msg_buf = new_msg_buf;
|
|
||||||
hdr->SetBytes(new_msg_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DCE_RPC_Analyzer::DCE_RPC_Analyzer(Connection* conn, bool arg_speculative)
|
|
||||||
: tcp::TCP_ApplicationAnalyzer("DCE_RPC", conn)
|
: tcp::TCP_ApplicationAnalyzer("DCE_RPC", conn)
|
||||||
{
|
{
|
||||||
session = new DCE_RPC_Session(this);
|
interp = new binpac::DCE_RPC::DCE_RPC_Conn(this);
|
||||||
speculative = arg_speculative;
|
|
||||||
|
|
||||||
AddSupportAnalyzer(new Contents_DCE_RPC_Analyzer(conn, true, session,
|
|
||||||
speculative));
|
|
||||||
AddSupportAnalyzer(new Contents_DCE_RPC_Analyzer(conn, false, session,
|
|
||||||
speculative));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DCE_RPC_Analyzer::~DCE_RPC_Analyzer()
|
DCE_RPC_Analyzer::~DCE_RPC_Analyzer()
|
||||||
{
|
{
|
||||||
delete session;
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCE_RPC_Analyzer::Done()
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::Done();
|
||||||
|
|
||||||
|
interp->FlowEOF(true);
|
||||||
|
interp->FlowEOF(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCE_RPC_Analyzer::EndpointEOF(bool is_orig)
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||||
|
interp->FlowEOF(is_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCE_RPC_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||||
|
interp->NewGap(orig, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCE_RPC_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
|
||||||
|
assert(TCP());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
}
|
||||||
|
catch ( const binpac::Exception& e )
|
||||||
|
{
|
||||||
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,187 +3,33 @@
|
||||||
#ifndef ANALYZER_PROTOCOL_DCE_RPC_DCE_RPC_H
|
#ifndef ANALYZER_PROTOCOL_DCE_RPC_DCE_RPC_H
|
||||||
#define ANALYZER_PROTOCOL_DCE_RPC_DCE_RPC_H
|
#define ANALYZER_PROTOCOL_DCE_RPC_DCE_RPC_H
|
||||||
|
|
||||||
// NOTE: This is a somewhat crude analyzer for DCE/RPC (used on Microsoft
|
|
||||||
// Windows systems) and shouldn't be considered as stable.
|
|
||||||
|
|
||||||
#include "NetVar.h"
|
#include "NetVar.h"
|
||||||
#include "analyzer/protocol/tcp/TCP.h"
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
#include "analyzer/protocol/dce-rpc/events.bif.h"
|
#include "analyzer/protocol/dce-rpc/events.bif.h"
|
||||||
#include "IPAddr.h"
|
#include "IPAddr.h"
|
||||||
|
|
||||||
#include "dce_rpc_simple_pac.h"
|
#include "dce_rpc_pac.h"
|
||||||
|
|
||||||
|
|
||||||
namespace analyzer { namespace dce_rpc {
|
namespace analyzer { namespace dce_rpc {
|
||||||
|
|
||||||
class UUID {
|
|
||||||
public:
|
|
||||||
UUID();
|
|
||||||
UUID(const u_char data[16]);
|
|
||||||
UUID(const binpac::bytestring &uuid);
|
|
||||||
UUID(const char* s);
|
|
||||||
|
|
||||||
const char* to_string() const { return s.c_str(); }
|
|
||||||
const string& str() const { return s; }
|
|
||||||
bool operator==(const UUID& u) const
|
|
||||||
{ return s == u.str(); }
|
|
||||||
bool operator<(const UUID& u) const
|
|
||||||
{ return s < u.str(); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
u_char data[16];
|
|
||||||
string s;
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* uuid_to_string(const u_char* uuid_data);
|
|
||||||
|
|
||||||
struct dce_rpc_endpoint_addr {
|
|
||||||
// All fields are in host byteorder.
|
|
||||||
IPAddr addr;
|
|
||||||
u_short port;
|
|
||||||
TransportProto proto;
|
|
||||||
|
|
||||||
dce_rpc_endpoint_addr()
|
|
||||||
{
|
|
||||||
addr = IPAddr();
|
|
||||||
port = 0;
|
|
||||||
proto = TRANSPORT_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_valid_addr() const
|
|
||||||
{ return addr != IPAddr() && port != 0 && proto != TRANSPORT_UNKNOWN; }
|
|
||||||
|
|
||||||
bool operator<(dce_rpc_endpoint_addr const &e) const
|
|
||||||
{
|
|
||||||
if ( addr != e.addr )
|
|
||||||
return addr < e.addr;
|
|
||||||
if ( proto != e.proto )
|
|
||||||
return proto < e.proto;
|
|
||||||
if ( port != e.port )
|
|
||||||
return port < e.port;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string to_string() const
|
|
||||||
{
|
|
||||||
static char buf[128];
|
|
||||||
snprintf(buf, sizeof(buf), "%s/%d/%s",
|
|
||||||
addr.AsString().c_str(), port,
|
|
||||||
proto == TRANSPORT_TCP ? "tcp" :
|
|
||||||
(proto == TRANSPORT_UDP ? "udp" : "?"));
|
|
||||||
|
|
||||||
return string(buf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
enum DCE_RPC_PTYPE {
|
|
||||||
DCE_RPC_REQUEST, DCE_RPC_PING, DCE_RPC_RESPONSE, DCE_RPC_FAULT,
|
|
||||||
DCE_RPC_WORKING, DCE_RPC_NOCALL, DCE_RPC_REJECT, DCE_RPC_ACK,
|
|
||||||
DCE_RPC_CL_CANCEL, DCE_RPC_FACK, DCE_RPC_CANCEL_ACK, DCE_RPC_BIND,
|
|
||||||
DCE_RPC_BIND_ACK, DCE_RPC_BIND_NAK, DCE_RPC_ALTER_CONTEXT,
|
|
||||||
DCE_RPC_ALTER_CONTEXT_RESP, DCE_RPC_SHUTDOWN, DCE_RPC_CO_CANCEL,
|
|
||||||
DCE_RPC_ORPHANED,
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DCE_RPC_HEADER_LENGTH 16
|
|
||||||
|
|
||||||
class DCE_RPC_Header {
|
|
||||||
public:
|
|
||||||
DCE_RPC_Header(analyzer::Analyzer* a, const u_char* bytes);
|
|
||||||
|
|
||||||
BifEnum::dce_rpc_ptype PTYPE() const { return ptype; }
|
|
||||||
int FragLen() const { return frag_len; }
|
|
||||||
int LittleEndian() const { return bytes[4] >> 4; }
|
|
||||||
bool Fragmented() const { return fragmented; }
|
|
||||||
|
|
||||||
void Weird(const char* msg) { analyzer->Weird(msg); }
|
|
||||||
void SetBytes(const u_char* b) { bytes = b; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
analyzer::Analyzer* analyzer;
|
|
||||||
const u_char* bytes;
|
|
||||||
BifEnum::dce_rpc_ptype ptype;
|
|
||||||
int frag_len;
|
|
||||||
bool fragmented;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a general DCE_RPC_Session class so that it can be used in
|
|
||||||
// case the RPC conversation is tunneled through other connections,
|
|
||||||
// e.g. through an SMB session.
|
|
||||||
|
|
||||||
class DCE_RPC_Session {
|
|
||||||
public:
|
|
||||||
DCE_RPC_Session(analyzer::Analyzer* a);
|
|
||||||
virtual ~DCE_RPC_Session() {}
|
|
||||||
virtual void DeliverPDU(int is_orig, int len, const u_char* data);
|
|
||||||
|
|
||||||
static bool LooksLikeRPC(int len, const u_char* msg);
|
|
||||||
static bool any_dce_rpc_event()
|
|
||||||
{ return dce_rpc_message || dce_rpc_bind || dce_rpc_request; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void DeliverBind(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu);
|
|
||||||
void DeliverRequest(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu);
|
|
||||||
void DeliverResponse(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu);
|
|
||||||
|
|
||||||
void DeliverEpmapperRequest(
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_Request* req);
|
|
||||||
void DeliverEpmapperResponse(
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp);
|
|
||||||
void DeliverEpmapperMapResponse(
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
|
||||||
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp);
|
|
||||||
|
|
||||||
analyzer::Analyzer* analyzer;
|
|
||||||
UUID if_uuid;
|
|
||||||
BifEnum::dce_rpc_if_id if_id;
|
|
||||||
int opnum;
|
|
||||||
struct {
|
|
||||||
dce_rpc_endpoint_addr addr;
|
|
||||||
UUID uuid;
|
|
||||||
} mapped;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Contents_DCE_RPC_Analyzer : public tcp::TCP_SupportAnalyzer {
|
|
||||||
public:
|
|
||||||
Contents_DCE_RPC_Analyzer(Connection* conn, bool orig, DCE_RPC_Session* session,
|
|
||||||
bool speculative);
|
|
||||||
~Contents_DCE_RPC_Analyzer();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
|
||||||
virtual void DeliverPDU(int len, const u_char* data);
|
|
||||||
|
|
||||||
void InitState();
|
|
||||||
|
|
||||||
int speculation;
|
|
||||||
u_char* msg_buf;
|
|
||||||
int msg_len;
|
|
||||||
int buf_n; // number of bytes in msg_buf
|
|
||||||
int buf_len; // size off msg_buf
|
|
||||||
DCE_RPC_Header* hdr;
|
|
||||||
|
|
||||||
bool ParseHeader();
|
|
||||||
|
|
||||||
DCE_RPC_Session* session;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DCE_RPC_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
class DCE_RPC_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
||||||
public:
|
public:
|
||||||
DCE_RPC_Analyzer(Connection* conn, bool speculative = false);
|
DCE_RPC_Analyzer(Connection* conn);
|
||||||
~DCE_RPC_Analyzer();
|
~DCE_RPC_Analyzer();
|
||||||
|
|
||||||
|
void Done() override;
|
||||||
|
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||||
|
void Undelivered(uint64 seq, int len, bool orig) override;
|
||||||
|
void EndpointEOF(bool is_orig) override;
|
||||||
|
|
||||||
|
bool SetFileID(uint64 fid_in)
|
||||||
|
{ interp->set_file_id(fid_in); return true; }
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
{ return new DCE_RPC_Analyzer(conn); }
|
{ return new DCE_RPC_Analyzer(conn); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DCE_RPC_Session* session;
|
binpac::DCE_RPC::DCE_RPC_Conn* interp;
|
||||||
bool speculative;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace analyzer::*
|
} } // namespace analyzer::*
|
||||||
|
|
|
@ -13,7 +13,6 @@ public:
|
||||||
plugin::Configuration Configure()
|
plugin::Configuration Configure()
|
||||||
{
|
{
|
||||||
AddComponent(new ::analyzer::Component("DCE_RPC", ::analyzer::dce_rpc::DCE_RPC_Analyzer::Instantiate));
|
AddComponent(new ::analyzer::Component("DCE_RPC", ::analyzer::dce_rpc::DCE_RPC_Analyzer::Instantiate));
|
||||||
AddComponent(new ::analyzer::Component("Contents_DCE_RPC", 0));
|
|
||||||
|
|
||||||
plugin::Configuration config;
|
plugin::Configuration config;
|
||||||
config.name = "Bro::DCE_RPC";
|
config.name = "Bro::DCE_RPC";
|
||||||
|
|
|
@ -1,26 +1,19 @@
|
||||||
# DCE/RPC protocol data unit.
|
|
||||||
|
|
||||||
type DCE_RPC_PDU = record {
|
refine connection DCE_RPC_Conn += {
|
||||||
# Set header's byteorder to little-endian (or big-endian) to
|
%member{
|
||||||
# avoid cyclic dependency.
|
map<uint16, uint16> cont_id_opnum_map;
|
||||||
header : DCE_RPC_Header;
|
uint64 fid;
|
||||||
frag : bytestring &length = body_length;
|
%}
|
||||||
auth : DCE_RPC_Auth(header);
|
|
||||||
} &let {
|
|
||||||
body_length: int =
|
|
||||||
header.frag_length - sizeof(header) - header.auth_length;
|
|
||||||
frag_reassembled: bool =
|
|
||||||
$context.flow.reassemble_fragment(frag, header.lastfrag);
|
|
||||||
body: DCE_RPC_Body(header)
|
|
||||||
withinput $context.flow.reassembled_body()
|
|
||||||
&if frag_reassembled;
|
|
||||||
} &byteorder = header.byteorder,
|
|
||||||
&length = header.frag_length; # length of the PDU
|
|
||||||
|
|
||||||
|
%init{
|
||||||
|
fid = 0;
|
||||||
|
%}
|
||||||
|
|
||||||
connection DCE_RPC_Conn(bro_analyzer: BroAnalyzer) {
|
function set_file_id(fid_in: uint64): bool
|
||||||
upflow = DCE_RPC_Flow(true);
|
%{
|
||||||
downflow = DCE_RPC_Flow(false);
|
fid = fid_in;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
function get_cont_id_opnum_map(cont_id: uint16): uint16
|
function get_cont_id_opnum_map(cont_id: uint16): uint16
|
||||||
%{
|
%{
|
||||||
|
@ -33,102 +26,162 @@ connection DCE_RPC_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%member{
|
function proc_dce_rpc_pdu(pdu: DCE_RPC_PDU): bool
|
||||||
map<uint16, uint16> cont_id_opnum_map;
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
flow DCE_RPC_Flow(is_orig: bool) {
|
|
||||||
flowunit = DCE_RPC_PDU withcontext (connection, this);
|
|
||||||
|
|
||||||
%member{
|
|
||||||
FlowBuffer frag_reassembler_;
|
|
||||||
%}
|
|
||||||
|
|
||||||
# Fragment reassembly.
|
|
||||||
function reassemble_fragment(frag: bytestring, lastfrag: bool): bool
|
|
||||||
%{
|
%{
|
||||||
int orig_data_length = frag_reassembler_.data_length();
|
// If a whole pdu message parsed ok, let's confirm the protocol
|
||||||
|
bro_analyzer()->ProtocolConfirmation();
|
||||||
frag_reassembler_.NewData(frag.begin(), frag.end());
|
return true;
|
||||||
|
|
||||||
int new_frame_length = orig_data_length + frag.length();
|
|
||||||
if ( orig_data_length == 0 )
|
|
||||||
frag_reassembler_.NewFrame(new_frame_length, false);
|
|
||||||
else
|
|
||||||
frag_reassembler_.GrowFrame(new_frame_length);
|
|
||||||
|
|
||||||
return lastfrag;
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function reassembled_body(): const_bytestring
|
function proc_dce_rpc_message(header: DCE_RPC_Header): bool
|
||||||
%{
|
%{
|
||||||
return const_bytestring(
|
if ( dce_rpc_message )
|
||||||
frag_reassembler_.begin(),
|
{
|
||||||
frag_reassembler_.end());
|
BifEvent::generate_dce_rpc_message(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
${header.is_orig},
|
||||||
|
fid,
|
||||||
|
${header.PTYPE},
|
||||||
|
new EnumVal(${header.PTYPE}, BifType::Enum::DCE_RPC::PType));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
# Bind.
|
|
||||||
function process_dce_rpc_bind(bind: DCE_RPC_Bind): bool
|
function process_dce_rpc_bind(bind: DCE_RPC_Bind): bool
|
||||||
%{
|
%{
|
||||||
$const_def{bind_elems = bind.p_context_elem};
|
if ( dce_rpc_bind )
|
||||||
|
{
|
||||||
if ( ${bind_elems.n_context_elem} > 1 ) {
|
|
||||||
${connection.bro_analyzer}->Weird(
|
|
||||||
"DCE_RPC_bind_to_multiple_interfaces");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dce_rpc_bind ) {
|
|
||||||
// Go over the elements, each having a UUID
|
// Go over the elements, each having a UUID
|
||||||
for ( int i = 0; i < ${bind_elems.n_context_elem}; ++i ) {
|
$const_def{bind_elems = bind.context_list};
|
||||||
$const_def{if_uuid =
|
for ( int i = 0; i < ${bind_elems.num_contexts}; ++i )
|
||||||
bind_elems.p_cont_elem[i].abstract_syntax.if_uuid};
|
{
|
||||||
|
if ( ${bind_elems.request_contexts[i].abstract_syntax} )
|
||||||
|
{
|
||||||
|
$const_def{uuid = bind_elems.request_contexts[i].abstract_syntax.uuid};
|
||||||
|
$const_def{ver_major = bind_elems.request_contexts[i].abstract_syntax.ver_major};
|
||||||
|
$const_def{ver_minor = bind_elems.request_contexts[i].abstract_syntax.ver_minor};
|
||||||
|
|
||||||
// Queue the event
|
// Queue the event
|
||||||
BifEvent::generate_dce_rpc_bind(
|
BifEvent::generate_dce_rpc_bind(bro_analyzer(),
|
||||||
${connection.bro_analyzer},
|
bro_analyzer()->Conn(),
|
||||||
${connection.bro_analyzer}->Conn(),
|
fid,
|
||||||
bytestring_to_val(${if_uuid}));
|
bytestring_to_val(${uuid}),
|
||||||
|
${ver_major},
|
||||||
// Set the connection's UUID
|
${ver_minor});
|
||||||
// ${connection}->set_uuid(${if_uuid});
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ${bind_elems.n_context_elem} > 0;
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function process_dce_rpc_bind_ack(bind: DCE_RPC_Bind_Ack): bool
|
||||||
|
%{
|
||||||
|
if ( dce_rpc_bind_ack )
|
||||||
|
{
|
||||||
|
StringVal *sec_addr;
|
||||||
|
// Remove the null from the end of the string if it's there.
|
||||||
|
if ( ${bind.sec_addr}.length() > 0 &&
|
||||||
|
*(${bind.sec_addr}.begin() + ${bind.sec_addr}.length()) == 0 )
|
||||||
|
{
|
||||||
|
sec_addr = new StringVal(${bind.sec_addr}.length()-1, (const char*) ${bind.sec_addr}.begin());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sec_addr = new StringVal(${bind.sec_addr}.length(), (const char*) ${bind.sec_addr}.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
BifEvent::generate_dce_rpc_bind_ack(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
fid,
|
||||||
|
sec_addr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
# Request.
|
|
||||||
function process_dce_rpc_request(req: DCE_RPC_Request): bool
|
function process_dce_rpc_request(req: DCE_RPC_Request): bool
|
||||||
%{
|
%{
|
||||||
if ( dce_rpc_request )
|
if ( dce_rpc_request )
|
||||||
{
|
{
|
||||||
BifEvent::generate_dce_rpc_request(
|
BifEvent::generate_dce_rpc_request(bro_analyzer(),
|
||||||
${connection.bro_analyzer},
|
bro_analyzer()->Conn(),
|
||||||
${connection.bro_analyzer}->Conn(),
|
fid,
|
||||||
${req.opnum},
|
${req.opnum},
|
||||||
bytestring_to_val(${req.stub}));
|
${req.stub}.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
${connection}->set_cont_id_opnum_map(${req.p_cont_id},
|
set_cont_id_opnum_map(${req.context_id},
|
||||||
${req.opnum});
|
${req.opnum});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
# Response.
|
|
||||||
function process_dce_rpc_response(resp: DCE_RPC_Response): bool
|
function process_dce_rpc_response(resp: DCE_RPC_Response): bool
|
||||||
%{
|
%{
|
||||||
if ( dce_rpc_response )
|
if ( dce_rpc_response )
|
||||||
{
|
{
|
||||||
BifEvent::generate_dce_rpc_response(
|
BifEvent::generate_dce_rpc_response(bro_analyzer(),
|
||||||
${connection.bro_analyzer},
|
bro_analyzer()->Conn(),
|
||||||
${connection.bro_analyzer}->Conn(),
|
fid,
|
||||||
${connection}->get_cont_id_opnum_map(${resp.p_cont_id}),
|
get_cont_id_opnum_map(${resp.context_id}),
|
||||||
bytestring_to_val(${resp.stub}));
|
${resp.stub}.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
refine flow DCE_RPC_Flow += {
|
||||||
|
#%member{
|
||||||
|
#FlowBuffer frag_reassembler_;
|
||||||
|
#%}
|
||||||
|
|
||||||
|
# Fragment reassembly.
|
||||||
|
#function reassemble_fragment(frag: bytestring, lastfrag: bool): bool
|
||||||
|
# %{
|
||||||
|
# int orig_data_length = frag_reassembler_.data_length();
|
||||||
|
#
|
||||||
|
# frag_reassembler_.NewData(frag.begin(), frag.end());
|
||||||
|
#
|
||||||
|
# int new_frame_length = orig_data_length + frag.length();
|
||||||
|
# if ( orig_data_length == 0 )
|
||||||
|
# frag_reassembler_.NewFrame(new_frame_length, false);
|
||||||
|
# else
|
||||||
|
# frag_reassembler_.GrowFrame(new_frame_length);
|
||||||
|
#
|
||||||
|
# return lastfrag;
|
||||||
|
# %}
|
||||||
|
|
||||||
|
#function reassembled_body(): const_bytestring
|
||||||
|
# %{
|
||||||
|
# return const_bytestring(
|
||||||
|
# frag_reassembler_.begin(),
|
||||||
|
# frag_reassembler_.end());
|
||||||
|
# %}
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_PDU += &let {
|
||||||
|
proc = $context.connection.proc_dce_rpc_pdu(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_Header += &let {
|
||||||
|
proc = $context.connection.proc_dce_rpc_message(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_Bind += &let {
|
||||||
|
proc = $context.connection.process_dce_rpc_bind(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_Bind_Ack += &let {
|
||||||
|
proc = $context.connection.process_dce_rpc_bind_ack(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_Request += &let {
|
||||||
|
proc = $context.connection.process_dce_rpc_request(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_Response += &let {
|
||||||
|
proc = $context.connection.process_dce_rpc_response(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
56
src/analyzer/protocol/dce-rpc/dce_rpc-auth.pac
Normal file
56
src/analyzer/protocol/dce-rpc/dce_rpc-auth.pac
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
%extern{
|
||||||
|
#include "analyzer/Manager.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
refine connection DCE_RPC_Conn += {
|
||||||
|
%member{
|
||||||
|
analyzer::Analyzer *gssapi;
|
||||||
|
analyzer::Analyzer *ntlm;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
ntlm = 0;
|
||||||
|
gssapi = 0;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
if ( gssapi )
|
||||||
|
{
|
||||||
|
gssapi->Done();
|
||||||
|
delete gssapi;
|
||||||
|
}
|
||||||
|
if ( ntlm )
|
||||||
|
{
|
||||||
|
ntlm->Done();
|
||||||
|
delete ntlm;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
function forward_auth(auth: DCE_RPC_Auth, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
switch ( ${auth.type} )
|
||||||
|
{
|
||||||
|
case 0x09:
|
||||||
|
if ( ! gssapi )
|
||||||
|
gssapi = analyzer_mgr->InstantiateAnalyzer("KRB", bro_analyzer()->Conn());
|
||||||
|
if ( gssapi )
|
||||||
|
gssapi->DeliverStream(${auth.blob}.length(), ${auth.blob}.begin(), is_orig);
|
||||||
|
break;
|
||||||
|
case 0x0a:
|
||||||
|
if ( ! ntlm )
|
||||||
|
ntlm = analyzer_mgr->InstantiateAnalyzer("NTLM", bro_analyzer()->Conn());
|
||||||
|
if ( ntlm )
|
||||||
|
ntlm->DeliverStream(${auth.blob}.length(), ${auth.blob}.begin(), is_orig);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bro_analyzer()->Weird(fmt("unknown_dce_rpc_auth_type_%d",${auth.type}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr DCE_RPC_Auth += &let {
|
||||||
|
proc = $context.connection.forward_auth(this, true);
|
||||||
|
}
|
|
@ -25,101 +25,151 @@ enum dce_rpc_ptype {
|
||||||
type uuid = bytestring &length = 16;
|
type uuid = bytestring &length = 16;
|
||||||
|
|
||||||
type context_handle = record {
|
type context_handle = record {
|
||||||
cxt_attributes: uint32;
|
attrs : uint32;
|
||||||
cxt_uuid: uuid;
|
uuid : bytestring &length = 16;
|
||||||
};
|
};
|
||||||
|
|
||||||
type rpc_if_id_t = record {
|
type DCE_RPC_PDU(is_orig: bool) = record {
|
||||||
if_uuid : uuid;
|
# Set header's byteorder to little-endian (or big-endian) to
|
||||||
vers_major : uint16;
|
# avoid cyclic dependency.
|
||||||
vers_minor : uint16;
|
header : DCE_RPC_Header(is_orig);
|
||||||
};
|
# TODO: bring back reassembly. It was having trouble.
|
||||||
|
#frag : bytestring &length = body_length;
|
||||||
|
body : DCE_RPC_Body(header);
|
||||||
|
auth : DCE_RPC_Auth_wrapper(header);
|
||||||
|
} &let {
|
||||||
|
#body_length : int = header.frag_length - sizeof(header) - header.auth_length;
|
||||||
|
#frag_reassembled : bool = $context.flow.reassemble_fragment(frag, header.lastfrag);
|
||||||
|
#body : DCE_RPC_Body(header)
|
||||||
|
# withinput $context.flow.reassembled_body()
|
||||||
|
# &if frag_reassembled;
|
||||||
|
} &byteorder = header.byteorder, &length = header.frag_length;
|
||||||
|
|
||||||
type NDR_Format = record {
|
type NDR_Format = record {
|
||||||
intchar : uint8;
|
intchar : uint8;
|
||||||
floatspec : uint8;
|
floatspec : uint8;
|
||||||
reserved : padding[2];
|
reserved : padding[2];
|
||||||
} &let {
|
} &let {
|
||||||
byteorder = (intchar >> 4) ? littleendian : bigendian;
|
byteorder = (intchar >> 4) ? littleendian : bigendian;
|
||||||
};
|
};
|
||||||
|
|
||||||
#### There might be a endianness problem here: the frag_length
|
# There might be a endianness problem here: the frag_length
|
||||||
# causes problems despite the NDR_Format having a byteorder set.
|
# causes problems despite the NDR_Format having a byteorder set.
|
||||||
|
|
||||||
type DCE_RPC_Header = record {
|
type DCE_RPC_Header(is_orig: bool) = record {
|
||||||
rpc_vers : uint8 &check(rpc_vers == 5);
|
rpc_vers : uint8 &check(rpc_vers == 5);
|
||||||
rpc_vers_minor : uint8;
|
rpc_vers_minor : uint8;
|
||||||
PTYPE : uint8;
|
PTYPE : uint8;
|
||||||
pfc_flags : uint8;
|
pfc_flags : uint8;
|
||||||
packed_drep : NDR_Format;
|
packed_drep : NDR_Format;
|
||||||
frag_length : uint16;
|
frag_length : uint16;
|
||||||
auth_length : uint16;
|
auth_length : uint16;
|
||||||
call_id : uint32;
|
call_id : uint32;
|
||||||
} &let {
|
} &let {
|
||||||
frag = pfc_flags & 4;
|
frag = pfc_flags & 4;
|
||||||
lastfrag = (! frag) || (pfc_flags & 2);
|
lastfrag = (! frag) || (pfc_flags & 2);
|
||||||
} &byteorder = packed_drep.byteorder;
|
} &byteorder = packed_drep.byteorder;
|
||||||
|
|
||||||
type p_context_id_t = uint16;
|
type Syntax = record {
|
||||||
|
uuid : bytestring &length = 16;
|
||||||
type p_syntax_id_t = record {
|
ver_major : uint16;
|
||||||
if_uuid : uuid;
|
ver_minor : uint16;
|
||||||
if_version : uint32;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type p_cont_elem_t = record {
|
type ContextRequest = record {
|
||||||
p_cont_id : p_context_id_t;
|
id : uint16;
|
||||||
n_transfer_syn : uint8;
|
num_syntaxes : uint8;
|
||||||
reserved : padding[1];
|
reserved : padding[1];
|
||||||
abstract_syntax : p_syntax_id_t;
|
abstract_syntax : Syntax;
|
||||||
transfer_syntaxes : p_syntax_id_t[n_transfer_syn];
|
transfer_syntaxes : Syntax[num_syntaxes];
|
||||||
};
|
};
|
||||||
|
|
||||||
type p_cont_list_t = record {
|
type ContextReply = record {
|
||||||
n_context_elem : uint8;
|
ack_result : uint16;
|
||||||
reserved : padding[3];
|
ack_reason : uint16;
|
||||||
p_cont_elem : p_cont_elem_t[n_context_elem];
|
syntax : Syntax;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ContextList(is_request: bool) = record {
|
||||||
|
num_contexts : uint8;
|
||||||
|
reserved : padding[3];
|
||||||
|
req_reply : case is_request of {
|
||||||
|
true -> request_contexts : ContextRequest[num_contexts];
|
||||||
|
false -> reply_contexts : ContextReply[num_contexts];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type DCE_RPC_Bind = record {
|
type DCE_RPC_Bind = record {
|
||||||
max_xmit_frag : uint16;
|
max_xmit_frag : uint16;
|
||||||
max_recv_frag : uint16;
|
max_recv_frag : uint16;
|
||||||
assoc_group_id : uint32;
|
assoc_group_id : uint32;
|
||||||
p_context_elem : p_cont_list_t;
|
context_list : ContextList(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
type DCE_RPC_AlterContext = record {
|
type DCE_RPC_Bind_Ack = record {
|
||||||
max_xmit_frag : uint16;
|
max_xmit_frag : uint16;
|
||||||
max_recv_frag : uint16;
|
max_recv_frag : uint16;
|
||||||
assoc_group_id : uint32;
|
assoc_group_id : uint32;
|
||||||
p_context_elem : p_cont_list_t;
|
sec_addr_length : uint16;
|
||||||
|
sec_addr : bytestring &length=sec_addr_length;
|
||||||
|
pad : padding align 4;
|
||||||
|
contexts : ContextList(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
type DCE_RPC_Request = record {
|
type DCE_RPC_Request = record {
|
||||||
alloc_hint : uint32;
|
alloc_hint : uint32;
|
||||||
p_cont_id : p_context_id_t;
|
context_id : uint16;
|
||||||
opnum : uint16;
|
opnum : uint16;
|
||||||
# object : uuid;
|
# object : uuid;
|
||||||
# stub_pad_0 : padding align 8;
|
# stub_pad_0 : padding align 8;
|
||||||
stub : bytestring &restofdata;
|
stub : bytestring &restofdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DCE_RPC_Response = record {
|
type DCE_RPC_Response = record {
|
||||||
alloc_hint : uint32;
|
alloc_hint : uint32;
|
||||||
p_cont_id : p_context_id_t;
|
context_id : uint16;
|
||||||
cancel_count : uint8;
|
cancel_count : uint8;
|
||||||
reserved : uint8;
|
reserved : uint8;
|
||||||
# stub_pad_0 : padding align 8;
|
# stub_pad_0 : padding align 8;
|
||||||
stub : bytestring &restofdata;
|
stub : bytestring &restofdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DCE_RPC_AlterContext = record {
|
||||||
|
max_xmit_frag : uint16;
|
||||||
|
max_recv_frag : uint16;
|
||||||
|
assoc_group_id : uint32;
|
||||||
|
contexts : ContextList(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
type DCE_RPC_AlterContext_Resp = record {
|
||||||
|
max_xmit_frag : uint16;
|
||||||
|
max_recv_frag : uint16;
|
||||||
|
assoc_group_id : uint32;
|
||||||
|
sec_addr_len : uint16;
|
||||||
|
contexts : ContextList(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of {
|
type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of {
|
||||||
DCE_RPC_BIND -> bind : DCE_RPC_Bind;
|
DCE_RPC_BIND -> bind : DCE_RPC_Bind;
|
||||||
DCE_RPC_REQUEST -> request : DCE_RPC_Request;
|
DCE_RPC_BIND_ACK -> bind_ack : DCE_RPC_Bind_Ack;
|
||||||
DCE_RPC_RESPONSE -> response : DCE_RPC_Response;
|
DCE_RPC_REQUEST -> request : DCE_RPC_Request;
|
||||||
default -> other : bytestring &restofdata;
|
DCE_RPC_RESPONSE -> response : DCE_RPC_Response;
|
||||||
|
# TODO: Something about the two following structures isn't being handled correctly.
|
||||||
|
#DCE_RPC_ALTER_CONTEXT -> alter_context : DCE_RPC_AlterContext;
|
||||||
|
#DCE_RPC_ALTER_CONTEXT_RESP -> alter_resp : DCE_RPC_AlterContext_Resp;
|
||||||
|
default -> other : bytestring &restofdata;
|
||||||
|
} &length=header.frag_length - 16 - header.auth_length - (header.auth_length==0 ? 0 : 8);
|
||||||
|
|
||||||
|
type DCE_RPC_Auth_wrapper(header: DCE_RPC_Header) = case header.auth_length of {
|
||||||
|
0 -> none : empty;
|
||||||
|
default -> auth : DCE_RPC_Auth(header);
|
||||||
};
|
};
|
||||||
|
|
||||||
type DCE_RPC_Auth(header: DCE_RPC_Header) = uint8[header.auth_length];
|
type DCE_RPC_Auth(header: DCE_RPC_Header) = record {
|
||||||
|
type : uint8;
|
||||||
%include epmapper.pac
|
level : uint8;
|
||||||
|
pad_len : uint8;
|
||||||
|
reserved : uint8;
|
||||||
|
context_id : uint32;
|
||||||
|
blob : bytestring &length=header.auth_length;
|
||||||
|
};
|
||||||
|
|
|
@ -2,13 +2,27 @@
|
||||||
%include bro.pac
|
%include bro.pac
|
||||||
|
|
||||||
%extern{
|
%extern{
|
||||||
|
#include "types.bif.h"
|
||||||
#include "events.bif.h"
|
#include "events.bif.h"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
analyzer DCE_RPC withcontext {
|
analyzer DCE_RPC withcontext {
|
||||||
connection: DCE_RPC_Conn;
|
connection : DCE_RPC_Conn;
|
||||||
flow: DCE_RPC_Flow;
|
flow : DCE_RPC_Flow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
connection DCE_RPC_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = DCE_RPC_Flow(true);
|
||||||
|
downflow = DCE_RPC_Flow(false);
|
||||||
|
};
|
||||||
%include dce_rpc-protocol.pac
|
%include dce_rpc-protocol.pac
|
||||||
|
|
||||||
|
# Now we define the flow:
|
||||||
|
flow DCE_RPC_Flow(is_orig: bool) {
|
||||||
|
flowunit = DCE_RPC_PDU(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include endpoint-atsvc.pac
|
||||||
|
%include endpoint-epmapper.pac
|
||||||
%include dce_rpc-analyzer.pac
|
%include dce_rpc-analyzer.pac
|
||||||
|
%include dce_rpc-auth.pac
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
%include bro.pac
|
|
||||||
|
|
||||||
%extern{
|
|
||||||
#include "events.bif.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
analyzer DCE_RPC_Simple withcontext {};
|
|
||||||
|
|
||||||
%include dce_rpc-protocol.pac
|
|
||||||
|
|
||||||
type DCE_RPC_PDU = record {
|
|
||||||
# Set header's byteorder to little-endian (or big-endian) to
|
|
||||||
# avoid cyclic dependency.
|
|
||||||
header : DCE_RPC_Header;
|
|
||||||
body : DCE_RPC_Body(header)
|
|
||||||
&length = header.frag_length - sizeof(header) -
|
|
||||||
header.auth_length;
|
|
||||||
auth : DCE_RPC_Auth(header);
|
|
||||||
} &byteorder = header.byteorder,
|
|
||||||
&length = header.frag_length;
|
|
39
src/analyzer/protocol/dce-rpc/endpoint-atsvc.pac
Normal file
39
src/analyzer/protocol/dce-rpc/endpoint-atsvc.pac
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
type ATSVC_Request(unicode: bool, opnum: uint8) = record {
|
||||||
|
empty: padding[1];
|
||||||
|
op: case opnum of {
|
||||||
|
0 -> add : ATSVC_NetrJobAdd(unicode);
|
||||||
|
default -> unknown : bytestring &restofdata;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type ATSVC_String_Pointer(unicode: bool) = record {
|
||||||
|
referent_id : uint32;
|
||||||
|
max_count : uint32;
|
||||||
|
offset : uint32;
|
||||||
|
actual_count : uint32;
|
||||||
|
string : bytestring &length=max_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ATSVC_NetrJobAdd(unicode: bool) = record {
|
||||||
|
server : ATSVC_String_Pointer(unicode);
|
||||||
|
unknown : padding[2];
|
||||||
|
job_time : uint32;
|
||||||
|
days_of_month : uint32;
|
||||||
|
days_of_week : uint8;
|
||||||
|
flags : uint8;
|
||||||
|
unknown2 : padding[2];
|
||||||
|
command : ATSVC_String_Pointer(unicode);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ATSVC_Reply(unicode: bool, opnum: uint16) = record {
|
||||||
|
op: case opnum of {
|
||||||
|
0 -> add: ATSVC_JobID(unicode);
|
||||||
|
default -> unknown: bytestring &restofdata;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type ATSVC_JobID(unicode: bool) = record {
|
||||||
|
id : uint32;
|
||||||
|
status : uint32;
|
||||||
|
};
|
|
@ -1,55 +1,74 @@
|
||||||
## TODO.
|
## Generated for every DCE-RPC message.
|
||||||
##
|
##
|
||||||
## .. bro:see:: rpc_call rpc_dialogue rpc_reply dce_rpc_bind dce_rpc_request
|
## c: The connection.
|
||||||
## dce_rpc_response rpc_timeout
|
|
||||||
##
|
##
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
## is_orig: True if the message was sent by the originator of the TCP connection.
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
##
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||||
## register a port for it or add a DPD payload signature.
|
## DCE-RPC was not transported over a pipe.
|
||||||
event dce_rpc_message%(c: connection, is_orig: bool, ptype: dce_rpc_ptype, msg: string%);
|
##
|
||||||
|
## ptype_id: Numeric representation of the procedure type of the message.
|
||||||
|
##
|
||||||
|
## ptype: Enum representation of the prodecure type of the message.
|
||||||
|
##
|
||||||
|
## .. bro:see:: dce_rpc_bind dce_rpc_bind_ack dce_rpc_request dce_rpc_response
|
||||||
|
event dce_rpc_message%(c: connection, is_orig: bool, fid: count, ptype_id: count, ptype: DCE_RPC::PType%);
|
||||||
|
|
||||||
## TODO.
|
## Generated for every DCE-RPC bind request message. Since RPC offers the ability
|
||||||
|
## for a client to request connections to multiple endpoints, this event can occur
|
||||||
|
## multiple times for a single RPC message.
|
||||||
##
|
##
|
||||||
## .. bro:see:: rpc_call rpc_dialogue rpc_reply dce_rpc_message dce_rpc_request
|
## c: The connection.
|
||||||
## dce_rpc_response rpc_timeout
|
|
||||||
##
|
##
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
## DCE-RPC was not transported over a pipe.
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
##
|
||||||
## register a port for it or add a DPD payload signature.
|
## uuid: The string interpretted uuid of the endpoint being requested.
|
||||||
event dce_rpc_bind%(c: connection, uuid: string%);
|
##
|
||||||
|
## ver_major: The major version of the endpoint being requested.
|
||||||
|
##
|
||||||
|
## ver_minor: The minor version of the endpoint being requested.
|
||||||
|
##
|
||||||
|
## .. bro:see:: dce_rpc_message dce_rpc_bind_ack dce_rpc_request dce_rpc_response
|
||||||
|
event dce_rpc_bind%(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count%);
|
||||||
|
|
||||||
## TODO.
|
## Generated for every DCE-RPC bind request ack message.
|
||||||
##
|
##
|
||||||
## .. bro:see:: rpc_call rpc_dialogue rpc_reply dce_rpc_bind dce_rpc_message
|
## c: The connection.
|
||||||
## dce_rpc_response rpc_timeout
|
|
||||||
##
|
##
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
## DCE-RPC was not transported over a pipe.
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
##
|
||||||
## register a port for it or add a DPD payload signature.
|
## sec_addr: Secondary address for the ack.
|
||||||
event dce_rpc_request%(c: connection, opnum: count, stub: string%);
|
##
|
||||||
|
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_request dce_rpc_response
|
||||||
|
event dce_rpc_bind_ack%(c: connection, fid: count, sec_addr: string%);
|
||||||
|
|
||||||
## TODO.
|
## Generated for every DCE-RPC request message.
|
||||||
##
|
##
|
||||||
## .. bro:see:: rpc_call rpc_dialogue rpc_reply dce_rpc_bind dce_rpc_message
|
## c: The connection.
|
||||||
## dce_rpc_request rpc_timeout
|
|
||||||
##
|
##
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
## DCE-RPC was not transported over a pipe.
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
##
|
||||||
## register a port for it or add a DPD payload signature.
|
## opnum: Number of the RPC operation.
|
||||||
event dce_rpc_response%(c: connection, opnum: count, stub: string%);
|
##
|
||||||
|
## stub_len: Length of the data for the request.
|
||||||
|
##
|
||||||
|
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_response
|
||||||
|
event dce_rpc_request%(c: connection, fid: count, opnum: count, stub_len: count%);
|
||||||
|
|
||||||
## TODO.
|
## Generated for every DCE-RPC response message.
|
||||||
##
|
##
|
||||||
## .. bro:see:: rpc_call rpc_dialogue rpc_reply dce_rpc_bind dce_rpc_message
|
## c: The connection.
|
||||||
## dce_rpc_request dce_rpc_response rpc_timeout
|
|
||||||
##
|
##
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
## DCE-RPC was not transported over a pipe.
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
##
|
||||||
## register a port for it or add a DPD payload signature.
|
## opnum: Number of the RPC operation.
|
||||||
event epm_map_response%(c: connection, uuid: string, p: port, h: addr%);
|
##
|
||||||
|
## stub_len: Length of the data for the response.
|
||||||
|
##
|
||||||
|
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request
|
||||||
|
event dce_rpc_response%(c: connection, fid: count, opnum: count, stub_len: count%);
|
||||||
|
|
||||||
|
|
41
src/analyzer/protocol/dce-rpc/types.bif
Normal file
41
src/analyzer/protocol/dce-rpc/types.bif
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
module DCE_RPC;
|
||||||
|
|
||||||
|
enum PType %{
|
||||||
|
REQUEST,
|
||||||
|
PING,
|
||||||
|
RESPONSE,
|
||||||
|
FAULT,
|
||||||
|
WORKING,
|
||||||
|
NOCALL,
|
||||||
|
REJECT,
|
||||||
|
ACK,
|
||||||
|
CL_CANCEL,
|
||||||
|
FACK,
|
||||||
|
CANCEL_ACK,
|
||||||
|
BIND,
|
||||||
|
BIND_ACK,
|
||||||
|
BIND_NAK,
|
||||||
|
ALTER_CONTEXT,
|
||||||
|
ALTER_CONTEXT_RESP,
|
||||||
|
SHUTDOWN,
|
||||||
|
CO_CANCEL,
|
||||||
|
ORPHANED,
|
||||||
|
%}
|
||||||
|
|
||||||
|
enum IfID %{
|
||||||
|
unknown_if,
|
||||||
|
epmapper,
|
||||||
|
lsarpc,
|
||||||
|
lsa_ds,
|
||||||
|
mgmt,
|
||||||
|
netlogon,
|
||||||
|
samr,
|
||||||
|
srvsvc,
|
||||||
|
spoolss,
|
||||||
|
drs,
|
||||||
|
winspipe,
|
||||||
|
wkssvc,
|
||||||
|
oxid,
|
||||||
|
ISCMActivator,
|
||||||
|
%}
|
16
src/analyzer/protocol/gssapi/CMakeLists.txt
Normal file
16
src/analyzer/protocol/gssapi/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
include(BroPlugin)
|
||||||
|
|
||||||
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
bro_plugin_begin(Bro GSSAPI)
|
||||||
|
bro_plugin_cc(GSSAPI.cc Plugin.cc)
|
||||||
|
bro_plugin_bif(types.bif events.bif)
|
||||||
|
bro_plugin_pac(
|
||||||
|
gssapi.pac
|
||||||
|
gssapi-protocol.pac
|
||||||
|
gssapi-analyzer.pac
|
||||||
|
../asn1/asn1.pac
|
||||||
|
)
|
||||||
|
bro_plugin_end()
|
||||||
|
|
56
src/analyzer/protocol/gssapi/GSSAPI.cc
Normal file
56
src/analyzer/protocol/gssapi/GSSAPI.cc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "GSSAPI.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
|
||||||
|
using namespace analyzer::gssapi;
|
||||||
|
|
||||||
|
GSSAPI_Analyzer::GSSAPI_Analyzer(Connection* c)
|
||||||
|
: tcp::TCP_ApplicationAnalyzer("GSSAPI", c)
|
||||||
|
{
|
||||||
|
interp = new binpac::GSSAPI::GSSAPI_Conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GSSAPI_Analyzer::~GSSAPI_Analyzer()
|
||||||
|
{
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::Done()
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Done();
|
||||||
|
|
||||||
|
interp->FlowEOF(true);
|
||||||
|
interp->FlowEOF(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::EndpointEOF(bool is_orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||||
|
interp->FlowEOF(is_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
|
||||||
|
assert(TCP());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
ProtocolConfirmation();
|
||||||
|
}
|
||||||
|
catch ( const binpac::Exception& e )
|
||||||
|
{
|
||||||
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||||
|
interp->NewGap(orig, len);
|
||||||
|
}
|
39
src/analyzer/protocol/gssapi/GSSAPI.h
Normal file
39
src/analyzer/protocol/gssapi/GSSAPI.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#ifndef ANALYZER_PROTOCOL_GSSAPI_GSSAPI_H
|
||||||
|
#define ANALYZER_PROTOCOL_GSSAPI_GSSAPI_H
|
||||||
|
|
||||||
|
#include "events.bif.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
|
|
||||||
|
#include "gssapi_pac.h"
|
||||||
|
|
||||||
|
namespace analyzer { namespace gssapi {
|
||||||
|
|
||||||
|
class GSSAPI_Analyzer
|
||||||
|
|
||||||
|
: public tcp::TCP_ApplicationAnalyzer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSSAPI_Analyzer(Connection* conn);
|
||||||
|
virtual ~GSSAPI_Analyzer();
|
||||||
|
|
||||||
|
// Overriden from Analyzer.
|
||||||
|
void Done() override;
|
||||||
|
|
||||||
|
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||||
|
void Undelivered(uint64 seq, int len, bool orig) override;
|
||||||
|
|
||||||
|
// Overriden from tcp::TCP_ApplicationAnalyzer.
|
||||||
|
void EndpointEOF(bool is_orig) override;
|
||||||
|
|
||||||
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
|
{ return new GSSAPI_Analyzer(conn); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binpac::GSSAPI::GSSAPI_Conn* interp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // namespace analyzer::*
|
||||||
|
|
||||||
|
#endif
|
24
src/analyzer/protocol/gssapi/Plugin.cc
Normal file
24
src/analyzer/protocol/gssapi/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// See the file in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "plugin/Plugin.h"
|
||||||
|
|
||||||
|
#include "GSSAPI.h"
|
||||||
|
|
||||||
|
namespace plugin {
|
||||||
|
namespace Bro_GSSAPI {
|
||||||
|
|
||||||
|
class Plugin : public plugin::Plugin {
|
||||||
|
public:
|
||||||
|
plugin::Configuration Configure()
|
||||||
|
{
|
||||||
|
AddComponent(new ::analyzer::Component("GSSAPI", ::analyzer::gssapi::GSSAPI_Analyzer::Instantiate));
|
||||||
|
|
||||||
|
plugin::Configuration config;
|
||||||
|
config.name = "Bro::GSSAPI";
|
||||||
|
config.description = "GSSAPI analyzer";
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
} plugin;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
7
src/analyzer/protocol/gssapi/events.bif
Normal file
7
src/analyzer/protocol/gssapi/events.bif
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
## Generated for GSSAPI negotiation results.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## state: The resulting state of the negotiation.
|
||||||
|
##
|
||||||
|
event gssapi_neg_result%(c: connection, state: count%);
|
46
src/analyzer/protocol/gssapi/gssapi-analyzer.pac
Normal file
46
src/analyzer/protocol/gssapi/gssapi-analyzer.pac
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
refine connection GSSAPI_Conn += {
|
||||||
|
%member{
|
||||||
|
analyzer::Analyzer *ntlm;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
ntlm = analyzer_mgr->InstantiateAnalyzer("NTLM", bro_analyzer->Conn());
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
if ( ntlm )
|
||||||
|
{
|
||||||
|
ntlm->Done();
|
||||||
|
delete ntlm;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
function forward_ntlm(data: bytestring, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
if ( ntlm )
|
||||||
|
ntlm->DeliverStream(${data}.length(), ${data}.begin(), is_orig);
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_gssapi_neg_result(val: GSSAPI_NEG_TOKEN_RESP_Arg): bool
|
||||||
|
%{
|
||||||
|
if ( gssapi_neg_result )
|
||||||
|
{
|
||||||
|
BifEvent::generate_gssapi_neg_result(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
binary_to_int64(${val.neg_state.encoding.content}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
}
|
||||||
|
|
||||||
|
refine typeattr GSSAPI_NEG_TOKEN_MECH_TOKEN += &let {
|
||||||
|
fwd: bool = $context.connection.forward_ntlm(mech_token, is_orig);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr GSSAPI_NEG_TOKEN_RESP_Arg += &let {
|
||||||
|
proc: bool = $context.connection.proc_gssapi_neg_result(this) &if(seq_meta.index==0);
|
||||||
|
};
|
||||||
|
|
55
src/analyzer/protocol/gssapi/gssapi-protocol.pac
Normal file
55
src/analyzer/protocol/gssapi/gssapi-protocol.pac
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN(is_orig: bool) = record {
|
||||||
|
wrapper : ASN1EncodingMeta;
|
||||||
|
have_oid : case is_init of {
|
||||||
|
true -> oid : ASN1Encoding;
|
||||||
|
false -> no_oid : empty;
|
||||||
|
};
|
||||||
|
have_init_wrapper : case is_init of {
|
||||||
|
true -> init_wrapper : ASN1EncodingMeta;
|
||||||
|
false -> no_init_wrapper : empty;
|
||||||
|
};
|
||||||
|
msg_type : case is_init of {
|
||||||
|
true -> init : GSSAPI_NEG_TOKEN_INIT;
|
||||||
|
false -> resp : GSSAPI_NEG_TOKEN_RESP;
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
is_init: bool = wrapper.tag == 0x60;
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_INIT = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_INIT_Arg[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_INIT_Arg = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_INIT_Arg_Data(seq_meta.index) &length=seq_meta.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_INIT_Arg_Data(index: uint8) = case index of {
|
||||||
|
0 -> mech_type_list : ASN1Encoding;
|
||||||
|
1 -> req_flags : ASN1Encoding;
|
||||||
|
2 -> mech_token : GSSAPI_NEG_TOKEN_MECH_TOKEN(true);
|
||||||
|
3 -> mech_list_mic : ASN1OctetString;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_RESP = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_RESP_Arg[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_RESP_Arg = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : case seq_meta.index of {
|
||||||
|
0 -> neg_state : ASN1Integer;
|
||||||
|
1 -> supported_mech : ASN1Encoding;
|
||||||
|
2 -> response_token : GSSAPI_NEG_TOKEN_MECH_TOKEN(false);
|
||||||
|
3 -> mech_list_mic : ASN1OctetString;
|
||||||
|
} &length=seq_meta.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_MECH_TOKEN(is_orig: bool) = record {
|
||||||
|
meta : ASN1EncodingMeta;
|
||||||
|
mech_token : bytestring &length=meta.length;
|
||||||
|
};
|
30
src/analyzer/protocol/gssapi/gssapi.pac
Normal file
30
src/analyzer/protocol/gssapi/gssapi.pac
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
%include binpac.pac
|
||||||
|
%include bro.pac
|
||||||
|
|
||||||
|
%extern{
|
||||||
|
#include "analyzer/Manager.h"
|
||||||
|
#include "analyzer/Analyzer.h"
|
||||||
|
|
||||||
|
#include "types.bif.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
analyzer GSSAPI withcontext {
|
||||||
|
connection : GSSAPI_Conn;
|
||||||
|
flow : GSSAPI_Flow;
|
||||||
|
};
|
||||||
|
|
||||||
|
connection GSSAPI_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = GSSAPI_Flow(true);
|
||||||
|
downflow = GSSAPI_Flow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include gssapi-protocol.pac
|
||||||
|
%include ../asn1/asn1.pac
|
||||||
|
|
||||||
|
# Now we define the flow:
|
||||||
|
flow GSSAPI_Flow(is_orig: bool) {
|
||||||
|
datagram = GSSAPI_NEG_TOKEN(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include gssapi-analyzer.pac
|
1
src/analyzer/protocol/gssapi/types.bif
Normal file
1
src/analyzer/protocol/gssapi/types.bif
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# Empty.
|
|
@ -47,11 +47,10 @@ NetbiosDGM_RawMsgHdr::NetbiosDGM_RawMsgHdr(const u_char*& data, int& len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NetbiosSSN_Interpreter::NetbiosSSN_Interpreter(analyzer::Analyzer* arg_analyzer,
|
NetbiosSSN_Interpreter::NetbiosSSN_Interpreter(Analyzer* arg_analyzer)
|
||||||
smb::SMB_Session* arg_smb_session)
|
|
||||||
{
|
{
|
||||||
analyzer = arg_analyzer;
|
analyzer = arg_analyzer;
|
||||||
smb_session = arg_smb_session;
|
//smb_session = arg_smb_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NetbiosSSN_Interpreter::ParseMessage(unsigned int type, unsigned int flags,
|
int NetbiosSSN_Interpreter::ParseMessage(unsigned int type, unsigned int flags,
|
||||||
|
@ -106,11 +105,11 @@ int NetbiosSSN_Interpreter::ParseMessage(unsigned int type, unsigned int flags,
|
||||||
int NetbiosSSN_Interpreter::ParseDatagram(const u_char* data, int len,
|
int NetbiosSSN_Interpreter::ParseDatagram(const u_char* data, int len,
|
||||||
int is_query)
|
int is_query)
|
||||||
{
|
{
|
||||||
if ( smb_session )
|
//if ( smb_session )
|
||||||
{
|
// {
|
||||||
smb_session->Deliver(is_query, len, data);
|
// smb_session->Deliver(is_query, len, data);
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -132,8 +131,8 @@ int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
|
||||||
delete srcname;
|
delete srcname;
|
||||||
delete dstname;
|
delete dstname;
|
||||||
|
|
||||||
if ( smb_session )
|
//if ( smb_session )
|
||||||
smb_session->Deliver(is_query, len, data);
|
// smb_session->Deliver(is_query, len, data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -188,12 +187,12 @@ int NetbiosSSN_Interpreter::ParseSessionMsg(const u_char* data, int len,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( smb_session )
|
//if ( smb_session )
|
||||||
{
|
// {
|
||||||
smb_session->Deliver(is_query, len, data);
|
// smb_session->Deliver(is_query, len, data);
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
// }
|
||||||
else
|
//else
|
||||||
{
|
{
|
||||||
analyzer->Weird("no_smb_session_using_parsesambamsg");
|
analyzer->Weird("no_smb_session_using_parsesambamsg");
|
||||||
data += 4;
|
data += 4;
|
||||||
|
@ -458,8 +457,8 @@ void Contents_NetbiosSSN::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
NetbiosSSN_Analyzer::NetbiosSSN_Analyzer(Connection* conn)
|
NetbiosSSN_Analyzer::NetbiosSSN_Analyzer(Connection* conn)
|
||||||
: tcp::TCP_ApplicationAnalyzer("NETBIOS", conn)
|
: tcp::TCP_ApplicationAnalyzer("NETBIOS", conn)
|
||||||
{
|
{
|
||||||
smb_session = new smb::SMB_Session(this);
|
//smb_session = new SMB_Session(this);
|
||||||
interp = new NetbiosSSN_Interpreter(this, smb_session);
|
interp = new NetbiosSSN_Interpreter(this);
|
||||||
orig_netbios = resp_netbios = 0;
|
orig_netbios = resp_netbios = 0;
|
||||||
did_session_done = 0;
|
did_session_done = 0;
|
||||||
|
|
||||||
|
@ -481,7 +480,7 @@ NetbiosSSN_Analyzer::NetbiosSSN_Analyzer(Connection* conn)
|
||||||
NetbiosSSN_Analyzer::~NetbiosSSN_Analyzer()
|
NetbiosSSN_Analyzer::~NetbiosSSN_Analyzer()
|
||||||
{
|
{
|
||||||
delete interp;
|
delete interp;
|
||||||
delete smb_session;
|
//delete smb_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetbiosSSN_Analyzer::Done()
|
void NetbiosSSN_Analyzer::Done()
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "analyzer/protocol/udp/UDP.h"
|
#include "analyzer/protocol/udp/UDP.h"
|
||||||
#include "analyzer/protocol/tcp/TCP.h"
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
#include "analyzer/protocol/smb/SMB.h"
|
//#include "analyzer/protocol/smb/SMB.h"
|
||||||
|
|
||||||
namespace analyzer { namespace netbios_ssn {
|
namespace analyzer { namespace netbios_ssn {
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ struct NetbiosDGM_RawMsgHdr {
|
||||||
|
|
||||||
class NetbiosSSN_Interpreter {
|
class NetbiosSSN_Interpreter {
|
||||||
public:
|
public:
|
||||||
NetbiosSSN_Interpreter(analyzer::Analyzer* analyzer, smb::SMB_Session* smb_session);
|
NetbiosSSN_Interpreter(Analyzer* analyzer);
|
||||||
|
|
||||||
int ParseMessage(unsigned int type, unsigned int flags,
|
int ParseMessage(unsigned int type, unsigned int flags,
|
||||||
const u_char* data, int len, int is_query);
|
const u_char* data, int len, int is_query);
|
||||||
|
@ -99,8 +99,8 @@ protected:
|
||||||
u_char*& xname, int& xlen);
|
u_char*& xname, int& xlen);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
analyzer::Analyzer* analyzer;
|
Analyzer* analyzer;
|
||||||
smb::SMB_Session* smb_session;
|
//SMB_Session* smb_session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ public:
|
||||||
NetbiosSSN_State State() const { return state; }
|
NetbiosSSN_State State() const { return state; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||||
|
|
||||||
NetbiosSSN_Interpreter* interp;
|
NetbiosSSN_Interpreter* interp;
|
||||||
|
|
||||||
|
@ -144,22 +144,22 @@ public:
|
||||||
NetbiosSSN_Analyzer(Connection* conn);
|
NetbiosSSN_Analyzer(Connection* conn);
|
||||||
~NetbiosSSN_Analyzer();
|
~NetbiosSSN_Analyzer();
|
||||||
|
|
||||||
virtual void Done();
|
void Done() override;
|
||||||
virtual void DeliverPacket(int len, const u_char* data, bool orig,
|
void DeliverPacket(int len, const u_char* data, bool orig,
|
||||||
uint64 seq, const IP_Hdr* ip, int caplen);
|
uint64 seq, const IP_Hdr* ip, int caplen) override;
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
{ return new NetbiosSSN_Analyzer(conn); }
|
{ return new NetbiosSSN_Analyzer(conn); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void ConnectionClosed(tcp::TCP_Endpoint* endpoint,
|
void ConnectionClosed(tcp::TCP_Endpoint* endpoint,
|
||||||
tcp::TCP_Endpoint* peer, int gen_event);
|
tcp::TCP_Endpoint* peer, int gen_event) override;
|
||||||
virtual void EndpointEOF(bool is_orig);
|
void EndpointEOF(bool is_orig) override;
|
||||||
|
|
||||||
void ExpireTimer(double t);
|
void ExpireTimer(double t);
|
||||||
|
|
||||||
NetbiosSSN_Interpreter* interp;
|
NetbiosSSN_Interpreter* interp;
|
||||||
smb::SMB_Session* smb_session;
|
//SMB_Session* smb_session;
|
||||||
Contents_NetbiosSSN* orig_netbios;
|
Contents_NetbiosSSN* orig_netbios;
|
||||||
Contents_NetbiosSSN* resp_netbios;
|
Contents_NetbiosSSN* resp_netbios;
|
||||||
int did_session_done;
|
int did_session_done;
|
||||||
|
|
15
src/analyzer/protocol/ntlm/CMakeLists.txt
Normal file
15
src/analyzer/protocol/ntlm/CMakeLists.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
include(BroPlugin)
|
||||||
|
|
||||||
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
bro_plugin_begin(Bro NTLM)
|
||||||
|
bro_plugin_cc(NTLM.cc Plugin.cc)
|
||||||
|
bro_plugin_bif(types.bif events.bif)
|
||||||
|
bro_plugin_pac(
|
||||||
|
ntlm.pac
|
||||||
|
ntlm-protocol.pac
|
||||||
|
ntlm-analyzer.pac
|
||||||
|
)
|
||||||
|
bro_plugin_end()
|
||||||
|
|
56
src/analyzer/protocol/ntlm/NTLM.cc
Normal file
56
src/analyzer/protocol/ntlm/NTLM.cc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "NTLM.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
|
||||||
|
using namespace analyzer::ntlm;
|
||||||
|
|
||||||
|
NTLM_Analyzer::NTLM_Analyzer(Connection* c)
|
||||||
|
: tcp::TCP_ApplicationAnalyzer("NTLM", c)
|
||||||
|
{
|
||||||
|
interp = new binpac::NTLM::NTLM_Conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NTLM_Analyzer::~NTLM_Analyzer()
|
||||||
|
{
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::Done()
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Done();
|
||||||
|
|
||||||
|
interp->FlowEOF(true);
|
||||||
|
interp->FlowEOF(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::EndpointEOF(bool is_orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||||
|
interp->FlowEOF(is_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
|
||||||
|
assert(TCP());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
ProtocolConfirmation();
|
||||||
|
}
|
||||||
|
catch ( const binpac::Exception& e )
|
||||||
|
{
|
||||||
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||||
|
interp->NewGap(orig, len);
|
||||||
|
}
|
39
src/analyzer/protocol/ntlm/NTLM.h
Normal file
39
src/analyzer/protocol/ntlm/NTLM.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#ifndef ANALYZER_PROTOCOL_NTLM_NTLM_H
|
||||||
|
#define ANALYZER_PROTOCOL_NTLM_NTLM_H
|
||||||
|
|
||||||
|
#include "events.bif.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
|
|
||||||
|
#include "ntlm_pac.h"
|
||||||
|
|
||||||
|
namespace analyzer { namespace ntlm {
|
||||||
|
|
||||||
|
class NTLM_Analyzer
|
||||||
|
|
||||||
|
: public tcp::TCP_ApplicationAnalyzer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
NTLM_Analyzer(Connection* conn);
|
||||||
|
virtual ~NTLM_Analyzer();
|
||||||
|
|
||||||
|
// Overriden from Analyzer.
|
||||||
|
void Done() override;
|
||||||
|
|
||||||
|
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||||
|
void Undelivered(uint64 seq, int len, bool orig) override;
|
||||||
|
|
||||||
|
// Overriden from tcp::TCP_ApplicationAnalyzer.
|
||||||
|
void EndpointEOF(bool is_orig) override;
|
||||||
|
|
||||||
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
|
{ return new NTLM_Analyzer(conn); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binpac::NTLM::NTLM_Conn* interp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // namespace analyzer::*
|
||||||
|
|
||||||
|
#endif
|
24
src/analyzer/protocol/ntlm/Plugin.cc
Normal file
24
src/analyzer/protocol/ntlm/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// See the file in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "plugin/Plugin.h"
|
||||||
|
|
||||||
|
#include "NTLM.h"
|
||||||
|
|
||||||
|
namespace plugin {
|
||||||
|
namespace Bro_NTLM {
|
||||||
|
|
||||||
|
class Plugin : public plugin::Plugin {
|
||||||
|
public:
|
||||||
|
plugin::Configuration Configure()
|
||||||
|
{
|
||||||
|
AddComponent(new ::analyzer::Component("NTLM", ::analyzer::ntlm::NTLM_Analyzer::Instantiate));
|
||||||
|
|
||||||
|
plugin::Configuration config;
|
||||||
|
config.name = "Bro::NTLM";
|
||||||
|
config.description = "NTLM analyzer";
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
} plugin;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
23
src/analyzer/protocol/ntlm/events.bif
Normal file
23
src/analyzer/protocol/ntlm/events.bif
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
## Generated for NTLM messages of type *negotiate*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||||
|
##
|
||||||
|
event ntlm_negotiate%(c: connection, negotiate: NTLM::Negotiate%);
|
||||||
|
|
||||||
|
## Generated for NTLM messages of type *challenge*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||||
|
##
|
||||||
|
event ntlm_challenge%(c: connection, challenge: NTLM::Challenge%);
|
||||||
|
|
||||||
|
## Generated for NTLM messages of type *authenticate*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## request: The parsed data of the NTLM message. See init-bare for more details.
|
||||||
|
##
|
||||||
|
event ntlm_authenticate%(c: connection, request: NTLM::Authenticate%);
|
172
src/analyzer/protocol/ntlm/ntlm-analyzer.pac
Normal file
172
src/analyzer/protocol/ntlm/ntlm-analyzer.pac
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
|
||||||
|
refine connection NTLM_Conn += {
|
||||||
|
|
||||||
|
# This is replicated from the SMB analyzer. :(
|
||||||
|
function filetime2brotime(ts: uint64): Val
|
||||||
|
%{
|
||||||
|
double secs = (ts / 10000000.0);
|
||||||
|
|
||||||
|
// Bro can't support times back to the 1600's
|
||||||
|
// so we subtract a lot of seconds.
|
||||||
|
Val* bro_ts = new Val(secs - 11644473600.0, TYPE_TIME);
|
||||||
|
|
||||||
|
return bro_ts;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function build_version_record(val: NTLM_Version): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Version);
|
||||||
|
result->Assign(0, new Val(${val.major_version}, TYPE_COUNT));
|
||||||
|
result->Assign(1, new Val(${val.minor_version}, TYPE_COUNT));
|
||||||
|
result->Assign(2, new Val(${val.build_number}, TYPE_COUNT));
|
||||||
|
result->Assign(3, new Val(${val.ntlm_revision}, TYPE_COUNT));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function build_av_record(val: NTLM_AV_Pair_Sequence): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::AVs);
|
||||||
|
for ( uint i = 0; ${val.pairs[i].id} != 0; i++ )
|
||||||
|
{
|
||||||
|
switch ( ${val.pairs[i].id} )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
result->Assign(0, utf16_bytestring_to_utf8_val(${val.pairs[i].nb_computer_name.data}));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result->Assign(1, utf16_bytestring_to_utf8_val(${val.pairs[i].nb_domain_name.data}));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
result->Assign(2, utf16_bytestring_to_utf8_val(${val.pairs[i].dns_computer_name.data}));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
result->Assign(3, utf16_bytestring_to_utf8_val(${val.pairs[i].dns_domain_name.data}));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
result->Assign(4, utf16_bytestring_to_utf8_val(${val.pairs[i].dns_tree_name.data}));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
result->Assign(5, new Val(${val.pairs[i].constrained_auth}, TYPE_BOOL));
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
result->Assign(6, filetime2brotime(${val.pairs[i].timestamp}));
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
result->Assign(7, new Val(${val.pairs[i].single_host.machine_id}, TYPE_COUNT));
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
result->Assign(8, utf16_bytestring_to_utf8_val(${val.pairs[i].target_name.data}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function build_negotiate_flag_record(val: NTLM_Negotiate_Flags): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* flags = new RecordVal(BifType::Record::NTLM::NegotiateFlags);
|
||||||
|
flags->Assign(0, new Val(${val.negotiate_56}, TYPE_BOOL));
|
||||||
|
flags->Assign(1, new Val(${val.negotiate_key_exch}, TYPE_BOOL));
|
||||||
|
flags->Assign(2, new Val(${val.negotiate_128}, TYPE_BOOL));
|
||||||
|
flags->Assign(3, new Val(${val.negotiate_version}, TYPE_BOOL));
|
||||||
|
flags->Assign(4, new Val(${val.negotiate_target_info}, TYPE_BOOL));
|
||||||
|
flags->Assign(5, new Val(${val.request_non_nt_session_key}, TYPE_BOOL));
|
||||||
|
flags->Assign(6, new Val(${val.negotiate_identify}, TYPE_BOOL));
|
||||||
|
flags->Assign(7, new Val(${val.negotiate_extended_sessionsecurity}, TYPE_BOOL));
|
||||||
|
flags->Assign(8, new Val(${val.target_type_server}, TYPE_BOOL));
|
||||||
|
flags->Assign(9, new Val(${val.target_type_domain}, TYPE_BOOL));
|
||||||
|
flags->Assign(10, new Val(${val.negotiate_always_sign}, TYPE_BOOL));
|
||||||
|
flags->Assign(11, new Val(${val.negotiate_oem_workstation_supplied}, TYPE_BOOL));
|
||||||
|
flags->Assign(12, new Val(${val.negotiate_oem_domain_supplied}, TYPE_BOOL));
|
||||||
|
flags->Assign(13, new Val(${val.negotiate_anonymous_connection}, TYPE_BOOL));
|
||||||
|
flags->Assign(14, new Val(${val.negotiate_ntlm}, TYPE_BOOL));
|
||||||
|
flags->Assign(15, new Val(${val.negotiate_lm_key}, TYPE_BOOL));
|
||||||
|
flags->Assign(16, new Val(${val.negotiate_datagram}, TYPE_BOOL));
|
||||||
|
flags->Assign(17, new Val(${val.negotiate_seal}, TYPE_BOOL));
|
||||||
|
flags->Assign(18, new Val(${val.negotiate_sign}, TYPE_BOOL));
|
||||||
|
flags->Assign(19, new Val(${val.request_target}, TYPE_BOOL));
|
||||||
|
flags->Assign(20, new Val(${val.negotiate_oem}, TYPE_BOOL));
|
||||||
|
flags->Assign(21, new Val(${val.negotiate_unicode}, TYPE_BOOL));
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_ntlm_negotiate(val: NTLM_Negotiate): bool
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Negotiate);
|
||||||
|
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_oem_domain_supplied} )
|
||||||
|
result->Assign(1, utf16_bytestring_to_utf8_val(${val.domain_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_oem_workstation_supplied} )
|
||||||
|
result->Assign(2, utf16_bytestring_to_utf8_val(${val.workstation.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_version} )
|
||||||
|
result->Assign(3, build_version_record(${val.version}));
|
||||||
|
|
||||||
|
BifEvent::generate_ntlm_negotiate(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
result);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_ntlm_challenge(val: NTLM_Challenge): bool
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Challenge);
|
||||||
|
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||||
|
|
||||||
|
if ( ${val.flags.request_target} )
|
||||||
|
result->Assign(1, utf16_bytestring_to_utf8_val(${val.target_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_version} )
|
||||||
|
result->Assign(2, build_version_record(${val.version}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_target_info} )
|
||||||
|
result->Assign(3, build_av_record(${val.target_info}));
|
||||||
|
|
||||||
|
BifEvent::generate_ntlm_challenge(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
result);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_ntlm_authenticate(val: NTLM_Authenticate): bool
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Authenticate);
|
||||||
|
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||||
|
|
||||||
|
if ( ${val.domain_name_fields.length} > 0 )
|
||||||
|
result->Assign(1, utf16_bytestring_to_utf8_val(${val.domain_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.user_name_fields.length} > 0 )
|
||||||
|
result->Assign(2, utf16_bytestring_to_utf8_val(${val.user_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.workstation_fields.length} > 0 )
|
||||||
|
result->Assign(3, utf16_bytestring_to_utf8_val(${val.workstation.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_version} )
|
||||||
|
result->Assign(4, build_version_record(${val.version}));
|
||||||
|
|
||||||
|
BifEvent::generate_ntlm_authenticate(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
result);
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
}
|
||||||
|
|
||||||
|
refine typeattr NTLM_Negotiate += &let {
|
||||||
|
proc = $context.connection.proc_ntlm_negotiate(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr NTLM_Challenge += &let {
|
||||||
|
proc : bool = $context.connection.proc_ntlm_challenge(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr NTLM_Authenticate += &let {
|
||||||
|
proc : bool = $context.connection.proc_ntlm_authenticate(this);
|
||||||
|
};
|
||||||
|
|
200
src/analyzer/protocol/ntlm/ntlm-protocol.pac
Normal file
200
src/analyzer/protocol/ntlm/ntlm-protocol.pac
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
|
||||||
|
type NTLM_SSP_Token(is_orig: bool) = record {
|
||||||
|
signature : bytestring &length=8;
|
||||||
|
msg_type : uint32;
|
||||||
|
msg : case msg_type of {
|
||||||
|
1 -> negotiate : NTLM_Negotiate(offsetof(msg) - offsetof(signature));
|
||||||
|
2 -> challenge : NTLM_Challenge(offsetof(msg) - offsetof(signature));
|
||||||
|
3 -> authenticate : NTLM_Authenticate(offsetof(msg) - offsetof(signature));
|
||||||
|
default -> def : bytestring &restofdata &transient;
|
||||||
|
};
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type NTLM_Negotiate(offset: uint16) = record {
|
||||||
|
flags : NTLM_Negotiate_Flags;
|
||||||
|
domain_name_fields : NTLM_StringData;
|
||||||
|
workstation_fields : NTLM_StringData;
|
||||||
|
version_present : case flags.negotiate_version of {
|
||||||
|
true -> version : NTLM_Version;
|
||||||
|
false -> no_version : empty;
|
||||||
|
};
|
||||||
|
payload : bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||||
|
domain_name : NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_domain_supplied);
|
||||||
|
workstation : NTLM_String(workstation_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_workstation_supplied);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Challenge(offset: uint16) = record {
|
||||||
|
target_name_fields : NTLM_StringData;
|
||||||
|
flags : NTLM_Negotiate_Flags;
|
||||||
|
challenge : uint64;
|
||||||
|
reserved : padding[8];
|
||||||
|
target_info_fields : NTLM_StringData;
|
||||||
|
version_present : case flags.negotiate_version of {
|
||||||
|
true -> version : NTLM_Version;
|
||||||
|
false -> no_version : empty;
|
||||||
|
};
|
||||||
|
payload : bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||||
|
target_name : NTLM_String(target_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.request_target);
|
||||||
|
target_info : NTLM_AV_Pair_Sequence(target_info_fields.offset - absolute_offset) withinput payload &if(flags.negotiate_target_info);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Authenticate(offset: uint16) = record {
|
||||||
|
lm_challenge_response_fields : NTLM_StringData;
|
||||||
|
nt_challenge_response_fields : NTLM_StringData;
|
||||||
|
domain_name_fields : NTLM_StringData;
|
||||||
|
user_name_fields : NTLM_StringData;
|
||||||
|
workstation_fields : NTLM_StringData;
|
||||||
|
encrypted_session_key_fields : NTLM_StringData;
|
||||||
|
flags : NTLM_Negotiate_Flags;
|
||||||
|
version_present : case flags.negotiate_version of {
|
||||||
|
true -> version : NTLM_Version;
|
||||||
|
false -> no_version : empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Windows NT, 2000, XP, and 2003 don't have the MIC field
|
||||||
|
# TODO - figure out how to parse this for those that do have it
|
||||||
|
# mic : bytestring &length=16;
|
||||||
|
|
||||||
|
payload : bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||||
|
domain_name : NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(domain_name_fields.length > 0);
|
||||||
|
user_name : NTLM_String(user_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(user_name_fields.length > 0);
|
||||||
|
workstation : NTLM_String(workstation_fields, absolute_offset , flags.negotiate_unicode) withinput payload &if(workstation_fields.length > 0);
|
||||||
|
encrypted_session_key : NTLM_String(encrypted_session_key_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_key_exch);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Version = record {
|
||||||
|
major_version : uint8;
|
||||||
|
minor_version : uint8;
|
||||||
|
build_number : uint16;
|
||||||
|
reserved : padding[3];
|
||||||
|
ntlm_revision : uint8;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_StringData = record {
|
||||||
|
length : uint16;
|
||||||
|
max_length : uint16;
|
||||||
|
offset : uint32;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Fixed_Length_String(unicode: bool) = record {
|
||||||
|
data: bytestring &restofdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_String(fields: NTLM_StringData, offset: uint16, unicode: bool) = record {
|
||||||
|
pad1 : padding to fields.offset - offset;
|
||||||
|
string : Fixed_Length_String(unicode) &length=fields.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_AV_Pair_Sequence(offset: uint16) = record {
|
||||||
|
pad1 : padding to offset;
|
||||||
|
pairs : NTLM_AV_Pair[] &until($element.last);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_AV_Pair = record {
|
||||||
|
id : uint16;
|
||||||
|
length : uint16;
|
||||||
|
value_case : case id of {
|
||||||
|
0x0000 -> av_eol : empty;
|
||||||
|
0x0001 -> nb_computer_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0002 -> nb_domain_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0003 -> dns_computer_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0004 -> dns_domain_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0005 -> dns_tree_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0006 -> av_flags : uint32;
|
||||||
|
0x0007 -> timestamp : uint64;
|
||||||
|
0x0008 -> single_host : NTLM_Single_Host;
|
||||||
|
0x0009 -> target_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x000a -> channel_bindings : uint16;
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
last : bool = (id == 0x0000);
|
||||||
|
# av_flags refinement
|
||||||
|
constrained_auth : bool = (av_flags & 0x00000001) > 0 &if(id == 0x0006);
|
||||||
|
mic_present : bool = (av_flags & 0x00000002) > 0 &if(id == 0x0006);
|
||||||
|
untrusted_source : bool = (av_flags & 0x00000004) > 0 &if(id == 0x0006);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Single_Host = record {
|
||||||
|
size : uint32;
|
||||||
|
padpad : padding[4];
|
||||||
|
data_present : uint32;
|
||||||
|
optional : case custom_data_present of {
|
||||||
|
true -> custom_data : bytestring &length=4;
|
||||||
|
false -> nothing : empty;
|
||||||
|
};
|
||||||
|
machine_id : uint32;
|
||||||
|
} &let {
|
||||||
|
custom_data_present: bool = (data_present & 0x00000001) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LM_Response(offset: uint16) = record {
|
||||||
|
# This can be either LM (24 byte response) or
|
||||||
|
# LMv2 (16 byte response + 8 byte client challenge. No way to
|
||||||
|
# know for sure.
|
||||||
|
padpad : padding to offset;
|
||||||
|
response : bytestring &length=24;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Response(offset: uint16) = record {
|
||||||
|
padpad : padding to offset;
|
||||||
|
response : bytestring &length=24;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLMv2_Response(flags: NTLM_Negotiate_Flags, offset: uint16) = record {
|
||||||
|
padpad : padding to offset;
|
||||||
|
response : bytestring &length=16;
|
||||||
|
client_challenge : NTLMv2_Client_Challenge(flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLMv2_Client_Challenge(flags: NTLM_Negotiate_Flags) = record {
|
||||||
|
resp_type : uint8;
|
||||||
|
max_resp_type : uint8;
|
||||||
|
reserved : padding[6];
|
||||||
|
timestamp : uint64;
|
||||||
|
client_challenge : bytestring &length=8;
|
||||||
|
reserved2 : padding[4];
|
||||||
|
av_pairs : NTLM_AV_Pair_Sequence(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Negotiate_Flags = record {
|
||||||
|
flags: uint32;
|
||||||
|
} &let {
|
||||||
|
negotiate_56 : bool = (flags & 0x80000000) > 0;
|
||||||
|
negotiate_key_exch : bool = (flags & 0x40000000) > 0;
|
||||||
|
negotiate_128 : bool = (flags & 0x20000000) > 0;
|
||||||
|
|
||||||
|
negotiate_version : bool = (flags & 0x02000000) > 0;
|
||||||
|
|
||||||
|
negotiate_target_info : bool = (flags & 0x00800000) > 0;
|
||||||
|
request_non_nt_session_key : bool = (flags & 0x00400000) > 0;
|
||||||
|
negotiate_identify : bool = (flags & 0x00100000) > 0;
|
||||||
|
|
||||||
|
negotiate_extended_sessionsecurity : bool = (flags & 0x00040000) > 0;
|
||||||
|
target_type_server : bool = (flags & 0x00020000) > 0;
|
||||||
|
target_type_domain : bool = (flags & 0x00010000) > 0;
|
||||||
|
|
||||||
|
negotiate_always_sign : bool = (flags & 0x00008000) > 0;
|
||||||
|
negotiate_oem_workstation_supplied : bool = (flags & 0x00002000) > 0;
|
||||||
|
negotiate_oem_domain_supplied : bool = (flags & 0x00001000) > 0;
|
||||||
|
|
||||||
|
negotiate_anonymous_connection : bool = (flags & 0x00000400) > 0;
|
||||||
|
negotiate_ntlm : bool = (flags & 0x00000100) > 0;
|
||||||
|
|
||||||
|
negotiate_lm_key : bool = (flags & 0x00000080) > 0;
|
||||||
|
negotiate_datagram : bool = (flags & 0x00000040) > 0;
|
||||||
|
negotiate_seal : bool = (flags & 0x00000020) > 0;
|
||||||
|
|
||||||
|
negotiate_sign : bool = (flags & 0x00000008) > 0;
|
||||||
|
request_target : bool = (flags & 0x00000004) > 0;
|
||||||
|
negotiate_oem : bool = (flags & 0x00000002) > 0;
|
||||||
|
negotiate_unicode : bool = (flags & 0x00000001) > 0;
|
||||||
|
|
||||||
|
is_oem : bool = !negotiate_unicode && negotiate_oem;
|
||||||
|
is_invalid : bool = !negotiate_unicode && !negotiate_oem;
|
||||||
|
};
|
30
src/analyzer/protocol/ntlm/ntlm.pac
Normal file
30
src/analyzer/protocol/ntlm/ntlm.pac
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
%include binpac.pac
|
||||||
|
%include bro.pac
|
||||||
|
|
||||||
|
%extern{
|
||||||
|
#include "analyzer/Manager.h"
|
||||||
|
#include "analyzer/Analyzer.h"
|
||||||
|
|
||||||
|
#include "types.bif.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
analyzer NTLM withcontext {
|
||||||
|
connection : NTLM_Conn;
|
||||||
|
flow : NTLM_Flow;
|
||||||
|
};
|
||||||
|
|
||||||
|
connection NTLM_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = NTLM_Flow(true);
|
||||||
|
downflow = NTLM_Flow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include ntlm-protocol.pac
|
||||||
|
%include ../asn1/asn1.pac
|
||||||
|
|
||||||
|
# Now we define the flow:
|
||||||
|
flow NTLM_Flow(is_orig: bool) {
|
||||||
|
datagram = NTLM_SSP_Token(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include ntlm-analyzer.pac
|
9
src/analyzer/protocol/ntlm/types.bif
Normal file
9
src/analyzer/protocol/ntlm/types.bif
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
module NTLM;
|
||||||
|
|
||||||
|
type NTLM::Negotiate: record;
|
||||||
|
type NTLM::Challenge: record;
|
||||||
|
type NTLM::Authenticate: record;
|
||||||
|
type NTLM::NegotiateFlags: record;
|
||||||
|
type NTLM::Version: record;
|
||||||
|
type NTLM::AVs: record;
|
|
@ -1,54 +1,9 @@
|
||||||
%extern{
|
%extern{
|
||||||
#include "ConvertUTF.h"
|
|
||||||
#include "file_analysis/Manager.h"
|
#include "file_analysis/Manager.h"
|
||||||
#include "types.bif.h"
|
#include "types.bif.h"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
refine flow RDP_Flow += {
|
refine flow RDP_Flow += {
|
||||||
|
|
||||||
function utf16_to_utf8_val(utf16: bytestring): StringVal
|
|
||||||
%{
|
|
||||||
std::string resultstring;
|
|
||||||
|
|
||||||
size_t utf8size = (3 * utf16.length() + 1);
|
|
||||||
|
|
||||||
if ( utf8size > resultstring.max_size() )
|
|
||||||
{
|
|
||||||
connection()->bro_analyzer()->Weird("excessive_utf16_length");
|
|
||||||
return new StringVal("");
|
|
||||||
}
|
|
||||||
|
|
||||||
resultstring.resize(utf8size, '\0');
|
|
||||||
|
|
||||||
// We can't assume that the string data is properly aligned
|
|
||||||
// here, so make a copy.
|
|
||||||
UTF16 utf16_copy[utf16.length()]; // Twice as much memory than necessary.
|
|
||||||
memcpy(utf16_copy, utf16.begin(), utf16.length());
|
|
||||||
|
|
||||||
const char* utf16_copy_end = reinterpret_cast<const char*>(utf16_copy) + utf16.length();
|
|
||||||
const UTF16* sourcestart = utf16_copy;
|
|
||||||
const UTF16* sourceend = reinterpret_cast<const UTF16*>(utf16_copy_end);
|
|
||||||
|
|
||||||
UTF8* targetstart = reinterpret_cast<UTF8*>(&resultstring[0]);
|
|
||||||
UTF8* targetend = targetstart + utf8size;
|
|
||||||
|
|
||||||
ConversionResult res = ConvertUTF16toUTF8(&sourcestart,
|
|
||||||
sourceend,
|
|
||||||
&targetstart,
|
|
||||||
targetend,
|
|
||||||
lenientConversion);
|
|
||||||
if ( res != conversionOK )
|
|
||||||
{
|
|
||||||
connection()->bro_analyzer()->Weird("Failed UTF-16 to UTF-8 conversion");
|
|
||||||
return new StringVal(utf16.length(), (const char *) utf16.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
*targetstart = 0;
|
|
||||||
|
|
||||||
// We're relying on no nulls being in the string.
|
|
||||||
return new StringVal(resultstring.c_str());
|
|
||||||
%}
|
|
||||||
|
|
||||||
function proc_rdp_connect_request(cr: Connect_Request): bool
|
function proc_rdp_connect_request(cr: Connect_Request): bool
|
||||||
%{
|
%{
|
||||||
if ( rdp_connect_request )
|
if ( rdp_connect_request )
|
||||||
|
@ -125,18 +80,18 @@ refine flow RDP_Flow += {
|
||||||
ccd->Assign(5, new Val(${ccore.sas_sequence}, TYPE_COUNT));
|
ccd->Assign(5, new Val(${ccore.sas_sequence}, TYPE_COUNT));
|
||||||
ccd->Assign(6, new Val(${ccore.keyboard_layout}, TYPE_COUNT));
|
ccd->Assign(6, new Val(${ccore.keyboard_layout}, TYPE_COUNT));
|
||||||
ccd->Assign(7, new Val(${ccore.client_build}, TYPE_COUNT));
|
ccd->Assign(7, new Val(${ccore.client_build}, TYPE_COUNT));
|
||||||
ccd->Assign(8, utf16_to_utf8_val(${ccore.client_name}));
|
ccd->Assign(8, utf16_bytestring_to_utf8_val(${ccore.client_name}));
|
||||||
ccd->Assign(9, new Val(${ccore.keyboard_type}, TYPE_COUNT));
|
ccd->Assign(9, new Val(${ccore.keyboard_type}, TYPE_COUNT));
|
||||||
ccd->Assign(10, new Val(${ccore.keyboard_sub}, TYPE_COUNT));
|
ccd->Assign(10, new Val(${ccore.keyboard_sub}, TYPE_COUNT));
|
||||||
ccd->Assign(11, new Val(${ccore.keyboard_function_key}, TYPE_COUNT));
|
ccd->Assign(11, new Val(${ccore.keyboard_function_key}, TYPE_COUNT));
|
||||||
ccd->Assign(12, utf16_to_utf8_val(${ccore.ime_file_name}));
|
ccd->Assign(12, utf16_bytestring_to_utf8_val(${ccore.ime_file_name}));
|
||||||
ccd->Assign(13, new Val(${ccore.post_beta2_color_depth}, TYPE_COUNT));
|
ccd->Assign(13, new Val(${ccore.post_beta2_color_depth}, TYPE_COUNT));
|
||||||
ccd->Assign(14, new Val(${ccore.client_product_id}, TYPE_COUNT));
|
ccd->Assign(14, new Val(${ccore.client_product_id}, TYPE_COUNT));
|
||||||
ccd->Assign(15, new Val(${ccore.serial_number}, TYPE_COUNT));
|
ccd->Assign(15, new Val(${ccore.serial_number}, TYPE_COUNT));
|
||||||
ccd->Assign(16, new Val(${ccore.high_color_depth}, TYPE_COUNT));
|
ccd->Assign(16, new Val(${ccore.high_color_depth}, TYPE_COUNT));
|
||||||
ccd->Assign(17, new Val(${ccore.supported_color_depths}, TYPE_COUNT));
|
ccd->Assign(17, new Val(${ccore.supported_color_depths}, TYPE_COUNT));
|
||||||
ccd->Assign(18, ec_flags);
|
ccd->Assign(18, ec_flags);
|
||||||
ccd->Assign(19, utf16_to_utf8_val(${ccore.dig_product_id}));
|
ccd->Assign(19, utf16_bytestring_to_utf8_val(${ccore.dig_product_id}));
|
||||||
|
|
||||||
BifEvent::generate_rdp_client_core_data(connection()->bro_analyzer(),
|
BifEvent::generate_rdp_client_core_data(connection()->bro_analyzer(),
|
||||||
connection()->bro_analyzer()->Conn(),
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
include(BroPlugin)
|
include(BroPlugin)
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
@ -6,6 +5,80 @@ include_directories(AFTER ${CMAKE_CURRENT_BINARY_DIR}/../dce-rpc)
|
||||||
|
|
||||||
bro_plugin_begin(Bro SMB)
|
bro_plugin_begin(Bro SMB)
|
||||||
bro_plugin_cc(SMB.cc Plugin.cc)
|
bro_plugin_cc(SMB.cc Plugin.cc)
|
||||||
bro_plugin_bif(events.bif)
|
bro_plugin_bif(
|
||||||
bro_plugin_pac(smb.pac smb-protocol.pac smb-pipe.pac smb-mailslot.pac)
|
smb1_com_check_directory.bif
|
||||||
|
smb1_com_close.bif
|
||||||
|
smb1_com_create_directory.bif
|
||||||
|
smb1_com_echo.bif
|
||||||
|
smb1_com_logoff_andx.bif
|
||||||
|
smb1_com_negotiate.bif
|
||||||
|
smb1_com_nt_create_andx.bif
|
||||||
|
smb1_com_nt_cancel.bif
|
||||||
|
smb1_com_query_information.bif
|
||||||
|
smb1_com_read_andx.bif
|
||||||
|
smb1_com_session_setup_andx.bif
|
||||||
|
smb1_com_transaction.bif
|
||||||
|
smb1_com_transaction2.bif
|
||||||
|
smb1_com_tree_connect_andx.bif
|
||||||
|
smb1_com_tree_disconnect.bif
|
||||||
|
smb1_com_write_andx.bif
|
||||||
|
smb1_events.bif
|
||||||
|
|
||||||
|
smb2_com_close.bif
|
||||||
|
smb2_com_create.bif
|
||||||
|
#smb2_com_ioctl.bif
|
||||||
|
#smb2_com_lock.bif
|
||||||
|
smb2_com_negotiate.bif
|
||||||
|
smb2_com_read.bif
|
||||||
|
smb2_com_session_setup.bif
|
||||||
|
smb2_com_set_info.bif
|
||||||
|
smb2_com_tree_connect.bif
|
||||||
|
#smb2_com_tree_disconnect.bif
|
||||||
|
smb2_com_write.bif
|
||||||
|
smb2_events.bif
|
||||||
|
|
||||||
|
types.bif)
|
||||||
|
bro_plugin_pac(
|
||||||
|
smb.pac
|
||||||
|
smb-common.pac
|
||||||
|
smb-strings.pac
|
||||||
|
smb-time.pac
|
||||||
|
smb-pipe.pac
|
||||||
|
smb-gssapi.pac
|
||||||
|
smb-mailslot.pac
|
||||||
|
|
||||||
|
smb1-protocol.pac
|
||||||
|
smb1-com-check-directory.pac
|
||||||
|
smb1-com-close.pac
|
||||||
|
smb1-com-create-directory.pac
|
||||||
|
smb1-com-echo.pac
|
||||||
|
smb1-com-locking-andx.pac
|
||||||
|
smb1-com-logoff-andx.pac
|
||||||
|
smb1-com-negotiate.pac
|
||||||
|
smb1-com-nt-cancel.pac
|
||||||
|
smb1-com-nt-create-andx.pac
|
||||||
|
smb1-com-nt-transact.pac
|
||||||
|
smb1-com-query-information.pac
|
||||||
|
smb1-com-read-andx.pac
|
||||||
|
smb1-com-session-setup-andx.pac
|
||||||
|
smb1-com-transaction-secondary.pac
|
||||||
|
smb1-com-transaction.pac
|
||||||
|
smb1-com-transaction2.pac
|
||||||
|
smb1-com-tree-connect-andx.pac
|
||||||
|
smb1-com-tree-disconnect.pac
|
||||||
|
smb1-com-write-andx.pac
|
||||||
|
|
||||||
|
smb2-protocol.pac
|
||||||
|
smb2-com-close.pac
|
||||||
|
smb2-com-create.pac
|
||||||
|
smb2-com-ioctl.pac
|
||||||
|
smb2-com-lock.pac
|
||||||
|
smb2-com-negotiate.pac
|
||||||
|
smb2-com-read.pac
|
||||||
|
smb2-com-session-setup.pac
|
||||||
|
smb2-com-set-info.pac
|
||||||
|
smb2-com-tree-connect.pac
|
||||||
|
smb2-com-tree-disconnect.pac
|
||||||
|
smb2-com-write.pac
|
||||||
|
)
|
||||||
bro_plugin_end()
|
bro_plugin_end()
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// See the file in the main distribution directory for copyright.
|
// See the file in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
|
||||||
#include "plugin/Plugin.h"
|
#include "plugin/Plugin.h"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,200 +1,36 @@
|
||||||
// See the file "COPYING" in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#ifndef ANALYZER_PROTOCOL_SMB_SMB_H
|
#ifndef ANALYZER_PROTOCOL_SMB_SMB_H
|
||||||
#define ANALYZER_PROTOCOL_SMB_SMB_H
|
#define ANALYZER_PROTOCOL_SMB_SMB_H
|
||||||
|
|
||||||
// SMB (CIFS) analyzer.
|
|
||||||
// Reference: http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf
|
|
||||||
|
|
||||||
#include "analyzer/protocol/tcp/TCP.h"
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
#include "analyzer/protocol/dce-rpc/DCE_RPC.h"
|
|
||||||
#include "smb_pac.h"
|
#include "smb_pac.h"
|
||||||
|
|
||||||
namespace analyzer { namespace smb {
|
namespace analyzer { namespace smb {
|
||||||
|
|
||||||
enum IPC_named_pipe {
|
|
||||||
IPC_NONE,
|
|
||||||
IPC_LOCATOR,
|
|
||||||
IPC_EPMAPPER,
|
|
||||||
IPC_SAMR, // Security Account Manager
|
|
||||||
};
|
|
||||||
|
|
||||||
class SMB_Body : public binpac::SMB::SMB_body {
|
|
||||||
public:
|
|
||||||
SMB_Body(const u_char* data, const u_char* data_end)
|
|
||||||
: binpac::SMB::SMB_body()
|
|
||||||
{
|
|
||||||
data_ = data;
|
|
||||||
Parse(data, data_end);
|
|
||||||
data_length_ = body_length();
|
|
||||||
if ( data + data_length_ > data_end )
|
|
||||||
data_length_ = data_end - data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u_char* data() const { return data_; }
|
|
||||||
int length() const { return data_length_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const u_char* data_;
|
|
||||||
int data_length_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SMB_Session {
|
|
||||||
public:
|
|
||||||
SMB_Session(analyzer::Analyzer* analyzer);
|
|
||||||
~SMB_Session();
|
|
||||||
|
|
||||||
void Deliver(int is_orig, int len, const u_char* msg);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void ParseMessage(int is_orig, int cmd,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseNegotiate(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseNegotiateResponse(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseAndx(int is_orig, binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseClose(int is_orig, binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseLogoffAndx(int is_orig, binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseSetupAndx(int is_orig, binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseTreeConnectAndx(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseTreeDisconnect(int is_orig, binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseNtCreateAndx(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseReadAndx(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseReadAndxResponse(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseWriteAndx(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseWriteAndxResponse(binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseTransaction(int is_orig, int cmd,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int TransactionEvent(EventHandlerPtr f, int is_orig,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
binpac::SMB::SMB_transaction const &trans,
|
|
||||||
int data_count,
|
|
||||||
binpac::SMB::SMB_transaction_data* data);
|
|
||||||
|
|
||||||
int TransactionEvent(EventHandlerPtr f, int is_orig,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
binpac::SMB::SMB_transaction_secondary const &trans,
|
|
||||||
int data_count,
|
|
||||||
binpac::SMB::SMB_transaction_data* data);
|
|
||||||
|
|
||||||
int TransactionEvent(EventHandlerPtr f, int is_orig,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
binpac::SMB::SMB_transaction_response const &trans,
|
|
||||||
int data_count,
|
|
||||||
binpac::SMB::SMB_transaction_data* data);
|
|
||||||
|
|
||||||
int ParseTransactionRequest(int cmd,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseTransactionSecondaryRequest(int cmd,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseTransactionResponse(int cmd,
|
|
||||||
binpac::SMB::SMB_header const &hdr,
|
|
||||||
SMB_Body const &body);
|
|
||||||
|
|
||||||
int ParseGetDFSReferral(binpac::SMB::SMB_header const &hdr,
|
|
||||||
int param_count, const u_char* param);
|
|
||||||
|
|
||||||
BroString* ExtractString(binpac::SMB::SMB_string const* s);
|
|
||||||
BroString* ExtractString(binpac::SMB::SMB_ascii_string const* s);
|
|
||||||
BroString* ExtractString(binpac::SMB::SMB_unicode_string const* s);
|
|
||||||
|
|
||||||
bool LooksLikeRPC(int len, const u_char* msg);
|
|
||||||
bool CheckRPC(int is_orig, int len, const u_char* msg);
|
|
||||||
|
|
||||||
int AndxOffset(int is_orig, int &next_command) const;
|
|
||||||
|
|
||||||
void Weird(const char* msg);
|
|
||||||
|
|
||||||
const binpac::SMB::SMB_andx* const andx(int is_orig) const
|
|
||||||
{
|
|
||||||
return is_orig ? andx_[1] : andx_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_andx(int is_orig, binpac::SMB::SMB_andx* andx);
|
|
||||||
|
|
||||||
Val* BuildHeaderVal(binpac::SMB::SMB_header const &hdr);
|
|
||||||
Val* BuildTransactionVal(binpac::SMB::SMB_transaction const &trans);
|
|
||||||
Val* BuildTransactionVal(binpac::SMB::SMB_transaction_secondary const &trans);
|
|
||||||
Val* BuildTransactionVal(binpac::SMB::SMB_transaction_response const &trans);
|
|
||||||
Val* BuildTransactionDataVal(binpac::SMB::SMB_transaction_data* data);
|
|
||||||
|
|
||||||
analyzer::Analyzer* analyzer;
|
|
||||||
dce_rpc::DCE_RPC_Session* dce_rpc_session;
|
|
||||||
enum IPC_named_pipe IPC_pipe;
|
|
||||||
int is_IPC;
|
|
||||||
int req_cmd;
|
|
||||||
uint16 transaction_subcmd;
|
|
||||||
bool smb_mailslot_prot;
|
|
||||||
bool smb_pipe_prot;
|
|
||||||
StringVal* transaction_name;
|
|
||||||
binpac::SMB::SMB_andx* andx_[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
class Contents_SMB : public tcp::TCP_SupportAnalyzer {
|
|
||||||
public:
|
|
||||||
Contents_SMB(Connection* conn, bool orig, SMB_Session* smb_session);
|
|
||||||
~Contents_SMB();
|
|
||||||
|
|
||||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void InitMsgBuf();
|
|
||||||
|
|
||||||
void DeliverSMB(int len, const u_char* data);
|
|
||||||
|
|
||||||
SMB_Session* smb_session;
|
|
||||||
u_char dshdr[4];
|
|
||||||
u_char* msg_buf;
|
|
||||||
int msg_len;
|
|
||||||
int buf_n; // number of bytes in msg_buf
|
|
||||||
int buf_len; // size off msg_buf
|
|
||||||
};
|
|
||||||
|
|
||||||
class SMB_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
class SMB_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
||||||
public:
|
public:
|
||||||
SMB_Analyzer(Connection* conn);
|
SMB_Analyzer(Connection* conn);
|
||||||
~SMB_Analyzer();
|
virtual ~SMB_Analyzer();
|
||||||
|
|
||||||
|
void Done() override;
|
||||||
|
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||||
|
void Undelivered(uint64 seq, int len, bool orig) override;
|
||||||
|
void EndpointEOF(bool is_orig) override;
|
||||||
|
|
||||||
|
bool HasSMBHeader(int len, const u_char* data);
|
||||||
|
void NeedResync() {
|
||||||
|
delete interp;
|
||||||
|
interp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
{ return new SMB_Analyzer(conn); }
|
{ return new SMB_Analyzer(conn); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SMB_Session* smb_session;
|
binpac::SMB::SMB_Conn* interp;
|
||||||
Contents_SMB* o_smb;
|
|
||||||
Contents_SMB* r_smb;
|
// Count the number of chunks received by the analyzer
|
||||||
|
// but only used to count the first few.
|
||||||
|
uint8 chunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace analyzer::*
|
} } // namespace analyzer::*
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
SMB_COMMAND(SMB_COM_CREATE_DIRECTORY, 0x00)
|
|
||||||
SMB_COMMAND(SMB_COM_DELETE_DIRECTORY, 0x01)
|
|
||||||
SMB_COMMAND(SMB_COM_OPEN, 0x02)
|
|
||||||
SMB_COMMAND(SMB_COM_CREATE, 0x03)
|
|
||||||
SMB_COMMAND(SMB_COM_CLOSE, 0x04)
|
|
||||||
SMB_COMMAND(SMB_COM_FLUSH, 0x05)
|
|
||||||
SMB_COMMAND(SMB_COM_DELETE, 0x06)
|
|
||||||
SMB_COMMAND(SMB_COM_RENAME, 0x07)
|
|
||||||
SMB_COMMAND(SMB_COM_QUERY_INFORMATION, 0x08)
|
|
||||||
SMB_COMMAND(SMB_COM_SET_INFORMATION, 0x09)
|
|
||||||
SMB_COMMAND(SMB_COM_READ, 0x0A)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE, 0x0B)
|
|
||||||
SMB_COMMAND(SMB_COM_LOCK_BYTE_RANGE, 0x0C)
|
|
||||||
SMB_COMMAND(SMB_COM_UNLOCK_BYTE_RANGE, 0x0D)
|
|
||||||
SMB_COMMAND(SMB_COM_CREATE_TEMPORARY, 0x0E)
|
|
||||||
SMB_COMMAND(SMB_COM_CREATE_NEW, 0x0F)
|
|
||||||
SMB_COMMAND(SMB_COM_CHECK_DIRECTORY, 0x10)
|
|
||||||
SMB_COMMAND(SMB_COM_PROCESS_EXIT, 0x11)
|
|
||||||
SMB_COMMAND(SMB_COM_SEEK, 0x12)
|
|
||||||
SMB_COMMAND(SMB_COM_LOCK_AND_READ, 0x13)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_AND_UNLOCK, 0x14)
|
|
||||||
SMB_COMMAND(SMB_COM_READ_RAW, 0x1A)
|
|
||||||
SMB_COMMAND(SMB_COM_READ_MPX, 0x1B)
|
|
||||||
SMB_COMMAND(SMB_COM_READ_MPX_SECONDARY, 0x1C)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_RAW, 0x1D)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_MPX, 0x1E)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_MPX_SECONDARY, 0x1F)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_COMPLETE, 0x20)
|
|
||||||
SMB_COMMAND(SMB_COM_QUERY_SERVER, 0x21)
|
|
||||||
SMB_COMMAND(SMB_COM_SET_INFORMATION2, 0x22)
|
|
||||||
SMB_COMMAND(SMB_COM_QUERY_INFORMATION2, 0x23)
|
|
||||||
SMB_COMMAND(SMB_COM_LOCKING_ANDX, 0x24)
|
|
||||||
SMB_COMMAND(SMB_COM_TRANSACTION, 0x25)
|
|
||||||
SMB_COMMAND(SMB_COM_TRANSACTION_SECONDARY, 0x26)
|
|
||||||
SMB_COMMAND(SMB_COM_IOCTL, 0x27)
|
|
||||||
SMB_COMMAND(SMB_COM_IOCTL_SECONDARY, 0x28)
|
|
||||||
SMB_COMMAND(SMB_COM_COPY, 0x29)
|
|
||||||
SMB_COMMAND(SMB_COM_MOVE, 0x2A)
|
|
||||||
SMB_COMMAND(SMB_COM_ECHO, 0x2B)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_AND_CLOSE, 0x2C)
|
|
||||||
SMB_COMMAND(SMB_COM_OPEN_ANDX, 0x2D)
|
|
||||||
SMB_COMMAND(SMB_COM_READ_ANDX, 0x2E)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_ANDX, 0x2F)
|
|
||||||
SMB_COMMAND(SMB_COM_NEW_FILE_SIZE, 0x30)
|
|
||||||
SMB_COMMAND(SMB_COM_CLOSE_AND_TREE_DISC, 0x31)
|
|
||||||
SMB_COMMAND(SMB_COM_TRANSACTION2, 0x32)
|
|
||||||
SMB_COMMAND(SMB_COM_TRANSACTION2_SECONDARY, 0x33)
|
|
||||||
SMB_COMMAND(SMB_COM_FIND_CLOSE2, 0x34)
|
|
||||||
SMB_COMMAND(SMB_COM_FIND_NOTIFY_CLOSE, 0x35)
|
|
||||||
|
|
||||||
// Used by Xenix/Unix 0x60 - 0x6E.
|
|
||||||
|
|
||||||
SMB_COMMAND(SMB_COM_TREE_CONNECT, 0x70)
|
|
||||||
SMB_COMMAND(SMB_COM_TREE_DISCONNECT, 0x71)
|
|
||||||
SMB_COMMAND(SMB_COM_NEGOTIATE, 0x72)
|
|
||||||
SMB_COMMAND(SMB_COM_SESSION_SETUP_ANDX, 0x73)
|
|
||||||
SMB_COMMAND(SMB_COM_LOGOFF_ANDX, 0x74)
|
|
||||||
SMB_COMMAND(SMB_COM_TREE_CONNECT_ANDX, 0x75)
|
|
||||||
SMB_COMMAND(SMB_COM_QUERY_INFORMATION_DISK, 0x80)
|
|
||||||
SMB_COMMAND(SMB_COM_SEARCH, 0x81)
|
|
||||||
SMB_COMMAND(SMB_COM_FIND, 0x82)
|
|
||||||
SMB_COMMAND(SMB_COM_FIND_UNIQUE, 0x83)
|
|
||||||
SMB_COMMAND(SMB_COM_FIND_CLOSE, 0x84)
|
|
||||||
SMB_COMMAND(SMB_COM_NT_TRANSACT, 0xA0)
|
|
||||||
SMB_COMMAND(SMB_COM_NT_TRANSACT_SECONDARY, 0xA1)
|
|
||||||
SMB_COMMAND(SMB_COM_NT_CREATE_ANDX, 0xA2)
|
|
||||||
SMB_COMMAND(SMB_COM_NT_CANCEL, 0xA4)
|
|
||||||
SMB_COMMAND(SMB_COM_NT_RENAME, 0xA5)
|
|
||||||
SMB_COMMAND(SMB_COM_OPEN_PRINT_FILE, 0xC0)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_PRINT_FILE, 0xC1)
|
|
||||||
SMB_COMMAND(SMB_COM_CLOSE_PRINT_FILE, 0xC2)
|
|
||||||
SMB_COMMAND(SMB_COM_GET_PRINT_QUEUE, 0xC3)
|
|
||||||
SMB_COMMAND(SMB_COM_READ_BULK, 0xD8)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_BULK, 0xD9)
|
|
||||||
SMB_COMMAND(SMB_COM_WRITE_BULK_DATA, 0xDA)
|
|
|
@ -1,495 +0,0 @@
|
||||||
## Generated for all SMB/CIFS messages.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## is_orig: True if the message was sent by the originator of the underlying
|
|
||||||
## transport-level connection.
|
|
||||||
##
|
|
||||||
## cmd: A string mnemonic of the SMB command code.
|
|
||||||
##
|
|
||||||
## body_length: The length of the SMB message body, i.e. the data starting after
|
|
||||||
## the SMB header.
|
|
||||||
##
|
|
||||||
## body: The raw SMB message body, i.e., the data starting after the SMB header.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_connect_andx smb_com_tree_disconnect smb_com_write_andx smb_error
|
|
||||||
## smb_get_dfs_referral
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_message%(c: connection, hdr: smb_hdr, is_orig: bool, cmd: string, body_length: count, body: string%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *tree connect andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## path: The ``path`` attribute specified in the message.
|
|
||||||
##
|
|
||||||
## service: The ``service`` attribute specified in the message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_tree_connect_andx%(c: connection, hdr: smb_hdr, path: string, service: string%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *tree disconnect*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_connect_andx smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_tree_disconnect%(c: connection, hdr: smb_hdr%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *nt create andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## name: The ``name`` attribute specified in the message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_read_andx
|
|
||||||
## smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_nt_create_andx%(c: connection, hdr: smb_hdr, name: string%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *nt transaction*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## trans: The parsed transaction header.
|
|
||||||
##
|
|
||||||
## data: The raw transaction data.
|
|
||||||
##
|
|
||||||
## is_orig: True if the message was sent by the originator of the connection.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe
|
|
||||||
## smb_com_trans_rap smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_transaction%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *nt transaction 2*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## trans: The parsed transaction header.
|
|
||||||
##
|
|
||||||
## data: The raw transaction data.
|
|
||||||
##
|
|
||||||
## is_orig: True if the message was sent by the originator of the connection.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe
|
|
||||||
## smb_com_trans_rap smb_com_transaction smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_transaction2%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *transaction mailslot*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## trans: The parsed transaction header.
|
|
||||||
##
|
|
||||||
## data: The raw transaction data.
|
|
||||||
##
|
|
||||||
## is_orig: True if the message was sent by the originator of the connection.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_trans_mailslot%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *transaction rap*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## trans: The parsed transaction header.
|
|
||||||
##
|
|
||||||
## data: The raw transaction data.
|
|
||||||
##
|
|
||||||
## is_orig: True if the message was sent by the originator of the connection.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_connect_andx smb_com_tree_disconnect smb_com_write_andx smb_error
|
|
||||||
## smb_get_dfs_referral smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_trans_rap%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *transaction pipe*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## trans: The parsed transaction header.
|
|
||||||
##
|
|
||||||
## data: The raw transaction data.
|
|
||||||
##
|
|
||||||
## is_orig: True if the message was sent by the originator of the connection.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_trans_pipe%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *read andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## data: Always empty.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_read_andx%(c: connection, hdr: smb_hdr, data: string%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *read andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## data: Always empty.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_connect_andx smb_com_tree_disconnect smb_error
|
|
||||||
## smb_get_dfs_referral smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_write_andx%(c: connection, hdr: smb_hdr, data: string%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *get dfs referral*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## max_referral_level: The ``max_referral_level`` attribute specified in the
|
|
||||||
## message.
|
|
||||||
##
|
|
||||||
## file_name: The ``filene_name`` attribute specified in the message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_connect_andx smb_com_tree_disconnect smb_com_write_andx smb_error
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_get_dfs_referral%(c: connection, hdr: smb_hdr, max_referral_level: count, file_name: string%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *negotiate*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate_response smb_com_nt_create_andx smb_com_read_andx smb_com_setup_andx
|
|
||||||
## smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap smb_com_transaction
|
|
||||||
## smb_com_transaction2 smb_com_tree_connect_andx smb_com_tree_disconnect
|
|
||||||
## smb_com_write_andx smb_error smb_get_dfs_referral smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_negotiate%(c: connection, hdr: smb_hdr%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *negotiate response*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## dialect_index: The ``dialect`` indicated in the message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_nt_create_andx smb_com_read_andx smb_com_setup_andx
|
|
||||||
## smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap smb_com_transaction
|
|
||||||
## smb_com_transaction2 smb_com_tree_connect_andx smb_com_tree_disconnect
|
|
||||||
## smb_com_write_andx smb_error smb_get_dfs_referral smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_negotiate_response%(c: connection, hdr: smb_hdr, dialect_index: count%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *setup andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_setup_andx%(c: connection, hdr: smb_hdr%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *generic andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_logoff_andx smb_com_negotiate
|
|
||||||
## smb_com_negotiate_response smb_com_nt_create_andx smb_com_read_andx
|
|
||||||
## smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_generic_andx%(c: connection, hdr: smb_hdr%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *close*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_generic_andx smb_com_logoff_andx smb_com_negotiate
|
|
||||||
## smb_com_negotiate_response smb_com_nt_create_andx smb_com_read_andx
|
|
||||||
## smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_close%(c: connection, hdr: smb_hdr%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages of type *logoff andx*.
|
|
||||||
##
|
|
||||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
|
||||||
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
|
||||||
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_negotiate
|
|
||||||
## smb_com_negotiate_response smb_com_nt_create_andx smb_com_read_andx
|
|
||||||
## smb_com_setup_andx smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
|
||||||
## smb_com_transaction smb_com_transaction2 smb_com_tree_connect_andx
|
|
||||||
## smb_com_tree_disconnect smb_com_write_andx smb_error smb_get_dfs_referral
|
|
||||||
## smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_com_logoff_andx%(c: connection, hdr: smb_hdr%);
|
|
||||||
|
|
||||||
## Generated for SMB/CIFS messages that indicate an error. This event is
|
|
||||||
## triggered by an SMB header including a status that signals an error.
|
|
||||||
##
|
|
||||||
## c: The connection.
|
|
||||||
##
|
|
||||||
## hdr: The parsed header of the SMB message.
|
|
||||||
##
|
|
||||||
## cmd: The SMB command code.
|
|
||||||
##
|
|
||||||
## cmd_str: A string mnemonic of the SMB command code.
|
|
||||||
##
|
|
||||||
## data: The raw SMB message body, i.e., the data starting after the SMB header.
|
|
||||||
##
|
|
||||||
## .. bro:see:: smb_com_close smb_com_generic_andx smb_com_logoff_andx
|
|
||||||
## smb_com_negotiate smb_com_negotiate_response smb_com_nt_create_andx
|
|
||||||
## smb_com_read_andx smb_com_setup_andx smb_com_trans_mailslot
|
|
||||||
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction smb_com_transaction2
|
|
||||||
## smb_com_tree_connect_andx smb_com_tree_disconnect smb_com_write_andx
|
|
||||||
## smb_get_dfs_referral smb_message
|
|
||||||
##
|
|
||||||
## .. todo:: Bro's current default configuration does not activate the protocol
|
|
||||||
## analyzer that generates this event; the corresponding script has not yet
|
|
||||||
## been ported to Bro 2.x. To still enable this event, one needs to
|
|
||||||
## register a port for it or add a DPD payload signature.
|
|
||||||
event smb_error%(c: connection, hdr: smb_hdr, cmd: count, cmd_str: string, data: string%);
|
|
||||||
|
|
252
src/analyzer/protocol/smb/smb-common.pac
Normal file
252
src/analyzer/protocol/smb/smb-common.pac
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
enum SMBVersion {
|
||||||
|
SMB1 = 0xff534d42, # \xffSMB
|
||||||
|
SMB2 = 0xfe534d42, # \xfeSMB
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TransactionType {
|
||||||
|
SMB_MAILSLOT_BROWSE, # \MAILSLOT\BROWSE - MS Browse Protocol
|
||||||
|
SMB_MAILSLOT_LANMAN, # \MAILSLOT\LANMAN - deprecated cmds
|
||||||
|
SMB_PIPE, # \PIPE\* named pipes?
|
||||||
|
SMB_RAP, # \PIPE\LANMAN - remote administration protocol
|
||||||
|
SMB_UNKNOWN, # there are probably lots of these
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SMB_Command {
|
||||||
|
SMB_COM_CREATE_DIRECTORY = 0x00,
|
||||||
|
SMB_COM_DELETE_DIRECTORY = 0x01,
|
||||||
|
SMB_COM_OPEN = 0x02,
|
||||||
|
SMB_COM_CREATE = 0x03,
|
||||||
|
SMB_COM_CLOSE = 0x04,
|
||||||
|
SMB_COM_FLUSH = 0x05,
|
||||||
|
SMB_COM_DELETE = 0x06,
|
||||||
|
SMB_COM_RENAME = 0x07,
|
||||||
|
SMB_COM_QUERY_INFORMATION = 0x08,
|
||||||
|
SMB_COM_SET_INFORMATION = 0x09,
|
||||||
|
SMB_COM_READ = 0x0A,
|
||||||
|
SMB_COM_WRITE = 0x0B,
|
||||||
|
SMB_COM_LOCK_BYTE_RANGE = 0x0C,
|
||||||
|
SMB_COM_UNLOCK_BYTE_RANGE = 0x0D,
|
||||||
|
SMB_COM_CREATE_TEMPORARY = 0x0E,
|
||||||
|
SMB_COM_CREATE_NEW = 0x0F,
|
||||||
|
SMB_COM_CHECK_DIRECTORY = 0x10,
|
||||||
|
SMB_COM_PROCESS_EXIT = 0x11,
|
||||||
|
SMB_COM_SEEK = 0x12,
|
||||||
|
SMB_COM_LOCK_AND_READ = 0x13,
|
||||||
|
SMB_COM_WRITE_AND_UNLOCK = 0x14,
|
||||||
|
SMB_COM_READ_RAW = 0x1A,
|
||||||
|
SMB_COM_READ_MPX = 0x1B,
|
||||||
|
SMB_COM_READ_MPX_SECONDARY = 0x1C,
|
||||||
|
SMB_COM_WRITE_RAW = 0x1D,
|
||||||
|
SMB_COM_WRITE_MPX = 0x1E,
|
||||||
|
SMB_COM_WRITE_MPX_SECONDARY = 0x1F,
|
||||||
|
SMB_COM_WRITE_COMPLETE = 0x20,
|
||||||
|
SMB_COM_QUERY_SERVER = 0x21,
|
||||||
|
SMB_COM_SET_INFORMATION2 = 0x22,
|
||||||
|
SMB_COM_QUERY_INFORMATION2 = 0x23,
|
||||||
|
SMB_COM_LOCKING_ANDX = 0x24,
|
||||||
|
SMB_COM_TRANSACTION = 0x25,
|
||||||
|
SMB_COM_TRANSACTION_SECONDARY = 0x26,
|
||||||
|
SMB_COM_IOCTL = 0x27,
|
||||||
|
SMB_COM_IOCTL_SECONDARY = 0x28,
|
||||||
|
SMB_COM_COPY = 0x29,
|
||||||
|
SMB_COM_MOVE = 0x2A,
|
||||||
|
SMB_COM_ECHO = 0x2B,
|
||||||
|
SMB_COM_WRITE_AND_CLOSE = 0x2C,
|
||||||
|
SMB_COM_OPEN_ANDX = 0x2D,
|
||||||
|
SMB_COM_READ_ANDX = 0x2E,
|
||||||
|
SMB_COM_WRITE_ANDX = 0x2F,
|
||||||
|
SMB_COM_NEW_FILE_SIZE = 0x30,
|
||||||
|
SMB_COM_CLOSE_AND_TREE_DISC = 0x31,
|
||||||
|
SMB_COM_TRANSACTION2 = 0x32,
|
||||||
|
SMB_COM_TRANSACTION2_SECONDARY = 0x33,
|
||||||
|
SMB_COM_FIND_CLOSE2 = 0x34,
|
||||||
|
SMB_COM_FIND_NOTIFY_CLOSE = 0x35,
|
||||||
|
|
||||||
|
SMB_COM_TREE_CONNECT = 0x70,
|
||||||
|
SMB_COM_TREE_DISCONNECT = 0x71,
|
||||||
|
SMB_COM_NEGOTIATE = 0x72,
|
||||||
|
SMB_COM_SESSION_SETUP_ANDX = 0x73,
|
||||||
|
SMB_COM_LOGOFF_ANDX = 0x74,
|
||||||
|
SMB_COM_TREE_CONNECT_ANDX = 0x75,
|
||||||
|
SMB_COM_QUERY_INFORMATION_DISK = 0x80,
|
||||||
|
SMB_COM_SEARCH = 0x81,
|
||||||
|
SMB_COM_FIND = 0x82,
|
||||||
|
SMB_COM_FIND_UNIQUE = 0x83,
|
||||||
|
SMB_COM_FIND_CLOSE = 0x84,
|
||||||
|
SMB_COM_NT_TRANSACT = 0xA0,
|
||||||
|
SMB_COM_NT_TRANSACT_SECONDARY = 0xA1,
|
||||||
|
SMB_COM_NT_CREATE_ANDX = 0xA2,
|
||||||
|
SMB_COM_NT_CANCEL = 0xA4,
|
||||||
|
SMB_COM_NT_RENAME = 0xA5,
|
||||||
|
SMB_COM_OPEN_PRINT_FILE = 0xC0,
|
||||||
|
SMB_COM_WRITE_PRINT_FILE = 0xC1,
|
||||||
|
SMB_COM_CLOSE_PRINT_FILE = 0xC2,
|
||||||
|
SMB_COM_GET_PRINT_QUEUE = 0xC3,
|
||||||
|
SMB_COM_READ_BULK = 0xD8,
|
||||||
|
SMB_COM_WRITE_BULK = 0xD9,
|
||||||
|
SMB_COM_WRITE_BULK_DATA = 0xDA,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SMB_Status {
|
||||||
|
# 0x000
|
||||||
|
STATUS_SUCCESS = 0x00000000,
|
||||||
|
STATUS_NOTIFY_ENUM_DIR = 0x0000010C,
|
||||||
|
STATUS_INVALID_SMB = 0x00010002,
|
||||||
|
STATUS_SMB_BAD_TID = 0x00050002,
|
||||||
|
STATUS_SMB_BAD_FID = 0x00060001,
|
||||||
|
STATUS_OS2_INVALID_ACCESS = 0x000C0001,
|
||||||
|
# 0x001
|
||||||
|
STATUS_SMB_BAD_COMMAND = 0x00160002,
|
||||||
|
# 0x005
|
||||||
|
STATUS_SMB_BAD_UID = 0x005B0002,
|
||||||
|
# 0x007
|
||||||
|
STATUS_OS2_NO_MORE_SIDS = 0x00710001,
|
||||||
|
STATUS_OS2_INVALID_LEVEL = 0x007C0001,
|
||||||
|
# 0x008
|
||||||
|
STATUS_OS2_NEGATIVE_SEEK = 0x00830001,
|
||||||
|
# 0x00A
|
||||||
|
STATUS_OS2_CANCEL_VIOLATION = 0x00AD0001,
|
||||||
|
STATUS_OS2_ATOMIC_LOCKS_NOT_SUPPORTED = 0x00AE0001,
|
||||||
|
# 0x00F
|
||||||
|
STATUS_SMB_USE_MPX = 0x00FA0002,
|
||||||
|
STATUS_SMB_USE_STANDARD = 0x00FB0002,
|
||||||
|
STATUS_SMB_CONTINUE_MPX = 0x00FC0002,
|
||||||
|
# 0x01
|
||||||
|
STATUS_OS2_CANNOT_COPY = 0x010A0001,
|
||||||
|
STATUS_OS2_EAS_DIDNT_FIT = 0x01130001,
|
||||||
|
# 0x03
|
||||||
|
STATUS_OS2_EA_ACCESS_DENIED = 0x03E20001,
|
||||||
|
# 0x8
|
||||||
|
STATUS_BUFFER_OVERFLOW = 0x80000005,
|
||||||
|
STATUS_NO_MORE_FILES = 0x80000006,
|
||||||
|
STATUS_DEVICE_PAPER_EMPTY = 0x8000000E,
|
||||||
|
STATUS_STOPPED_ON_SYMLINK = 0x8000002D,
|
||||||
|
# 0xC000000
|
||||||
|
STATUS_UNSUCCESSFUL = 0xC0000001,
|
||||||
|
STATUS_NOT_IMPLEMENTED = 0xC0000002,
|
||||||
|
STATUS_INVALID_INFO_CLASS = 0xC0000003,
|
||||||
|
STATUS_INVALID_HANDLE = 0xC0000008,
|
||||||
|
STATUS_INVALID_PARAMETER = 0xC000000D,
|
||||||
|
STATUS_NO_SUCH_DEVICE = 0xC000000E,
|
||||||
|
STATUS_NO_SUCH_FILE = 0xC000000F,
|
||||||
|
# 0xC000001
|
||||||
|
STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
|
||||||
|
STATUS_END_OF_FILE = 0xC0000011,
|
||||||
|
STATUS_WRONG_VOLUME = 0xC0000012,
|
||||||
|
STATUS_NONEXISTENT_SECTOR = 0xC0000015,
|
||||||
|
STATUS_NO_MEDIA_IN_DEVICE = 0xC0000013,
|
||||||
|
STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016,
|
||||||
|
STATUS_INVALID_LOCK_SEQUENCE = 0xC000001E,
|
||||||
|
STATUS_INVALID_VIEW_SIZE = 0xC000001F,
|
||||||
|
# 0xC000002
|
||||||
|
STATUS_ALREADY_COMMITTED = 0xC0000021,
|
||||||
|
STATUS_ACCESS_DENIED = 0xC0000022,
|
||||||
|
STATUS_BUFFER_TOO_SMALL = 0xC0000023,
|
||||||
|
STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024,
|
||||||
|
STATUS_HANDLE_NOT_CLOSABLE = 0xC0000025,
|
||||||
|
# 0xC000003
|
||||||
|
STATUS_DISK_CORRUPT_ERROR = 0xC0000032,
|
||||||
|
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||||
|
STATUS_OBJECT_NAME_COLLISION = 0xC0000035,
|
||||||
|
STATUS_PORT_DISCONNECTED = 0xC0000037,
|
||||||
|
STATUS_OBJECT_PATH_INVALID = 0xC0000039,
|
||||||
|
STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A,
|
||||||
|
STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B,
|
||||||
|
STATUS_DATA_ERROR = 0xC000003E,
|
||||||
|
STATUS_CRC_ERROR = 0xC000003F,
|
||||||
|
# 0xC000004
|
||||||
|
STATUS_SECTION_TOO_BIG = 0xC0000040,
|
||||||
|
STATUS_PORT_CONNECTION_REFUSED = 0xC0000041,
|
||||||
|
STATUS_INVALID_PORT_HANDLE = 0xC0000042,
|
||||||
|
STATUS_SHARING_VIOLATION = 0xC0000043,
|
||||||
|
STATUS_THREAD_IS_TERMINATING = 0xC000004B,
|
||||||
|
STATUS_EAS_NOT_SUPPORTED = 0xC000004F,
|
||||||
|
# 0xC000005
|
||||||
|
STATUS_EA_TOO_LARGE = 0xC0000050,
|
||||||
|
STATUS_FILE_LOCK_CONFLICT = 0xC0000054,
|
||||||
|
STATUS_LOCK_NOT_GRANTED = 0xC0000055,
|
||||||
|
STATUS_DELETE_PENDING = 0xC0000056,
|
||||||
|
# 0xC000006
|
||||||
|
STATUS_PRIVILEGE_NOT_HELD = 0xC0000061,
|
||||||
|
STATUS_LOGON_FAILURE = 0xC000006D,
|
||||||
|
STATUS_WRONG_PASSWORD = 0xC000006A,
|
||||||
|
STATUS_INVALID_LOGON_HOURS = 0xC000006F,
|
||||||
|
# 0xC000007
|
||||||
|
STATUS_INVALID_WORKSTATION = 0xC0000070,
|
||||||
|
STATUS_PASSWORD_EXPIRED = 0xC0000071,
|
||||||
|
STATUS_ACCOUNT_DISABLED = 0xC0000072,
|
||||||
|
STATUS_RANGE_NOT_LOCKED = 0xC000007E,
|
||||||
|
STATUS_DISK_FULL = 0xC000007F,
|
||||||
|
# 0xC000009
|
||||||
|
STATUS_TOO_MANY_PAGING_FILES = 0xC0000097,
|
||||||
|
STATUS_DFS_EXIT_PATH_FOUND = 0xC000009B,
|
||||||
|
STATUS_DEVICE_DATA_ERROR = 0xC000009C,
|
||||||
|
# 0xC00000A
|
||||||
|
STATUS_MEDIA_WRITE_PROTECTED = 0xC00000A2,
|
||||||
|
STATUS_BAD_IMPERSONATION_LEVEL = 0xC00000A5,
|
||||||
|
STATUS_INSTANCE_NOT_AVAILABLE = 0xC00000AB,
|
||||||
|
STATUS_PIPE_NOT_AVAILABLE = 0xC00000AC,
|
||||||
|
STATUS_PIPE_STATE = 0xC00000AD,
|
||||||
|
STATUS_PIPE_BUSY = 0xC00000AE,
|
||||||
|
STATUS_ILLEGAL_FUNCTION = 0xC00000AF,
|
||||||
|
# 0xC00000B
|
||||||
|
STATUS_PIPE_DISCONNECTED = 0xC00000B0,
|
||||||
|
STATUS_PIPE_CLOSING = 0xC00000B1,
|
||||||
|
STATUS_INVALID_READ_MODE = 0xC00000B4,
|
||||||
|
STATUS_IO_TIMEOUT = 0xC00000B5,
|
||||||
|
STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA,
|
||||||
|
STATUS_NOT_SUPPORTED = 0xC00000BB,
|
||||||
|
# 0xC00000C
|
||||||
|
STATUS_UNEXPECTED_NETWORK_ERROR = 0xC00000C4,
|
||||||
|
STATUS_PRINT_QUEUE_FULL = 0xC00000C6,
|
||||||
|
STATUS_NO_SPOOL_SPACE = 0xC00000C7,
|
||||||
|
STATUS_PRINT_CANCELLED = 0xC00000C8,
|
||||||
|
STATUS_NETWORK_NAME_DELETED = 0xC00000C9,
|
||||||
|
STATUS_NETWORK_ACCESS_DENIED = 0xC00000CA,
|
||||||
|
STATUS_BAD_DEVICE_TYPE = 0xC00000CB,
|
||||||
|
STATUS_BAD_NETWORK_NAME = 0xC00000CC,
|
||||||
|
STATUS_TOO_MANY_SESSIONS = 0xC00000CE,
|
||||||
|
# 0xC00000D
|
||||||
|
STATUS_REQUEST_NOT_ACCEPTED = 0xC00000D0,
|
||||||
|
STATUS_NOT_SAME_DEVICE = 0xC00000D4,
|
||||||
|
STATUS_FILE_RENAMED = 0xC00000D5,
|
||||||
|
STATUS_PIPE_EMPTY = 0xC00000D9,
|
||||||
|
# 0xC00000F
|
||||||
|
STATUS_REDIRECTOR_NOT_STARTED = 0xC00000FB,
|
||||||
|
# 0xC00001
|
||||||
|
STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101,
|
||||||
|
STATUS_PROCESS_IS_TERMINATING = 0xC000010A,
|
||||||
|
STATUS_TOO_MANY_OPENED_FILES = 0xC000011F,
|
||||||
|
STATUS_CANNOT_DELETE = 0xC0000121,
|
||||||
|
STATUS_FILE_DELETED = 0xC0000123,
|
||||||
|
STATUS_FILE_CLOSED = 0xC0000128,
|
||||||
|
STATUS_INVALID_DEVICE_STATE = 0xC0000184,
|
||||||
|
STATUS_ACCOUNT_EXPIRED = 0xC0000193,
|
||||||
|
# 0xC00002
|
||||||
|
STATUS_USER_SESSION_DELETED = 0xC0000203,
|
||||||
|
STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205,
|
||||||
|
STATUS_PASSWORD_MUST_CHANGE = 0xC0000224,
|
||||||
|
STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234,
|
||||||
|
STATUS_PATH_NOT_COVERED = 0xC0000257,
|
||||||
|
# 0xC00003
|
||||||
|
STATUS_NETWORK_SESSION_EXPIRED = 0xC000035C,
|
||||||
|
# 0xC0002
|
||||||
|
STATUS_SMB_TOO_MANY_UIDS = 0xC000205A,
|
||||||
|
# 0xF
|
||||||
|
STATUS_SMB_NO_SUPPORT = 0xFFFF0002,
|
||||||
|
};
|
||||||
|
|
||||||
|
function determine_transaction_type(setup_count: int, name: SMB_string): TransactionType
|
||||||
|
%{
|
||||||
|
if ( name == NULL )
|
||||||
|
{
|
||||||
|
return SMB_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ${name.u.s}->size() == 14 && ${name.u.s[0]} == '\\' && ${name.u.s[2]} == 'P' && ${name.u.s[4]} == 'I' && ${name.u.s[6]} == 'P' && ${name.u.s[8]} == 'E' && ${name.u.s[10]} == '\\')
|
||||||
|
{
|
||||||
|
return SMB_PIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SMB_UNKNOWN;
|
||||||
|
%}
|
29
src/analyzer/protocol/smb/smb-gssapi.pac
Normal file
29
src/analyzer/protocol/smb/smb-gssapi.pac
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
%member{
|
||||||
|
analyzer::Analyzer *gssapi;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
gssapi = 0;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
if ( gssapi )
|
||||||
|
{
|
||||||
|
gssapi->Done();
|
||||||
|
delete gssapi;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
function forward_gssapi(data: bytestring, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
if ( ! gssapi )
|
||||||
|
gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer()->Conn());
|
||||||
|
|
||||||
|
if ( gssapi )
|
||||||
|
gssapi->DeliverStream(${data}.length(), ${data}.begin(), is_orig);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
enum SMB_MailSlot_opcode {
|
enum SMB_MailSlot_opcode {
|
||||||
HOST_ANNOUNCEMENT = 1,
|
HOST_ANNOUNCEMENT = 1,
|
||||||
ANNOUCEMENT_REQUEST = 2,
|
ANNOUCEMENT_REQUEST = 2,
|
||||||
|
|
|
@ -1,19 +1,56 @@
|
||||||
# this won't work correctly yet, since sometimes the parameters
|
%extern{
|
||||||
# field in the transaction takes up all of the data field
|
#include "../dce-rpc/DCE_RPC.h"
|
||||||
|
%}
|
||||||
|
|
||||||
type SMB_Pipe_message( unicode: bool, byte_count: uint16, sub_cmd: uint16 ) = record {
|
refine connection SMB_Conn += {
|
||||||
|
%member{
|
||||||
|
map<uint16,bool> tree_is_pipe_map;
|
||||||
|
map<uint64,analyzer::dce_rpc::DCE_RPC_Analyzer*> fid_to_analyzer_map;;
|
||||||
|
%}
|
||||||
|
|
||||||
# there's a problem with byte_count here, not sure why ... its
|
%cleanup{
|
||||||
# not the real length of the rest of the packet
|
// Iterate all of the analyzers and destroy them.
|
||||||
data : bytestring &restofdata;
|
for ( auto kv : fid_to_analyzer_map )
|
||||||
|
{
|
||||||
|
if ( kv.second )
|
||||||
|
{
|
||||||
|
kv.second->Done();
|
||||||
|
delete kv.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record {
|
function get_tree_is_pipe(tree_id: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( tree_is_pipe_map.count(tree_id) > 0 )
|
||||||
|
return tree_is_pipe_map.at(tree_id);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
%}
|
||||||
|
|
||||||
rap_code : uint16;
|
function set_tree_is_pipe(tree_id: uint16, is_pipe: bool): bool
|
||||||
param_desc : SMB_string(unicode, offsetof(param_desc) );
|
%{
|
||||||
data_desc : SMB_string(unicode, offsetof(data_desc) );
|
tree_is_pipe_map[tree_id] = is_pipe;
|
||||||
data : bytestring &restofdata;
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
} &byteorder = littleendian;
|
function forward_dce_rpc(pipe_data: bytestring, fid: uint64, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
analyzer::dce_rpc::DCE_RPC_Analyzer *pipe_dcerpc;
|
||||||
|
if ( fid_to_analyzer_map.count(fid) == 0 )
|
||||||
|
{
|
||||||
|
pipe_dcerpc = (analyzer::dce_rpc::DCE_RPC_Analyzer *)analyzer_mgr->InstantiateAnalyzer("DCE_RPC", bro_analyzer()->Conn());
|
||||||
|
pipe_dcerpc->SetFileID(fid);
|
||||||
|
fid_to_analyzer_map[fid] = pipe_dcerpc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipe_dcerpc = fid_to_analyzer_map.at(fid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_dcerpc->DeliverStream(${pipe_data}.length(), ${pipe_data}.begin(), is_orig);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
|
@ -1,465 +0,0 @@
|
||||||
# CIFS/SMB
|
|
||||||
|
|
||||||
# TODO:
|
|
||||||
# - Built support for unicode strings
|
|
||||||
# - Unicode as an implicit attribute (as byteorder)
|
|
||||||
# - &truncation_ok attribute for the last field of a record to deal with partial data
|
|
||||||
|
|
||||||
enum TransactionType {
|
|
||||||
SMB_MAILSLOT_BROWSE, # \MAILSLOT\BROWSE - MS Browse Protocol
|
|
||||||
SMB_MAILSLOT_LANMAN, # \MAILSLOT\LANMAN - deprecated cmds
|
|
||||||
SMB_PIPE, # \PIPE\* named pipes?
|
|
||||||
SMB_RAP, # \PIPE\LANMAN - remote administration protocol
|
|
||||||
SMB_UNKNOWN, # there's probably lots of these
|
|
||||||
};
|
|
||||||
|
|
||||||
function extract_string(s: SMB_string) : const_bytestring
|
|
||||||
%{
|
|
||||||
int length = 0;
|
|
||||||
|
|
||||||
char* buf;
|
|
||||||
const char* sp;
|
|
||||||
|
|
||||||
if( s->val_case_index() == 0 )
|
|
||||||
{
|
|
||||||
length = s->a()->size();
|
|
||||||
buf = new char[ length ];
|
|
||||||
|
|
||||||
for( int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
unsigned char t = (*(s->a()))[i];
|
|
||||||
buf[i] = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
length = s->u()->s()->size();
|
|
||||||
buf = new char[ length ];
|
|
||||||
|
|
||||||
for( int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
unsigned short temp = (*(s->u()->s()))[i];
|
|
||||||
buf[i] = temp & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytestring((uint8*) buf, length);
|
|
||||||
%}
|
|
||||||
|
|
||||||
function determine_transaction_type(setup_count: int, name: SMB_string): TransactionType
|
|
||||||
%{
|
|
||||||
// This logic needs to be verified! the relationship between
|
|
||||||
// setup_count and type is very unclear.
|
|
||||||
if ( name == NULL )
|
|
||||||
return SMB_UNKNOWN;
|
|
||||||
|
|
||||||
if ( bytestring_caseprefix( extract_string(name),
|
|
||||||
"\\PIPE\\LANMAN" ) )
|
|
||||||
{
|
|
||||||
return SMB_RAP;
|
|
||||||
}
|
|
||||||
else if ( bytestring_caseprefix( extract_string(name),
|
|
||||||
"\\MAILSLOT\\LANMAN" ) )
|
|
||||||
{
|
|
||||||
return SMB_MAILSLOT_LANMAN;
|
|
||||||
//return SMB_MAILSLOT_BROWSE;
|
|
||||||
}
|
|
||||||
else if ( bytestring_caseprefix( extract_string(name),
|
|
||||||
"\\MAILSLOT\\NET\\NETLOGON" ) )
|
|
||||||
{
|
|
||||||
/* Don't really know what to do here, its got a Mailslot
|
|
||||||
* type but its a depricated packet format that handles
|
|
||||||
* old windows logon
|
|
||||||
*/
|
|
||||||
return SMB_UNKNOWN;
|
|
||||||
}
|
|
||||||
else if(setup_count == 2 ||
|
|
||||||
bytestring_caseprefix( extract_string(name), "\\PIPE\\" ) )
|
|
||||||
{
|
|
||||||
return SMB_PIPE;
|
|
||||||
}
|
|
||||||
else if (setup_count == 3 ||
|
|
||||||
bytestring_caseprefix( extract_string(name), "\\MAILSLOT\\" ) )
|
|
||||||
{
|
|
||||||
return SMB_MAILSLOT_BROWSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return SMB_UNKNOWN;
|
|
||||||
%}
|
|
||||||
|
|
||||||
function name_string(trans: SMB_transaction): SMB_string
|
|
||||||
%{
|
|
||||||
if( trans->trans_type() == 1 )
|
|
||||||
return trans->name();
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
%}
|
|
||||||
|
|
||||||
|
|
||||||
type SMB_dos_error = record {
|
|
||||||
error_class : uint8;
|
|
||||||
reserved : uint8;
|
|
||||||
error : uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SMB_error (err_status_type: int) = case err_status_type of {
|
|
||||||
0 -> dos_error: SMB_dos_error;
|
|
||||||
1 -> status: int32;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SMB_header = record {
|
|
||||||
protocol : bytestring &length = 4;
|
|
||||||
command : uint8;
|
|
||||||
status : SMB_error(err_status_type);
|
|
||||||
flags : uint8;
|
|
||||||
flags2 : uint16;
|
|
||||||
pad : padding[12];
|
|
||||||
tid : uint16;
|
|
||||||
pid : uint16;
|
|
||||||
uid : uint16;
|
|
||||||
mid : uint16;
|
|
||||||
} &let {
|
|
||||||
err_status_type = (flags2 >> 14) & 1;
|
|
||||||
unicode = (flags2 >> 15) & 1;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
# TODO: compute this as
|
|
||||||
# let smb_header_length = sizeof(SMB_header);
|
|
||||||
let smb_header_length = 32;
|
|
||||||
|
|
||||||
type SMB_body = record {
|
|
||||||
word_count : uint8;
|
|
||||||
parameter_words : uint16[word_count];
|
|
||||||
byte_count : uint16;
|
|
||||||
# buffer : uint8[byte_count];
|
|
||||||
} &let {
|
|
||||||
body_length = 1 + word_count * 2 + 2 + byte_count;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_ascii_string = uint8[] &until($element == 0);
|
|
||||||
type SMB_unicode_string(offset: int) = record {
|
|
||||||
pad : padding[offset & 1];
|
|
||||||
s : uint16[] &until($element == 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
type SMB_string(unicode: bool, offset: int) = case unicode of {
|
|
||||||
true -> u: SMB_unicode_string(offset);
|
|
||||||
false -> a: SMB_ascii_string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SMB_time = record {
|
|
||||||
two_seconds : uint16;
|
|
||||||
minutes : uint16;
|
|
||||||
hours : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_date = record {
|
|
||||||
day : uint16;
|
|
||||||
month : uint16;
|
|
||||||
year : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_andx = record {
|
|
||||||
command : uint8;
|
|
||||||
reserved : uint8;
|
|
||||||
offset : uint16;
|
|
||||||
} &refcount;
|
|
||||||
|
|
||||||
type SMB_generic_andx = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx_u : case word_count of {
|
|
||||||
0 -> null : empty;
|
|
||||||
default -> andx : SMB_andx;
|
|
||||||
};
|
|
||||||
data : bytestring &restofdata;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_dialect = record {
|
|
||||||
bufferformat : uint8; # must be 0x2
|
|
||||||
dialectname : SMB_ascii_string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SMB_negotiate = record {
|
|
||||||
word_count : uint8; # must be 0
|
|
||||||
byte_count : uint16;
|
|
||||||
dialects : SMB_dialect[] &length = byte_count;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_negotiate_response = record {
|
|
||||||
word_count : uint8; # should be 1
|
|
||||||
dialect_index : uint16;
|
|
||||||
byte_count : uint16; # should be 0
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_negotiate_response_long(unicode: bool) = record {
|
|
||||||
word_count : uint8; # should be 13
|
|
||||||
dialect_index : uint16;
|
|
||||||
security_mode : uint16; # bit 0: 0=share 1=user, bit 1: 1=chalenge/response
|
|
||||||
max_buffer_size : uint16;
|
|
||||||
max_mpx_count : uint16;
|
|
||||||
max_number_vcs : uint16;
|
|
||||||
raw_mode : uint16;
|
|
||||||
session_key : uint32;
|
|
||||||
server_time : SMB_time;
|
|
||||||
server_date : SMB_date;
|
|
||||||
server_tz : uint16;
|
|
||||||
enc_key_len : uint16;
|
|
||||||
reserved : uint16; # must be 0
|
|
||||||
byte_count : uint16;
|
|
||||||
encryption_key : uint8[enc_key_len];
|
|
||||||
primary_domain : SMB_string(unicode, offsetof(primary_domain));
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
# pre NT LM 0.12
|
|
||||||
type SMB_setup_andx_basic(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
max_buffer_size : uint16;
|
|
||||||
max_mpx_count : uint16;
|
|
||||||
vc_number : uint16;
|
|
||||||
session_key : uint32;
|
|
||||||
passwd_length : uint8;
|
|
||||||
reserved : uint32;
|
|
||||||
byte_count : uint8;
|
|
||||||
password : uint8[passwd_length];
|
|
||||||
name : SMB_string(unicode, offsetof(name));
|
|
||||||
domain : SMB_string(unicode, offsetof(domain));
|
|
||||||
native_os : SMB_string(unicode, offsetof(native_os));
|
|
||||||
native_lanman : SMB_string(unicode, offsetof(native_lanman));
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_setup_andx_basic_response(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
action : uint8;
|
|
||||||
byte_count : uint8;
|
|
||||||
native_os : SMB_string(unicode, offsetof(native_os));
|
|
||||||
native_lanman : SMB_string(unicode, offsetof(native_lanman));
|
|
||||||
primary_domain : SMB_string(unicode, offsetof(primary_domain));
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
# NT LM 0.12 && CAP_EXTENDED_SECURITY
|
|
||||||
type SMB_setup_andx_ext(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
max_buffer_size : uint16;
|
|
||||||
max_mpx_count : uint16;
|
|
||||||
vc_number : uint16;
|
|
||||||
session_key : uint32;
|
|
||||||
security_length : uint8;
|
|
||||||
reserved : uint32;
|
|
||||||
capabilities : uint32;
|
|
||||||
byte_count : uint8;
|
|
||||||
security_blob : uint8[security_length];
|
|
||||||
native_os : SMB_string(unicode, offsetof(native_os));
|
|
||||||
native_lanman : SMB_string(unicode, offsetof(native_lanman));
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_setup_andx_ext_response(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
action : uint8;
|
|
||||||
security_length : uint8;
|
|
||||||
byte_count : uint8;
|
|
||||||
security_blob : uint8[security_length];
|
|
||||||
native_os : SMB_string(unicode, offsetof(native_os));
|
|
||||||
native_lanman : SMB_string(unicode, offsetof(native_lanman));
|
|
||||||
primary_domain : SMB_string(unicode, offsetof(primary_domain));
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_logoff_andx(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
byte_count : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_tree_connect_andx(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
flags : uint16;
|
|
||||||
password_length : uint16;
|
|
||||||
byte_count : uint16;
|
|
||||||
password : uint8[password_length];
|
|
||||||
path : SMB_string(unicode, offsetof(path));
|
|
||||||
service : SMB_ascii_string;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_close(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
fid : uint16;
|
|
||||||
time : SMB_time;
|
|
||||||
byte_count : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_tree_disconnect(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
byte_count : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_nt_create_andx(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
reserved : uint8;
|
|
||||||
name_length : uint16;
|
|
||||||
flags : uint32;
|
|
||||||
rest_words : uint8[word_count * 2 - 11];
|
|
||||||
byte_count : uint16;
|
|
||||||
name : SMB_string(unicode, offsetof(name));
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_read_andx = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
fid : uint16;
|
|
||||||
offset : uint32;
|
|
||||||
max_count : uint16;
|
|
||||||
min_count : uint16;
|
|
||||||
max_count_high : uint16;
|
|
||||||
remaining : uint16;
|
|
||||||
offset_high_u : case word_count of {
|
|
||||||
12-> offset_high : uint32;
|
|
||||||
10-> null : empty;
|
|
||||||
};
|
|
||||||
byte_count : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_read_andx_response = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
remaining : uint16;
|
|
||||||
data_compact : uint16;
|
|
||||||
reserved : uint16;
|
|
||||||
data_len : uint16;
|
|
||||||
data_offset : uint16;
|
|
||||||
data_len_high : uint16;
|
|
||||||
reserved2 : uint16[4];
|
|
||||||
byte_count : uint16;
|
|
||||||
pad : padding[padding_length];
|
|
||||||
data : bytestring &length = data_length;
|
|
||||||
# Chris: the length here is causing problems - could we be having
|
|
||||||
# issues with the packet format or is the data_length just not
|
|
||||||
# right. The problem is that the padding isn't always filled right,
|
|
||||||
# espeically when its not the first command in the packet.
|
|
||||||
#data : bytestring &restofdata;
|
|
||||||
} &let {
|
|
||||||
data_length = data_len_high * 0x10000 + data_len;
|
|
||||||
padding_length = byte_count - data_length;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_write_andx = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
fid : uint16;
|
|
||||||
offset : uint32;
|
|
||||||
reserved : uint32;
|
|
||||||
write_mode : uint16;
|
|
||||||
remaining : uint16;
|
|
||||||
data_len_high : uint16;
|
|
||||||
data_len : uint16;
|
|
||||||
data_offset : uint16;
|
|
||||||
rest_words : uint8[word_count * 2 - offsetof(rest_words) + 1];
|
|
||||||
byte_count : uint16;
|
|
||||||
pad : padding to data_offset - smb_header_length;
|
|
||||||
data : bytestring &length = data_length;
|
|
||||||
} &let {
|
|
||||||
data_length = data_len_high * 0x10000 + data_len;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_write_andx_response = record {
|
|
||||||
word_count : uint8;
|
|
||||||
andx : SMB_andx;
|
|
||||||
count : uint16; # written bytes
|
|
||||||
remaining : uint16;
|
|
||||||
reserved : uint32;
|
|
||||||
byte_count : uint16;
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_transaction_data(unicode: bool, count: uint16, sub_cmd: uint16,
|
|
||||||
trans_type: TransactionType ) = case trans_type of {
|
|
||||||
|
|
||||||
SMB_MAILSLOT_BROWSE -> mailslot : SMB_MailSlot_message(unicode, count);
|
|
||||||
SMB_MAILSLOT_LANMAN -> lanman : SMB_MailSlot_message(unicode, count);
|
|
||||||
SMB_RAP -> rap : SMB_Pipe_message(unicode, count, sub_cmd);
|
|
||||||
SMB_PIPE -> pipe : SMB_Pipe_message(unicode, count, sub_cmd);
|
|
||||||
SMB_UNKNOWN -> unknown : bytestring &restofdata;
|
|
||||||
default -> data : bytestring &restofdata;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
type SMB_transaction(trans_type: int, unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
total_param_count : uint16;
|
|
||||||
total_data_count : uint16;
|
|
||||||
max_param_count : uint16;
|
|
||||||
max_data_count : uint16;
|
|
||||||
max_setup_count : uint8;
|
|
||||||
reserved : uint8;
|
|
||||||
flags : uint16;
|
|
||||||
timeout : uint32;
|
|
||||||
reserved2 : uint16;
|
|
||||||
param_count : uint16;
|
|
||||||
param_offset : uint16;
|
|
||||||
data_count : uint16;
|
|
||||||
data_offset : uint16;
|
|
||||||
setup_count : uint8;
|
|
||||||
reserved3 : uint8;
|
|
||||||
setup : uint16[setup_count];
|
|
||||||
byte_count : uint16;
|
|
||||||
name_u : case trans_type of {
|
|
||||||
1 -> name: SMB_string(unicode, offsetof(name_u));
|
|
||||||
2 -> null: empty;
|
|
||||||
};
|
|
||||||
pad0 : padding to param_offset - smb_header_length;
|
|
||||||
parameters : bytestring &length = param_count;
|
|
||||||
pad1 : padding to data_offset - smb_header_length;
|
|
||||||
data : SMB_transaction_data(unicode, data_count, sub_cmd,
|
|
||||||
determine_transaction_type( setup_count, name_string( this )));
|
|
||||||
} &let {
|
|
||||||
# does this work?
|
|
||||||
sub_cmd : uint16 = setup_count ? setup[0] : 0;
|
|
||||||
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_transaction_secondary(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
total_param_count : uint16;
|
|
||||||
total_data_count : uint16;
|
|
||||||
param_count : uint16;
|
|
||||||
param_offset : uint16;
|
|
||||||
param_displacement : uint16;
|
|
||||||
data_count : uint16;
|
|
||||||
data_offset : uint16;
|
|
||||||
data_displacement : uint16;
|
|
||||||
fid : uint16;
|
|
||||||
byte_count : uint16;
|
|
||||||
pad0 : padding to param_offset - smb_header_length;
|
|
||||||
parameters : bytestring &length = param_count;
|
|
||||||
pad1 : padding to data_offset - smb_header_length;
|
|
||||||
data : SMB_transaction_data(unicode, data_count, 0, SMB_UNKNOWN);
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_transaction_response(unicode: bool) = record {
|
|
||||||
word_count : uint8;
|
|
||||||
total_param_count : uint16;
|
|
||||||
total_data_count : uint16;
|
|
||||||
reserved : uint16;
|
|
||||||
param_count : uint16;
|
|
||||||
param_offset : uint16;
|
|
||||||
param_displacement : uint16;
|
|
||||||
data_count : uint16;
|
|
||||||
data_offset : uint16;
|
|
||||||
data_displacement : uint16;
|
|
||||||
setup_count : uint8;
|
|
||||||
reserved2 : uint8;
|
|
||||||
setup : uint16[setup_count];
|
|
||||||
byte_count : uint16;
|
|
||||||
pad0 : padding to param_offset - smb_header_length;
|
|
||||||
parameters : bytestring &length = param_count;
|
|
||||||
pad1 : padding to data_offset - smb_header_length;
|
|
||||||
data : SMB_transaction_data(unicode, data_count, 0, SMB_UNKNOWN);
|
|
||||||
} &byteorder = littleendian;
|
|
||||||
|
|
||||||
type SMB_get_dfs_referral(unicode: bool) = record {
|
|
||||||
max_referral_level : uint16;
|
|
||||||
file_name : SMB_string(unicode, offsetof(file_name));
|
|
||||||
} &byteorder = littleendian;
|
|
92
src/analyzer/protocol/smb/smb-strings.pac
Normal file
92
src/analyzer/protocol/smb/smb-strings.pac
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
function uint8s_to_stringval(data: uint8[]): StringVal
|
||||||
|
%{
|
||||||
|
int length = data->size();
|
||||||
|
uint8 buf[length];
|
||||||
|
|
||||||
|
for ( int i = 0; i < length; ++i)
|
||||||
|
buf[i] = (*data)[i];
|
||||||
|
|
||||||
|
const bytestring bs = bytestring(buf, length);
|
||||||
|
return utf16_bytestring_to_utf8_val(bs);
|
||||||
|
%}
|
||||||
|
|
||||||
|
function extract_string(s: SMB_string) : StringVal
|
||||||
|
%{
|
||||||
|
if ( s->unicode() == 0 )
|
||||||
|
{
|
||||||
|
int length = s->a()->size();
|
||||||
|
char buf[length];
|
||||||
|
|
||||||
|
for ( int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
unsigned char t = (*(s->a()))[i];
|
||||||
|
buf[i] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( length > 0 && buf[length-1] == 0x00 )
|
||||||
|
length--;
|
||||||
|
|
||||||
|
return new StringVal(length, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return uint8s_to_stringval(s->u()->s());
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
function smb_string2stringval(s: SMB_string) : StringVal
|
||||||
|
%{
|
||||||
|
return extract_string(s);
|
||||||
|
%}
|
||||||
|
|
||||||
|
function smb2_string2stringval(s: SMB2_string) : StringVal
|
||||||
|
%{
|
||||||
|
return uint8s_to_stringval(s->s());
|
||||||
|
%}
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
%member{
|
||||||
|
SMB_unicode_string *me;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
me = 0;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function store_this_unicode_string(s: SMB_unicode_string): bool
|
||||||
|
%{
|
||||||
|
me = s;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function get_prev_elem(): uint8
|
||||||
|
%{
|
||||||
|
if ( me && (me->s()->size() & 1) == 0 && me->s()->size() > 1 )
|
||||||
|
{
|
||||||
|
return me->s()->at(me->s()->size() - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0xFF;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_ascii_string = uint8[] &until($element == 0x00);
|
||||||
|
|
||||||
|
type SMB_unicode_string(offset: int) = record {
|
||||||
|
pad : uint8[offset & 1] &let {
|
||||||
|
# Save off a pointer to this string instance.
|
||||||
|
prev: bool = $context.connection.store_this_unicode_string(this);
|
||||||
|
};
|
||||||
|
# Access the end of the string stored in this instance
|
||||||
|
# to see if the previous character was a null.
|
||||||
|
s : uint8[] &until($element == 0x00 && $context.connection.get_prev_elem() == 0x00);
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type SMB_string(unicode: bool, offset: int) = case unicode of {
|
||||||
|
true -> u: SMB_unicode_string(offset);
|
||||||
|
false -> a: SMB_ascii_string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB2_string(len: int) = record {
|
||||||
|
s : uint8[len];
|
||||||
|
};
|
51
src/analyzer/protocol/smb/smb-time.pac
Normal file
51
src/analyzer/protocol/smb/smb-time.pac
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
function SMB_BuildMACTimes(modify: uint64, access: uint64, create: uint64, change: uint64): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* r = new RecordVal(BifType::Record::SMB::MACTimes);
|
||||||
|
|
||||||
|
r->Assign(0, filetime2brotime(modify));
|
||||||
|
r->Assign(1, filetime2brotime(access));
|
||||||
|
r->Assign(2, filetime2brotime(create));
|
||||||
|
r->Assign(3, filetime2brotime(change));
|
||||||
|
|
||||||
|
return r;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function filetime2brotime(ts: uint64): Val
|
||||||
|
%{
|
||||||
|
double secs = (ts / 10000000.0);
|
||||||
|
|
||||||
|
// Bro can't support times back to the 1600's
|
||||||
|
// so we subtract a lot of seconds.
|
||||||
|
Val* bro_ts = new Val(secs - 11644473600.0, TYPE_TIME);
|
||||||
|
|
||||||
|
return bro_ts;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function time_from_lanman(t: SMB_time, d: SMB_date, tz: uint16): Val
|
||||||
|
%{
|
||||||
|
tm lTime;
|
||||||
|
lTime.tm_sec = ${t.two_seconds} * 2;
|
||||||
|
lTime.tm_min = ${t.minutes};
|
||||||
|
lTime.tm_hour = ${t.hours};
|
||||||
|
lTime.tm_mday = ${d.day};
|
||||||
|
lTime.tm_mon = ${d.month};
|
||||||
|
lTime.tm_year = 1980 + ${d.year};
|
||||||
|
double lResult = mktime(&lTime);
|
||||||
|
return new Val(lResult + tz, TYPE_TIME);
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
|
type SMB_timestamp32 = uint32;
|
||||||
|
type SMB_timestamp = uint64;
|
||||||
|
|
||||||
|
type SMB_time = record {
|
||||||
|
two_seconds : uint16;
|
||||||
|
minutes : uint16;
|
||||||
|
hours : uint16;
|
||||||
|
} &byteorder = littleendian;
|
||||||
|
|
||||||
|
type SMB_date = record {
|
||||||
|
day : uint16;
|
||||||
|
month : uint16;
|
||||||
|
year : uint16;
|
||||||
|
} &byteorder = littleendian;
|
|
@ -2,11 +2,136 @@
|
||||||
%include bro.pac
|
%include bro.pac
|
||||||
|
|
||||||
%extern{
|
%extern{
|
||||||
#include "events.bif.h"
|
#include "analyzer/Manager.h"
|
||||||
|
#include "analyzer/Analyzer.h"
|
||||||
|
|
||||||
|
#include "smb1_events.bif.h"
|
||||||
|
#include "smb2_events.bif.h"
|
||||||
|
|
||||||
|
#include "types.bif.h"
|
||||||
|
|
||||||
|
#include "smb1_com_check_directory.bif.h"
|
||||||
|
#include "smb1_com_close.bif.h"
|
||||||
|
#include "smb1_com_create_directory.bif.h"
|
||||||
|
#include "smb1_com_echo.bif.h"
|
||||||
|
#include "smb1_com_logoff_andx.bif.h"
|
||||||
|
#include "smb1_com_negotiate.bif.h"
|
||||||
|
#include "smb1_com_nt_cancel.bif.h"
|
||||||
|
#include "smb1_com_nt_create_andx.bif.h"
|
||||||
|
#include "smb1_com_query_information.bif.h"
|
||||||
|
#include "smb1_com_read_andx.bif.h"
|
||||||
|
#include "smb1_com_session_setup_andx.bif.h"
|
||||||
|
#include "smb1_com_transaction.bif.h"
|
||||||
|
#include "smb1_com_transaction2.bif.h"
|
||||||
|
#include "smb1_com_tree_connect_andx.bif.h"
|
||||||
|
#include "smb1_com_tree_disconnect.bif.h"
|
||||||
|
#include "smb1_com_write_andx.bif.h"
|
||||||
|
|
||||||
|
#include "smb2_com_close.bif.h"
|
||||||
|
#include "smb2_com_create.bif.h"
|
||||||
|
//#include "smb2_com_ioctl.bif.h"
|
||||||
|
//#include "smb2_com_lock.bif.h"
|
||||||
|
#include "smb2_com_negotiate.bif.h"
|
||||||
|
#include "smb2_com_read.bif.h"
|
||||||
|
#include "smb2_com_session_setup.bif.h"
|
||||||
|
#include "smb2_com_set_info.bif.h"
|
||||||
|
#include "smb2_com_tree_connect.bif.h"
|
||||||
|
//#include "smb2_com_tree_disconnect.bif.h"
|
||||||
|
#include "smb2_com_write.bif.h"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
analyzer SMB withcontext { };
|
analyzer SMB withcontext {
|
||||||
|
connection: SMB_Conn;
|
||||||
|
flow: SMB_Flow;
|
||||||
|
};
|
||||||
|
|
||||||
%include smb-protocol.pac
|
connection SMB_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = SMB_Flow(true);
|
||||||
|
downflow = SMB_Flow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include smb-strings.pac
|
||||||
|
%include smb-common.pac
|
||||||
|
%include smb-time.pac
|
||||||
%include smb-mailslot.pac
|
%include smb-mailslot.pac
|
||||||
%include smb-pipe.pac
|
%include smb-pipe.pac
|
||||||
|
%include smb-gssapi.pac
|
||||||
|
|
||||||
|
# SMB1 Commands
|
||||||
|
%include smb1-com-check-directory.pac
|
||||||
|
%include smb1-com-close.pac
|
||||||
|
%include smb1-com-create-directory.pac
|
||||||
|
%include smb1-com-echo.pac
|
||||||
|
%include smb1-com-locking-andx.pac
|
||||||
|
%include smb1-com-logoff-andx.pac
|
||||||
|
%include smb1-com-negotiate.pac
|
||||||
|
%include smb1-com-nt-cancel.pac
|
||||||
|
%include smb1-com-nt-create-andx.pac
|
||||||
|
%include smb1-com-nt-transact.pac
|
||||||
|
%include smb1-com-query-information.pac
|
||||||
|
%include smb1-com-read-andx.pac
|
||||||
|
%include smb1-com-session-setup-andx.pac
|
||||||
|
%include smb1-com-transaction-secondary.pac
|
||||||
|
%include smb1-com-transaction.pac
|
||||||
|
%include smb1-com-transaction2.pac
|
||||||
|
%include smb1-com-tree-connect-andx.pac
|
||||||
|
%include smb1-com-tree-disconnect.pac
|
||||||
|
%include smb1-com-write-andx.pac
|
||||||
|
|
||||||
|
# SMB2 Commands
|
||||||
|
%include smb2-com-close.pac
|
||||||
|
%include smb2-com-create.pac
|
||||||
|
%include smb2-com-ioctl.pac
|
||||||
|
%include smb2-com-lock.pac
|
||||||
|
%include smb2-com-negotiate.pac
|
||||||
|
%include smb2-com-read.pac
|
||||||
|
%include smb2-com-session-setup.pac
|
||||||
|
%include smb2-com-set-info.pac
|
||||||
|
%include smb2-com-tree-connect.pac
|
||||||
|
%include smb2-com-tree-disconnect.pac
|
||||||
|
%include smb2-com-write.pac
|
||||||
|
|
||||||
|
type uint24 = record {
|
||||||
|
byte1 : uint8;
|
||||||
|
byte2 : uint8;
|
||||||
|
byte3 : uint8;
|
||||||
|
};
|
||||||
|
|
||||||
|
function to_int(num: uint24): uint32
|
||||||
|
%{
|
||||||
|
return (num->byte1() << 16) | (num->byte2() << 8) | num->byte3();
|
||||||
|
%}
|
||||||
|
|
||||||
|
type SMB_TCP(is_orig: bool) = record {
|
||||||
|
# These are technically NetBIOS fields but it's considered
|
||||||
|
# to be SMB directly over TCP. The fields are essentially
|
||||||
|
# the NBSS protocol but it's only used for framing here.
|
||||||
|
message_type : uint8;
|
||||||
|
len24 : uint24;
|
||||||
|
body : case message_type of {
|
||||||
|
# SMB/SMB2 packets are required to use NBSS session messages.
|
||||||
|
0 -> nbss : SMB_Protocol_Identifier(is_orig, len);
|
||||||
|
|
||||||
|
# TODO: support more nbss message types?
|
||||||
|
default -> skip : bytestring &transient &restofdata;
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
len : uint32 = to_int(len24);
|
||||||
|
} &byteorder = littleendian &length=len+4;
|
||||||
|
|
||||||
|
type SMB_Protocol_Identifier(is_orig: bool, msg_len: uint32) = record {
|
||||||
|
# Sort of cheating by reading this in as an integer instead of a string.
|
||||||
|
protocol : uint32 &byteorder=bigendian;
|
||||||
|
smb_1_or_2 : case protocol of {
|
||||||
|
SMB1 -> smb1 : SMB_PDU(is_orig, msg_len);
|
||||||
|
SMB2 -> smb2 : SMB2_PDU(is_orig);
|
||||||
|
default -> unknown : empty;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
%include smb1-protocol.pac
|
||||||
|
%include smb2-protocol.pac
|
||||||
|
|
||||||
|
flow SMB_Flow(is_orig: bool) {
|
||||||
|
flowunit = SMB_TCP(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
37
src/analyzer/protocol/smb/smb1-com-check-directory.pac
Normal file
37
src/analyzer/protocol/smb/smb1-com-check-directory.pac
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_check_directory_request(header: SMB_Header, val: SMB1_check_directory_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_check_directory_request )
|
||||||
|
BifEvent::generate_smb1_check_directory_request(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.directory_name}));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_check_directory_response(header: SMB_Header, val: SMB1_check_directory_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_check_directory_response )
|
||||||
|
BifEvent::generate_smb1_check_directory_response(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_check_directory_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
buffer_format : uint8; # must be 0x04
|
||||||
|
directory_name : SMB_string(header.unicode, offsetof(directory_name));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_check_directory_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_check_directory_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_check_directory_response(header, this);
|
||||||
|
};
|
34
src/analyzer/protocol/smb/smb1-com-close.pac
Normal file
34
src/analyzer/protocol/smb/smb1-com-close.pac
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_close_request(h: SMB_Header, val: SMB1_close_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_close_request )
|
||||||
|
BifEvent::generate_smb1_close_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.file_id});
|
||||||
|
|
||||||
|
// This is commented out for the moment because it caused problems
|
||||||
|
// with extraction because the file kept having the same name due
|
||||||
|
// to repeatedly having the same file uid. This results in files
|
||||||
|
// effectively falling of SMB solely by expiration instead of
|
||||||
|
// manually being closed.
|
||||||
|
|
||||||
|
//file_mgr->EndOfFile(bro_analyzer()->GetAnalyzerTag(),
|
||||||
|
// bro_analyzer()->Conn(), h->is_orig());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
type SMB1_close_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
file_id : uint16;
|
||||||
|
last_modified_time : SMB_timestamp32;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_close_request(header, this);
|
||||||
|
};
|
36
src/analyzer/protocol/smb/smb1-com-create-directory.pac
Normal file
36
src/analyzer/protocol/smb/smb1-com-create-directory.pac
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_create_directory_request(header: SMB_Header, val: SMB1_create_directory_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_create_directory_request )
|
||||||
|
BifEvent::generate_smb1_create_directory_request(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.directory_name}));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
function proc_smb1_create_directory_response(header: SMB_Header, val: SMB1_create_directory_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_create_directory_response )
|
||||||
|
BifEvent::generate_smb1_create_directory_response(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_create_directory_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
byte_count : uint16;
|
||||||
|
buffer_format : uint8;
|
||||||
|
directory_name : SMB_string(header.unicode, offsetof(directory_name));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_create_directory_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_create_directory_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_create_directory_response(header, this);
|
||||||
|
};
|
||||||
|
|
43
src/analyzer/protocol/smb/smb1-com-echo.pac
Normal file
43
src/analyzer/protocol/smb/smb1-com-echo.pac
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_echo_request(header: SMB_Header, val: SMB1_echo_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_echo_request )
|
||||||
|
BifEvent::generate_smb1_echo_request(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
${val.echo_count}, bytestring_to_val(${val.data}));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_echo_response(header: SMB_Header, val: SMB1_echo_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_echo_response )
|
||||||
|
BifEvent::generate_smb1_echo_response(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
${val.seq_num}, bytestring_to_val(${val.data}));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
# http://msdn.microsoft.com/en-us/library/ee441746.aspx
|
||||||
|
type SMB1_echo_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
echo_count : uint16;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
data : bytestring &length=byte_count;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_echo_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
# http://msdn.microsoft.com/en-us/library/ee441626.aspx
|
||||||
|
type SMB1_echo_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
seq_num : uint16;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
data : bytestring &length=byte_count;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_echo_response(header, this);
|
||||||
|
};
|
||||||
|
|
59
src/analyzer/protocol/smb/smb1-com-locking-andx.pac
Normal file
59
src/analyzer/protocol/smb/smb1-com-locking-andx.pac
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_locking_andx_request(header: SMB_Header, val: SMB1_locking_andx_request): bool
|
||||||
|
%{
|
||||||
|
//printf("locking_andx_request\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_locking_andx_response(header: SMB_Header, val: SMB1_locking_andx_response): bool
|
||||||
|
%{
|
||||||
|
//printf("locking_andx_response\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type LOCKING_ANDX_RANGE32 = record {
|
||||||
|
pid : uint16;
|
||||||
|
byte_offset : uint32;
|
||||||
|
byte_len : uint32;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LOCKING_ANDX_RANGE64 = record {
|
||||||
|
pid : uint16;
|
||||||
|
pad : uint16;
|
||||||
|
byte_offset : uint64;
|
||||||
|
byte_len : uint64;
|
||||||
|
};
|
||||||
|
|
||||||
|
# http://msdn.microsoft.com/en-us/library/ee442004.aspx
|
||||||
|
type SMB1_locking_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
file_id : uint16;
|
||||||
|
type_of_lock : uint8;
|
||||||
|
new_op_lock_level : uint8;
|
||||||
|
timeout : uint32;
|
||||||
|
num_requested_unlocks : uint16;
|
||||||
|
num_requested_locks : uint16;
|
||||||
|
|
||||||
|
bytecount : uint16;
|
||||||
|
unlocks : case $context.connection.get_offset_len() of {
|
||||||
|
32 -> unlocks32 : LOCKING_ANDX_RANGE32[num_requested_unlocks];
|
||||||
|
64 -> unlocks64 : LOCKING_ANDX_RANGE64[num_requested_unlocks];
|
||||||
|
};
|
||||||
|
locks : case $context.connection.get_offset_len() of {
|
||||||
|
32 -> locks32 : LOCKING_ANDX_RANGE32[num_requested_locks];
|
||||||
|
64 -> locks64 : LOCKING_ANDX_RANGE64[num_requested_locks];
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_locking_andx_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
# http://msdn.microsoft.com/en-us/library/ee441519.aspx
|
||||||
|
type SMB1_locking_andx_response(header: SMB_Header) = record {
|
||||||
|
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_locking_andx_response(header, this);
|
||||||
|
};
|
19
src/analyzer/protocol/smb/smb1-com-logoff-andx.pac
Normal file
19
src/analyzer/protocol/smb/smb1-com-logoff-andx.pac
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_logoff_andx(header: SMB_Header, val: SMB1_logoff_andx): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_logoff_andx )
|
||||||
|
BifEvent::generate_smb1_logoff_andx(bro_analyzer(), bro_analyzer()->Conn(), ${val.is_orig});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_logoff_andx(header: SMB_Header, is_orig: bool) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_logoff_andx(header, this);
|
||||||
|
};
|
250
src/analyzer/protocol/smb/smb1-com-negotiate.pac
Normal file
250
src/analyzer/protocol/smb/smb1-com-negotiate.pac
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
# This is an original Core Protocol command.
|
||||||
|
#
|
||||||
|
# This command is used to initiate an SMB connection between the
|
||||||
|
# client and the server. An SMB_COM_NEGOTIATE exchange MUST be
|
||||||
|
# completed before any other SMB messages are sent to the server.
|
||||||
|
#
|
||||||
|
# There MUST be only one SMB_COM_NEGOTIATE exchange per SMB
|
||||||
|
# connection. Subsequent SMB_COM_NEGOTIATE requests received by the
|
||||||
|
# server MUST be rejected with error responses. The server MUST NOT
|
||||||
|
# take any other action.
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_negotiate_request(header: SMB_Header, val: SMB1_negotiate_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_negotiate_request )
|
||||||
|
{
|
||||||
|
VectorVal* dialects = new VectorVal(string_vec);
|
||||||
|
for ( unsigned int i = 0; i < ${val.dialects}->size(); ++i )
|
||||||
|
{
|
||||||
|
StringVal* dia = smb_string2stringval((*${val.dialects})[i]->name());
|
||||||
|
dialects->Assign(i, dia);
|
||||||
|
}
|
||||||
|
BifEvent::generate_smb1_negotiate_request(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
dialects);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_negotiate_response(header: SMB_Header, val: SMB1_negotiate_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_negotiate_response )
|
||||||
|
{
|
||||||
|
RecordVal* response = new RecordVal(BifType::Record::SMB1::NegotiateResponse);
|
||||||
|
|
||||||
|
RecordVal* core;
|
||||||
|
RecordVal* lanman;
|
||||||
|
RecordVal* ntlm;
|
||||||
|
|
||||||
|
RecordVal* security;
|
||||||
|
RecordVal* raw;
|
||||||
|
RecordVal* capabilities;
|
||||||
|
switch ( ${val.word_count} )
|
||||||
|
{
|
||||||
|
case 0x01:
|
||||||
|
core = new RecordVal(BifType::Record::SMB1::NegotiateResponseCore);
|
||||||
|
core->Assign(0, new Val(${val.dialect_index}, TYPE_COUNT));
|
||||||
|
|
||||||
|
response->Assign(0, core);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0d:
|
||||||
|
security = new RecordVal(BifType::Record::SMB1::NegotiateResponseSecurity);
|
||||||
|
security->Assign(0, new Val(${val.lanman.security_user_level}, TYPE_BOOL));
|
||||||
|
security->Assign(1, new Val(${val.lanman.security_challenge_response}, TYPE_BOOL));
|
||||||
|
|
||||||
|
raw = new RecordVal(BifType::Record::SMB1::NegotiateRawMode);
|
||||||
|
raw->Assign(0, new Val(${val.lanman.raw_read_supported}, TYPE_BOOL));
|
||||||
|
raw->Assign(1, new Val(${val.lanman.raw_write_supported}, TYPE_BOOL));
|
||||||
|
|
||||||
|
lanman = new RecordVal(BifType::Record::SMB1::NegotiateResponseLANMAN);
|
||||||
|
lanman->Assign(0, new Val(${val.word_count}, TYPE_COUNT));
|
||||||
|
lanman->Assign(1, new Val(${val.dialect_index}, TYPE_COUNT));
|
||||||
|
lanman->Assign(2, security);
|
||||||
|
lanman->Assign(3, new Val(${val.lanman.max_buffer_size}, TYPE_COUNT));
|
||||||
|
lanman->Assign(4, new Val(${val.lanman.max_mpx_count}, TYPE_COUNT));
|
||||||
|
|
||||||
|
lanman->Assign(5, new Val(${val.lanman.max_number_vcs}, TYPE_COUNT));
|
||||||
|
lanman->Assign(6, raw);
|
||||||
|
lanman->Assign(7, new Val(${val.lanman.session_key}, TYPE_COUNT));
|
||||||
|
lanman->Assign(8, time_from_lanman(${val.lanman.server_time}, ${val.lanman.server_date}, ${val.lanman.server_tz}));
|
||||||
|
lanman->Assign(9, bytestring_to_val(${val.lanman.encryption_key}));
|
||||||
|
|
||||||
|
lanman->Assign(10, smb_string2stringval(${val.lanman.primary_domain}));
|
||||||
|
|
||||||
|
response->Assign(1, lanman);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x11:
|
||||||
|
security = new RecordVal(BifType::Record::SMB1::NegotiateResponseSecurity);
|
||||||
|
security->Assign(0, new Val(${val.ntlm.security_user_level}, TYPE_BOOL));
|
||||||
|
security->Assign(1, new Val(${val.ntlm.security_challenge_response}, TYPE_BOOL));
|
||||||
|
security->Assign(2, new Val(${val.ntlm.security_signatures_enabled}, TYPE_BOOL));
|
||||||
|
security->Assign(3, new Val(${val.ntlm.security_signatures_required}, TYPE_BOOL));
|
||||||
|
|
||||||
|
capabilities = new RecordVal(BifType::Record::SMB1::NegotiateCapabilities);
|
||||||
|
capabilities->Assign(0, new Val(${val.ntlm.capabilities_raw_mode}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(1, new Val(${val.ntlm.capabilities_mpx_mode}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(2, new Val(${val.ntlm.capabilities_unicode}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(3, new Val(${val.ntlm.capabilities_large_files}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(4, new Val(${val.ntlm.capabilities_nt_smbs}, TYPE_BOOL));
|
||||||
|
|
||||||
|
capabilities->Assign(5, new Val(${val.ntlm.capabilities_rpc_remote_apis}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(6, new Val(${val.ntlm.capabilities_status32}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(7, new Val(${val.ntlm.capabilities_level_2_oplocks}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(8, new Val(${val.ntlm.capabilities_lock_and_read}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(9, new Val(${val.ntlm.capabilities_nt_find}, TYPE_BOOL));
|
||||||
|
|
||||||
|
capabilities->Assign(10, new Val(${val.ntlm.capabilities_dfs}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(11, new Val(${val.ntlm.capabilities_infolevel_passthru}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(12, new Val(${val.ntlm.capabilities_large_readx}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(13, new Val(${val.ntlm.capabilities_large_writex}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(14, new Val(${val.ntlm.capabilities_unix}, TYPE_BOOL));
|
||||||
|
|
||||||
|
capabilities->Assign(15, new Val(${val.ntlm.capabilities_bulk_transfer}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(16, new Val(${val.ntlm.capabilities_compressed_data}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(17, new Val(${val.ntlm.capabilities_extended_security}, TYPE_BOOL));
|
||||||
|
|
||||||
|
ntlm = new RecordVal(BifType::Record::SMB1::NegotiateResponseNTLM);
|
||||||
|
ntlm->Assign(0, new Val(${val.word_count}, TYPE_COUNT));
|
||||||
|
ntlm->Assign(1, new Val(${val.dialect_index}, TYPE_COUNT));
|
||||||
|
ntlm->Assign(2, security);
|
||||||
|
ntlm->Assign(3, new Val(${val.ntlm.max_buffer_size}, TYPE_COUNT));
|
||||||
|
ntlm->Assign(4, new Val(${val.ntlm.max_mpx_count}, TYPE_COUNT));
|
||||||
|
|
||||||
|
ntlm->Assign(5, new Val(${val.ntlm.max_number_vcs}, TYPE_COUNT));
|
||||||
|
ntlm->Assign(6, new Val(${val.ntlm.max_raw_size}, TYPE_COUNT));
|
||||||
|
ntlm->Assign(7, new Val(${val.ntlm.session_key}, TYPE_COUNT));
|
||||||
|
ntlm->Assign(8, capabilities);
|
||||||
|
ntlm->Assign(9, filetime2brotime(${val.ntlm.server_time}));
|
||||||
|
|
||||||
|
if ( ${val.ntlm.capabilities_extended_security} == false )
|
||||||
|
{
|
||||||
|
ntlm->Assign(10, bytestring_to_val(${val.ntlm.encryption_key}));
|
||||||
|
ntlm->Assign(11, smb_string2stringval(${val.ntlm.domain_name}));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ntlm->Assign(12, bytestring_to_val(${val.ntlm.server_guid}));
|
||||||
|
}
|
||||||
|
|
||||||
|
response->Assign(2, ntlm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BifEvent::generate_smb1_negotiate_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_dialect = record {
|
||||||
|
buffer_format : uint8; # must be 0x2 for dialect
|
||||||
|
name : SMB_string(0,0);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_negotiate_request(header: SMB_Header) = record {
|
||||||
|
word_count: uint8; # must be 0
|
||||||
|
byte_count: uint16;
|
||||||
|
dialects: SMB_dialect[] &length=byte_count;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_negotiate_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_negotiate_response(header: SMB_Header) = record {
|
||||||
|
word_count: uint8;
|
||||||
|
dialect_index: uint16;
|
||||||
|
response: case word_count of {
|
||||||
|
0x01 -> core : SMB1_negotiate_core_response;
|
||||||
|
0x0d -> lanman : SMB1_negotiate_lanman_response(header);
|
||||||
|
0x11 -> ntlm : SMB1_negotiate_ntlm_response(header);
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
proc: bool = $context.connection.proc_smb1_negotiate_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_negotiate_core_response = record {
|
||||||
|
byte_count: uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_negotiate_lanman_response(header: SMB_Header) = record {
|
||||||
|
security_flags : uint16; # expanded in &let
|
||||||
|
max_buffer_size : uint16;
|
||||||
|
max_mpx_count : uint16;
|
||||||
|
max_number_vcs : uint16;
|
||||||
|
raw_mode : uint16; # expanded in &let
|
||||||
|
session_key : uint32;
|
||||||
|
server_time : SMB_time;
|
||||||
|
server_date : SMB_date;
|
||||||
|
server_tz : uint16;
|
||||||
|
encryption_key_length : uint16;
|
||||||
|
reserved : uint16; # must be zero
|
||||||
|
byte_count : uint16; # count of data bytes
|
||||||
|
encryption_key : bytestring &length=encryption_key_length;
|
||||||
|
primary_domain : SMB_string(header.unicode, offsetof(primary_domain));
|
||||||
|
} &let {
|
||||||
|
security_user_level : bool = ( security_flags & 0x1 ) > 0;
|
||||||
|
security_challenge_response : bool = ( security_flags & 0x2 ) > 0;
|
||||||
|
raw_read_supported : bool = ( raw_mode & 0x1 ) > 0;
|
||||||
|
raw_write_supported : bool = ( raw_mode & 0x2 ) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_negotiate_ntlm_response(header: SMB_Header) = record {
|
||||||
|
security_flags : uint8; # Expanded in &let
|
||||||
|
max_mpx_count : uint16;
|
||||||
|
max_number_vcs : uint16;
|
||||||
|
max_buffer_size : uint32;
|
||||||
|
max_raw_size : uint32;
|
||||||
|
session_key : uint32;
|
||||||
|
capabilities : uint32; # Expanded in &let
|
||||||
|
server_time : uint64;
|
||||||
|
server_tz : uint16;
|
||||||
|
encryption_key_length : uint8;
|
||||||
|
byte_count : uint16;
|
||||||
|
encryption_key_present: case capabilities_extended_security of {
|
||||||
|
false -> encryption_key : bytestring &length=encryption_key_length;
|
||||||
|
true -> no_key : empty;
|
||||||
|
} &requires(capabilities_extended_security);
|
||||||
|
domain_name_present: case capabilities_extended_security of {
|
||||||
|
false -> domain_name : SMB_string(header.unicode, offsetof(domain_name_present));
|
||||||
|
true -> no_name : empty;
|
||||||
|
} &requires(capabilities_extended_security);
|
||||||
|
server_guid_present: case capabilities_extended_security of {
|
||||||
|
true -> server_guid : bytestring &length=16;
|
||||||
|
false -> no_guid : empty;
|
||||||
|
} &requires(capabilities_extended_security);
|
||||||
|
security_blob_present: case capabilities_extended_security of {
|
||||||
|
true -> security_blob : bytestring &length=(byte_count-16);
|
||||||
|
false -> no_blob : empty;
|
||||||
|
} &requires(capabilities_extended_security);
|
||||||
|
} &let {
|
||||||
|
security_user_level : bool = (security_flags & 0x1) > 0;
|
||||||
|
security_challenge_response : bool = (security_flags & 0x2) > 0;
|
||||||
|
security_signatures_enabled : bool = (security_flags & 0x4) > 0;
|
||||||
|
security_signatures_required : bool = (security_flags & 0x8) > 0;
|
||||||
|
capabilities_raw_mode : bool = (capabilities & 0x1) > 0;
|
||||||
|
capabilities_mpx_mode : bool = (capabilities & 0x2) > 0;
|
||||||
|
capabilities_unicode : bool = (capabilities & 0x4) > 0;
|
||||||
|
capabilities_large_files : bool = (capabilities & 0x8) > 0;
|
||||||
|
capabilities_nt_smbs : bool = (capabilities & 0x10) > 0;
|
||||||
|
capabilities_rpc_remote_apis : bool = (capabilities & 0x20) > 0;
|
||||||
|
capabilities_status32 : bool = (capabilities & 0x40) > 0;
|
||||||
|
capabilities_level_2_oplocks : bool = (capabilities & 0x80) > 0;
|
||||||
|
capabilities_lock_and_read : bool = (capabilities & 0x100) > 0;
|
||||||
|
capabilities_nt_find : bool = (capabilities & 0x200) > 0;
|
||||||
|
capabilities_dfs : bool = (capabilities & 0x1000) > 0;
|
||||||
|
capabilities_infolevel_passthru : bool = (capabilities & 0x2000) > 0;
|
||||||
|
capabilities_large_readx : bool = (capabilities & 0x4000) > 0;
|
||||||
|
capabilities_large_writex : bool = (capabilities & 0x8000) > 0;
|
||||||
|
capabilities_unix : bool = (capabilities & 0x00800000) > 0;
|
||||||
|
capabilities_reserved : bool = (capabilities & 0x02000000) > 0;
|
||||||
|
capabilities_bulk_transfer : bool = (capabilities & 0x20000000) > 0;
|
||||||
|
capabilities_compressed_data : bool = (capabilities & 0x40000000) > 0;
|
||||||
|
capabilities_extended_security : bool = (capabilities & 0x80000000) > 0;
|
||||||
|
|
||||||
|
gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, false) &if(capabilities_extended_security);
|
||||||
|
};
|
||||||
|
|
18
src/analyzer/protocol/smb/smb1-com-nt-cancel.pac
Normal file
18
src/analyzer/protocol/smb/smb1-com-nt-cancel.pac
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_nt_cancel_request(header: SMB_Header, val: SMB1_nt_cancel_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_nt_cancel_request )
|
||||||
|
BifEvent::generate_smb1_nt_cancel_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_nt_cancel_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_nt_cancel_request(header, this);
|
||||||
|
};
|
88
src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac
Normal file
88
src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
function proc_smb1_nt_create_andx_request(header: SMB_Header, val: SMB1_nt_create_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_nt_create_andx_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_nt_create_andx_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.filename}));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_nt_create_andx_response(header: SMB_Header, val: SMB1_nt_create_andx_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_nt_create_andx_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_nt_create_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
${val.file_id},
|
||||||
|
${val.end_of_file},
|
||||||
|
SMB_BuildMACTimes(${val.last_write_time},
|
||||||
|
${val.last_access_time},
|
||||||
|
${val.create_time},
|
||||||
|
${val.last_change_time}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ${val.end_of_file} > 0 )
|
||||||
|
{
|
||||||
|
//file_mgr->SetSize(${val.end_of_file},
|
||||||
|
// bro_analyzer()->GetAnalyzerTag(),
|
||||||
|
// bro_analyzer()->Conn(),
|
||||||
|
// header->is_orig());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
type SMB1_nt_create_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
reserved : uint8;
|
||||||
|
|
||||||
|
name_length : uint16;
|
||||||
|
flags : uint32;
|
||||||
|
root_dir_file_id : uint32;
|
||||||
|
desired_access : uint32;
|
||||||
|
alloc_size : uint64;
|
||||||
|
ext_file_attrs : uint32;
|
||||||
|
share_access : uint32;
|
||||||
|
create_disposition : uint32;
|
||||||
|
create_options : uint32;
|
||||||
|
impersonation_level : uint32;
|
||||||
|
security_flags : uint8;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
filename : SMB_string(header.unicode, offsetof(filename));
|
||||||
|
|
||||||
|
andx_command : SMB_andx_command(header, 1, andx.command);
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_nt_create_andx_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_nt_create_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
oplock_level : uint8;
|
||||||
|
file_id : uint16;
|
||||||
|
create_disposition : uint32;
|
||||||
|
create_time : SMB_timestamp;
|
||||||
|
last_access_time : SMB_timestamp;
|
||||||
|
last_write_time : SMB_timestamp;
|
||||||
|
last_change_time : SMB_timestamp;
|
||||||
|
ext_file_attrs : uint32;
|
||||||
|
allocation_size : uint64;
|
||||||
|
end_of_file : uint64;
|
||||||
|
resource_type : uint16;
|
||||||
|
nm_pipe_status : uint16;
|
||||||
|
directory : uint8;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_nt_create_andx_response(header, this);
|
||||||
|
};
|
29
src/analyzer/protocol/smb/smb1-com-nt-transact.pac
Normal file
29
src/analyzer/protocol/smb/smb1-com-nt-transact.pac
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_nt_transact_request(header: SMB_Header, val: SMB1_nt_transact_request): bool
|
||||||
|
%{
|
||||||
|
//printf("nt_transact_request\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_nt_transact_response(header: SMB_Header, val: SMB1_nt_transact_response): bool
|
||||||
|
%{
|
||||||
|
//printf("nt_transact_response\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
# http://msdn.microsoft.com/en-us/library/ee441534.aspx
|
||||||
|
type SMB1_nt_transact_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_nt_transact_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
# http://msdn.microsoft.com/en-us/library/ee442112.aspx
|
||||||
|
type SMB1_nt_transact_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_nt_transact_response(header, this);
|
||||||
|
};
|
77
src/analyzer/protocol/smb/smb1-com-open-andx.pac
Normal file
77
src/analyzer/protocol/smb/smb1-com-open-andx.pac
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_open_andx_request(h: SMB_Header, val: SMB1_open_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_open_andx_request )
|
||||||
|
BifEvent::generate_smb1_open_andx_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.flags},
|
||||||
|
${val.access_mode},
|
||||||
|
${val.search_attrs},
|
||||||
|
${val.file_attrs},
|
||||||
|
${val.creation_time},
|
||||||
|
${val.open_mode},
|
||||||
|
${val.allocation_size},
|
||||||
|
${val.timeout},
|
||||||
|
smb_string2stringval(${val.filename}));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_open_andx_response(h: SMB_Header, val: SMB1_open_andx_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_open_andx_response )
|
||||||
|
BifEvent::generate_smb1_open_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.fid},
|
||||||
|
${val.file_attrs},
|
||||||
|
${val.last_write_time},
|
||||||
|
${val.file_data_size},
|
||||||
|
${val.access_rights},
|
||||||
|
${val.resource_type},
|
||||||
|
${val.nm_pipe_status},
|
||||||
|
${val.open_results});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type SMB1_open_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
flags : uint16;
|
||||||
|
access_mode : uint16;
|
||||||
|
search_attrs : uint16;
|
||||||
|
file_attrs : uint16;
|
||||||
|
creation_time : uint32;
|
||||||
|
open_mode : uint16;
|
||||||
|
allocation_size : uint32;
|
||||||
|
timeout : uint32;
|
||||||
|
reserved : padding[2];
|
||||||
|
byte_count : uint16;
|
||||||
|
filename : SMB_string(header.unicode, offsetof(filename);
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_open_andx_request(header, this);
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type SMB1_open_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
fid : uint16;
|
||||||
|
file_attrs : uint16;
|
||||||
|
last_write_time : uint32;
|
||||||
|
file_data_size : uint32;
|
||||||
|
access_rights : uint16;
|
||||||
|
resource_type : uint16;
|
||||||
|
nm_pipe_status : uint16;
|
||||||
|
open_results : uint16;
|
||||||
|
reserved : padding[3];
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_open_andx_response(header, this);
|
||||||
|
} &byteorder=littleendian;
|
77
src/analyzer/protocol/smb/smb1-com-open-andx.pcap
Normal file
77
src/analyzer/protocol/smb/smb1-com-open-andx.pcap
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_open_andx_request(h: SMB_Header, val: SMB1_open_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_open_andx_request )
|
||||||
|
BifEvent::generate_smb1_open_andx_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.flags},
|
||||||
|
${val.access_mode},
|
||||||
|
${val.search_attrs},
|
||||||
|
${val.file_attrs},
|
||||||
|
${val.creation_time},
|
||||||
|
${val.open_mode},
|
||||||
|
${val.allocation_size},
|
||||||
|
${val.timeout},
|
||||||
|
smb_string2stringval(${val.filename}));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_open_andx_response(h: SMB_Header, val: SMB1_open_andx_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_open_andx_response )
|
||||||
|
BifEvent::generate_smb1_open_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.fid},
|
||||||
|
${val.file_attrs},
|
||||||
|
${val.last_write_time},
|
||||||
|
${val.file_data_size},
|
||||||
|
${val.access_rights},
|
||||||
|
${val.resource_type},
|
||||||
|
${val.nm_pipe_status},
|
||||||
|
${val.open_results});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type SMB1_open_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
flags : uint16;
|
||||||
|
access_mode : uint16;
|
||||||
|
search_attrs : uint16;
|
||||||
|
file_attrs : uint16;
|
||||||
|
creation_time : uint32;
|
||||||
|
open_mode : uint16;
|
||||||
|
allocation_size : uint32;
|
||||||
|
timeout : uint32;
|
||||||
|
reserved : padding[2];
|
||||||
|
byte_count : uint16;
|
||||||
|
filename : SMB_string(header.unicode, offsetof(filename);
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_open_andx_request(header, this);
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type SMB1_open_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
fid : uint16;
|
||||||
|
file_attrs : uint16;
|
||||||
|
last_write_time : uint32;
|
||||||
|
file_data_size : uint32;
|
||||||
|
access_rights : uint16;
|
||||||
|
resource_type : uint16;
|
||||||
|
nm_pipe_status : uint16;
|
||||||
|
open_results : uint16;
|
||||||
|
reserved : padding[3];
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_open_andx_response(header, this);
|
||||||
|
} &byteorder=littleendian;
|
41
src/analyzer/protocol/smb/smb1-com-query-information.pac
Normal file
41
src/analyzer/protocol/smb/smb1-com-query-information.pac
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_query_information_request(header: SMB_Header, val: SMB1_query_information_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_query_information_request )
|
||||||
|
BifEvent::generate_smb1_query_information_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.filename}));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_query_information_response(header: SMB_Header, val: SMB1_query_information_response): bool
|
||||||
|
%{
|
||||||
|
//printf("query_information_response\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_query_information_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
buffer_format : uint8;
|
||||||
|
filename : SMB_string(header.unicode, offsetof(filename));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_query_information_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_query_information_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
file_attribs : uint16;
|
||||||
|
last_write_time : SMB_time;
|
||||||
|
file_size : uint32;
|
||||||
|
reserved : uint16[5];
|
||||||
|
byte_count : uint16 &check($element == 0);
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_query_information_response(header, this);
|
||||||
|
};
|
||||||
|
|
91
src/analyzer/protocol/smb/smb1-com-read-andx.pac
Normal file
91
src/analyzer/protocol/smb/smb1-com-read-andx.pac
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
%member{
|
||||||
|
// Track read offsets to provide correct
|
||||||
|
// offsets for file manager.
|
||||||
|
std::map<uint16,uint64> read_offsets;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_read_andx_request(h: SMB_Header, val: SMB1_read_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_read_andx_request )
|
||||||
|
BifEvent::generate_smb1_read_andx_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.file_id},
|
||||||
|
${val.offset},
|
||||||
|
${val.max_count});
|
||||||
|
|
||||||
|
read_offsets[${h.mid}] = ${val.offset};
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_read_andx_response(h: SMB_Header, val: SMB1_read_andx_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_read_andx_response )
|
||||||
|
BifEvent::generate_smb1_read_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.data_len});
|
||||||
|
|
||||||
|
if ( ! ${val.is_pipe} && ${val.data_len} > 0 )
|
||||||
|
{
|
||||||
|
uint64 offset = read_offsets[${h.mid}];
|
||||||
|
read_offsets.erase(${h.mid});
|
||||||
|
|
||||||
|
file_mgr->DataIn(${val.data}.begin(), ${val.data_len}, offset,
|
||||||
|
bro_analyzer()->GetAnalyzerTag(),
|
||||||
|
bro_analyzer()->Conn(), h->is_orig());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type SMB1_read_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
file_id : uint16;
|
||||||
|
offset_low : uint32;
|
||||||
|
max_count_low : uint16;
|
||||||
|
min_count : uint16;
|
||||||
|
max_count_high : uint32;
|
||||||
|
remaining : uint16;
|
||||||
|
offset_high_u : case word_count of {
|
||||||
|
0x0C -> offset_high_tmp : uint32;
|
||||||
|
default -> null : empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
offset_high : uint32 = (word_count == 0x0C) ? offset_high_tmp : 0;
|
||||||
|
offset : uint64 = (offset_high * 0x10000) + offset_low;
|
||||||
|
max_count : uint64 = (max_count_high * 0x10000) + max_count_low;
|
||||||
|
proc : bool = $context.connection.proc_smb1_read_andx_request(header, this);
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type SMB1_read_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
available : uint16;
|
||||||
|
data_compact_mode : uint16;
|
||||||
|
reserved1 : uint16;
|
||||||
|
data_len_low : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
data_len_high : uint16;
|
||||||
|
reserved2 : uint64;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
pad : padding to data_offset - SMB_Header_length;
|
||||||
|
data : bytestring &length=data_len;
|
||||||
|
} &let {
|
||||||
|
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid);
|
||||||
|
pipe_proc : bool = $context.connection.forward_dce_rpc(data, 0, false) &if(is_pipe);
|
||||||
|
|
||||||
|
padding_len : uint8 = (header.unicode == 1) ? 1 : 0;
|
||||||
|
data_len : uint32 = (data_len_high << 16) + data_len_low;
|
||||||
|
proc : bool = $context.connection.proc_smb1_read_andx_response(header, this);
|
||||||
|
} &byteorder=littleendian;
|
234
src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac
Normal file
234
src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
## This SMB is used to further "Set up" the session normally just
|
||||||
|
## established via the negotiate protocol.
|
||||||
|
##
|
||||||
|
## One primary function is to perform a "user logon" in the case
|
||||||
|
## where the server is in user level security mode. The UID in the
|
||||||
|
## SMB header is set by the client to by the userid desired for the
|
||||||
|
## AccountName and validated by the AccountPassword.
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_session_setup_andx_request(header: SMB_Header, val: SMB1_session_setup_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_session_setup_andx_request )
|
||||||
|
{
|
||||||
|
RecordVal* request = new RecordVal(BifType::Record::SMB1::SessionSetupAndXRequest);
|
||||||
|
RecordVal* capabilities;
|
||||||
|
|
||||||
|
request->Assign(0, new Val(${val.word_count}, TYPE_COUNT));
|
||||||
|
switch ( ${val.word_count} ) {
|
||||||
|
case 10: // pre NT LM 0.12
|
||||||
|
request->Assign(1, new Val(${val.lanman.max_buffer_size}, TYPE_COUNT));
|
||||||
|
request->Assign(2, new Val(${val.lanman.max_mpx_count}, TYPE_COUNT));
|
||||||
|
request->Assign(3, new Val(${val.lanman.vc_number}, TYPE_COUNT));
|
||||||
|
request->Assign(4, new Val(${val.lanman.session_key}, TYPE_COUNT));
|
||||||
|
|
||||||
|
request->Assign(5, smb_string2stringval(${val.lanman.native_os}));
|
||||||
|
request->Assign(6, smb_string2stringval(${val.lanman.native_lanman}));
|
||||||
|
request->Assign(7, smb_string2stringval(${val.lanman.account_name}));
|
||||||
|
request->Assign(8, bytestring_to_val(${val.lanman.account_password}));
|
||||||
|
request->Assign(9, smb_string2stringval(${val.lanman.primary_domain}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 12: // NT LM 0.12 with extended security
|
||||||
|
capabilities = new RecordVal(BifType::Record::SMB1::SessionSetupAndXCapabilities);
|
||||||
|
capabilities->Assign(0, new Val(${val.ntlm_extended_security.capabilities.unicode}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(1, new Val(${val.ntlm_extended_security.capabilities.large_files}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(2, new Val(${val.ntlm_extended_security.capabilities.nt_smbs}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(3, new Val(${val.ntlm_extended_security.capabilities.status32}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(4, new Val(${val.ntlm_extended_security.capabilities.level_2_oplocks}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(5, new Val(${val.ntlm_extended_security.capabilities.nt_find}, TYPE_BOOL));
|
||||||
|
|
||||||
|
request->Assign(1, new Val(${val.ntlm_extended_security.max_buffer_size}, TYPE_COUNT));
|
||||||
|
request->Assign(2, new Val(${val.ntlm_extended_security.max_mpx_count}, TYPE_COUNT));
|
||||||
|
request->Assign(3, new Val(${val.ntlm_extended_security.vc_number}, TYPE_COUNT));
|
||||||
|
request->Assign(4, new Val(${val.ntlm_extended_security.session_key}, TYPE_COUNT));
|
||||||
|
|
||||||
|
request->Assign(5, smb_string2stringval(${val.ntlm_extended_security.native_os}));
|
||||||
|
request->Assign(6, smb_string2stringval(${val.ntlm_extended_security.native_lanman}));
|
||||||
|
|
||||||
|
request->Assign(13, capabilities);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13: // NT LM 0.12 without extended security
|
||||||
|
capabilities = new RecordVal(BifType::Record::SMB1::SessionSetupAndXCapabilities);
|
||||||
|
capabilities->Assign(0, new Val(${val.ntlm_nonextended_security.capabilities.unicode}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(1, new Val(${val.ntlm_nonextended_security.capabilities.large_files}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(2, new Val(${val.ntlm_nonextended_security.capabilities.nt_smbs}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(3, new Val(${val.ntlm_nonextended_security.capabilities.status32}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(4, new Val(${val.ntlm_nonextended_security.capabilities.level_2_oplocks}, TYPE_BOOL));
|
||||||
|
capabilities->Assign(5, new Val(${val.ntlm_nonextended_security.capabilities.nt_find}, TYPE_BOOL));
|
||||||
|
|
||||||
|
request->Assign(1, new Val(${val.ntlm_nonextended_security.max_buffer_size}, TYPE_COUNT));
|
||||||
|
request->Assign(2, new Val(${val.ntlm_nonextended_security.max_mpx_count}, TYPE_COUNT));
|
||||||
|
request->Assign(3, new Val(${val.ntlm_nonextended_security.vc_number}, TYPE_COUNT));
|
||||||
|
request->Assign(4, new Val(${val.ntlm_nonextended_security.session_key}, TYPE_COUNT));
|
||||||
|
|
||||||
|
request->Assign(5, smb_string2stringval(${val.ntlm_nonextended_security.native_os}));
|
||||||
|
request->Assign(6, smb_string2stringval(${val.ntlm_nonextended_security.native_lanman}));
|
||||||
|
request->Assign(7, smb_string2stringval(${val.ntlm_nonextended_security.account_name}));
|
||||||
|
request->Assign(9, smb_string2stringval(${val.ntlm_nonextended_security.primary_domain}));
|
||||||
|
|
||||||
|
request->Assign(10, bytestring_to_val(${val.ntlm_nonextended_security.case_insensitive_password}));
|
||||||
|
request->Assign(11, bytestring_to_val(${val.ntlm_nonextended_security.case_sensitive_password}));
|
||||||
|
request->Assign(13, capabilities);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BifEvent::generate_smb1_session_setup_andx_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), request);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_session_setup_andx_response(header: SMB_Header, val: SMB1_session_setup_andx_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_session_setup_andx_response )
|
||||||
|
{
|
||||||
|
RecordVal* response = new RecordVal(BifType::Record::SMB1::SessionSetupAndXResponse);
|
||||||
|
|
||||||
|
response->Assign(0, new Val(${val.word_count}, TYPE_COUNT));
|
||||||
|
switch ( ${val.word_count} )
|
||||||
|
{
|
||||||
|
case 3: // pre NT LM 0.12
|
||||||
|
response->Assign(1, new Val(${val.lanman.is_guest}, TYPE_BOOL));
|
||||||
|
response->Assign(2, smb_string2stringval(${val.lanman.native_os}));
|
||||||
|
response->Assign(3, smb_string2stringval(${val.lanman.native_lanman}));
|
||||||
|
response->Assign(4, smb_string2stringval(${val.lanman.primary_domain}));
|
||||||
|
break;
|
||||||
|
case 4: // NT LM 0.12
|
||||||
|
response->Assign(1, new Val(${val.ntlm.is_guest}, TYPE_BOOL));
|
||||||
|
response->Assign(2, smb_string2stringval(${val.ntlm.native_os}));
|
||||||
|
response->Assign(3, smb_string2stringval(${val.ntlm.native_lanman}));
|
||||||
|
response->Assign(4, smb_string2stringval(${val.ntlm.primary_domain}));
|
||||||
|
//response->Assign(5, bytestring_to_val(${val.ntlm.security_blob}));
|
||||||
|
break;
|
||||||
|
default: // Error!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BifEvent::generate_smb1_session_setup_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
lanman_or_ntlm : case word_count of {
|
||||||
|
0x0a -> lanman : SMB1_session_setup_andx_request_lanman(header);
|
||||||
|
0x0c -> ntlm_extended_security : SMB1_session_setup_andx_request_ntlm_extended_security(header);
|
||||||
|
0x0d -> ntlm_nonextended_security : SMB1_session_setup_andx_request_ntlm_nonextended_security(header);
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
proc: bool = $context.connection.proc_smb1_session_setup_andx_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
lanman_or_ntlm : case word_count of {
|
||||||
|
0x03 -> lanman: SMB1_session_setup_andx_response_lanman(header);
|
||||||
|
0x04 -> ntlm: SMB1_session_setup_andx_response_ntlm(header);
|
||||||
|
default -> error: uint16;
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
proc: bool = $context.connection.proc_smb1_session_setup_andx_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_request_lanman(header: SMB_Header) = record {
|
||||||
|
andx : SMB_andx;
|
||||||
|
max_buffer_size : uint16;
|
||||||
|
max_mpx_count : uint16;
|
||||||
|
vc_number : uint16;
|
||||||
|
session_key : uint32;
|
||||||
|
password_length : uint16;
|
||||||
|
reserved : uint32;
|
||||||
|
byte_count : uint16;
|
||||||
|
account_password : bytestring &length=password_length;
|
||||||
|
# offset + 1 due to word_count in the parent type
|
||||||
|
account_name : SMB_string(header.unicode, offsetof(account_name) + 1);
|
||||||
|
primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1);
|
||||||
|
native_os : SMB_string(header.unicode, offsetof(native_os) + 1);
|
||||||
|
native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_response_lanman(header: SMB_Header) = record {
|
||||||
|
andx : SMB_andx;
|
||||||
|
action : uint16;
|
||||||
|
byte_count : uint16;
|
||||||
|
# offset + 1 due to word_count in the parent type
|
||||||
|
native_os : SMB_string(header.unicode, offsetof(native_os) + 1);
|
||||||
|
native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1);
|
||||||
|
primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1);
|
||||||
|
} &let {
|
||||||
|
is_guest: bool = ( action & 0x1 ) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_request_ntlm_capabilities = record {
|
||||||
|
capabilities: uint32;
|
||||||
|
} &let {
|
||||||
|
unicode : bool = ( capabilities & 0x0004 ) > 0;
|
||||||
|
large_files : bool = ( capabilities & 0x0008 ) > 0;
|
||||||
|
nt_smbs : bool = ( capabilities & 0x0010 ) > 0;
|
||||||
|
status32 : bool = ( capabilities & 0x0040 ) > 0;
|
||||||
|
level_2_oplocks : bool = ( capabilities & 0x0080 ) > 0;
|
||||||
|
nt_find : bool = ( capabilities & 0x0200 ) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_request_ntlm_nonextended_security(header: SMB_Header) = record {
|
||||||
|
andx : SMB_andx;
|
||||||
|
max_buffer_size : uint16;
|
||||||
|
max_mpx_count : uint16;
|
||||||
|
vc_number : uint16;
|
||||||
|
session_key : uint32;
|
||||||
|
case_insensitive_password_length : uint16;
|
||||||
|
case_sensitive_password_length : uint16;
|
||||||
|
reserved : uint32;
|
||||||
|
capabilities : SMB1_session_setup_andx_request_ntlm_capabilities;
|
||||||
|
byte_count : uint16;
|
||||||
|
case_insensitive_password : bytestring &length=case_insensitive_password_length;
|
||||||
|
case_sensitive_password : bytestring &length=case_sensitive_password_length;
|
||||||
|
# offset + 1 due to word_count in the parent type
|
||||||
|
account_name : SMB_string(header.unicode, offsetof(account_name) + 1);
|
||||||
|
primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1);
|
||||||
|
native_os : SMB_string(header.unicode, offsetof(native_os) + 1);
|
||||||
|
native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_request_ntlm_extended_security(header: SMB_Header) = record {
|
||||||
|
andx : SMB_andx;
|
||||||
|
max_buffer_size : uint16;
|
||||||
|
max_mpx_count : uint16;
|
||||||
|
vc_number : uint16;
|
||||||
|
session_key : uint32;
|
||||||
|
security_blob_length : uint16;
|
||||||
|
reserved : uint32;
|
||||||
|
capabilities : SMB1_session_setup_andx_request_ntlm_capabilities;
|
||||||
|
byte_count : uint16;
|
||||||
|
security_blob : bytestring &length=security_blob_length;
|
||||||
|
# offset + 1 due to word_count in the parent type
|
||||||
|
native_os : SMB_string(header.unicode, offsetof(native_os) + 1);
|
||||||
|
native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1);
|
||||||
|
} &let {
|
||||||
|
pipe_proc : bool = $context.connection.forward_gssapi(security_blob, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_session_setup_andx_response_ntlm(header: SMB_Header) = record {
|
||||||
|
andx : SMB_andx;
|
||||||
|
action : uint16;
|
||||||
|
security_blob_length : uint16;
|
||||||
|
byte_count : uint16;
|
||||||
|
security_blob : bytestring &length=security_blob_length;
|
||||||
|
# offset + 1 due to word_count in the parent type
|
||||||
|
native_os : SMB_string(header.unicode, offsetof(native_os) + 1);
|
||||||
|
native_lanman : SMB_string(header.unicode, offsetof(native_lanman) + 1);
|
||||||
|
primary_domain : SMB_string(header.unicode, offsetof(primary_domain) + 1);
|
||||||
|
} &let {
|
||||||
|
is_guest : bool = ( action & 0x1 ) > 0;
|
||||||
|
gssapi_proc : bool = $context.connection.forward_gssapi(security_blob, false);
|
||||||
|
};
|
||||||
|
|
17
src/analyzer/protocol/smb/smb1-com-transaction-secondary.pac
Normal file
17
src/analyzer/protocol/smb/smb1-com-transaction-secondary.pac
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
type SMB1_transaction_secondary_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
total_param_count : uint16;
|
||||||
|
total_data_count : uint16;
|
||||||
|
param_count : uint16;
|
||||||
|
param_offset : uint16;
|
||||||
|
param_displacement : uint16;
|
||||||
|
data_count : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
data_displacement : uint16;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
pad1 : padding to param_offset - SMB_Header_length;
|
||||||
|
parameters : bytestring &length = param_count;
|
||||||
|
pad2 : padding to data_offset - SMB_Header_length;
|
||||||
|
data : SMB1_transaction_data(header, true, data_count, 0, SMB_UNKNOWN);
|
||||||
|
};
|
126
src/analyzer/protocol/smb/smb1-com-transaction.pac
Normal file
126
src/analyzer/protocol/smb/smb1-com-transaction.pac
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
enum Trans_subcommands {
|
||||||
|
NT_TRANSACT_QUERY_QUOTA = 0x0007,
|
||||||
|
NT_TRANSACT_SET_QUOTA = 0x0008,
|
||||||
|
NT_TRANSACT_CREATE2 = 0x0009,
|
||||||
|
};
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
%member{
|
||||||
|
map<uint16, bool> is_file_a_pipe;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function get_is_file_a_pipe(id: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( is_file_a_pipe.count(id) > 0 )
|
||||||
|
{
|
||||||
|
bool is_pipe = is_file_a_pipe.at(id);
|
||||||
|
is_file_a_pipe.erase(id);
|
||||||
|
|
||||||
|
return is_pipe;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function set_is_file_a_pipe(id: uint16, is_it: bool): bool
|
||||||
|
%{
|
||||||
|
is_file_a_pipe[id] = is_it;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_transaction_request(header: SMB_Header, val: SMB1_transaction_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_transaction_request )
|
||||||
|
BifEvent::generate_smb1_transaction_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.name}),
|
||||||
|
${val.sub_cmd});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_transaction_response(header: SMB_Header, val: SMB1_transaction_response): bool
|
||||||
|
%{
|
||||||
|
//printf("transaction_response\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
type SMB1_transaction_data(header: SMB_Header, is_orig: bool, count: uint16, sub_cmd: uint16,
|
||||||
|
trans_type: int) = case trans_type of {
|
||||||
|
# SMB_MAILSLOT_BROWSE -> mailslot : SMB_MailSlot_message(header.unicode, count);
|
||||||
|
# SMB_MAILSLOT_LANMAN -> lanman : SMB_MailSlot_message(header.unicode, count);
|
||||||
|
# SMB_RAP -> rap : SMB_Pipe_message(header.unicode, count);
|
||||||
|
SMB_PIPE -> pipe_data : bytestring &restofdata;
|
||||||
|
SMB_UNKNOWN -> unknown : bytestring &restofdata &transient;
|
||||||
|
default -> data : bytestring &restofdata &transient;
|
||||||
|
} &let {
|
||||||
|
pipe_proc : bool = $context.connection.forward_dce_rpc(pipe_data, 0, is_orig) &if(trans_type == SMB_PIPE);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_transaction_setup(header: SMB_Header) = record {
|
||||||
|
op_code : uint16;
|
||||||
|
file_id : uint16;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SMB1_transaction_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
total_param_count : uint16;
|
||||||
|
total_data_count : uint16;
|
||||||
|
max_param_count : uint16;
|
||||||
|
max_data_count : uint16;
|
||||||
|
max_setup_count : uint8;
|
||||||
|
reserved1 : uint8;
|
||||||
|
flags : uint16;
|
||||||
|
timeout : uint32;
|
||||||
|
reserved2 : uint16;
|
||||||
|
param_count : uint16;
|
||||||
|
param_offset : uint16;
|
||||||
|
data_count : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
setup_count : uint8;
|
||||||
|
reserved3 : uint8;
|
||||||
|
setup : SMB1_transaction_setup(header);
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
name : SMB_string(header.unicode, offsetof(name));
|
||||||
|
pad1 : padding to param_offset - SMB_Header_length;
|
||||||
|
parameters : bytestring &length = param_count;
|
||||||
|
pad2 : padding to data_offset - SMB_Header_length;
|
||||||
|
data : SMB1_transaction_data(header, true, data_count, sub_cmd, transtype);
|
||||||
|
} &let {
|
||||||
|
sub_cmd : uint16 = setup_count ? setup.op_code : 0;
|
||||||
|
transtype : int = determine_transaction_type(setup_count, name);
|
||||||
|
is_pipe : bool = (transtype == SMB_PIPE);
|
||||||
|
|
||||||
|
proc_set_pipe : bool = $context.connection.set_is_file_a_pipe(header.mid, is_pipe);
|
||||||
|
proc : bool = $context.connection.proc_smb1_transaction_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_transaction_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
total_param_count : uint16;
|
||||||
|
total_data_count : uint16;
|
||||||
|
reserved : uint16;
|
||||||
|
param_count : uint16;
|
||||||
|
param_offset : uint16;
|
||||||
|
param_displacement : uint16;
|
||||||
|
data_count : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
data_displacement : uint16;
|
||||||
|
setup_count : uint8;
|
||||||
|
reserved2 : uint8;
|
||||||
|
setup : uint16[setup_count];
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
pad0 : padding to param_offset - SMB_Header_length;
|
||||||
|
parameters : bytestring &length = param_count;
|
||||||
|
pad1 : padding to data_offset - SMB_Header_length;
|
||||||
|
data : SMB1_transaction_data(header, false, data_count, 0, is_pipe ? SMB_PIPE : SMB_UNKNOWN)[data_count>0 ? 1 : 0];
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_transaction_response(header, this);
|
||||||
|
is_pipe: bool = $context.connection.get_is_file_a_pipe(header.mid);
|
||||||
|
};
|
331
src/analyzer/protocol/smb/smb1-com-transaction2.pac
Normal file
331
src/analyzer/protocol/smb/smb1-com-transaction2.pac
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
enum Trans2_subcommands {
|
||||||
|
TRANS2_OPEN2 = 0x0000,
|
||||||
|
TRANS2_FIND_FIRST2 = 0x0001,
|
||||||
|
TRANS2_FIND_NEXT2 = 0x0002,
|
||||||
|
TRANS2_QUERY_FS_INFORMATION = 0x0003,
|
||||||
|
TRANS2_SET_FS_INFORMATION = 0x0004,
|
||||||
|
TRANS2_QUERY_PATH_INFORMATION = 0x0005,
|
||||||
|
TRANS2_SET_PATH_INFORMATION = 0x0006,
|
||||||
|
TRANS2_QUERY_FILE_INFORMATION = 0x0007,
|
||||||
|
TRANS2_SET_FILE_INFORMATION = 0x0008,
|
||||||
|
TRANS2_FSCTL = 0x0009,
|
||||||
|
TRANS2_IOCTL2 = 0x000a,
|
||||||
|
TRANS2_FIND_NOTIFY_FIRST = 0x000b,
|
||||||
|
TRANS2_FIND_NOTIFY_NEXT = 0x000c,
|
||||||
|
TRANS2_CREATE_DIRECTORY = 0x000d,
|
||||||
|
TRANS2_SESSION_SETUP = 0x000e,
|
||||||
|
TRANS2_GET_DFS_REFERRAL = 0x0010,
|
||||||
|
TRANS2_REPORT_DFS_INCONSISTENCY = 0x0011,
|
||||||
|
};
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_transaction2_request(header: SMB_Header, val: SMB1_transaction2_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_transaction2_request )
|
||||||
|
BifEvent::generate_smb1_transaction2_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), ${val.sub_cmd});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_transaction2_response(header: SMB_Header, val: SMB1_transaction2_response): bool
|
||||||
|
%{
|
||||||
|
//if ( smb1_transaction2_response )
|
||||||
|
// BifEvent::generate_smb1_transaction2_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), ${val.sub_cmd});
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_transaction2_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
total_param_count : uint16;
|
||||||
|
total_data_count : uint16;
|
||||||
|
max_param_count : uint16;
|
||||||
|
max_data_count : uint16;
|
||||||
|
max_setup_count : uint8;
|
||||||
|
reserved1 : uint8;
|
||||||
|
flags : uint16;
|
||||||
|
timeout : uint32;
|
||||||
|
reserved2 : uint16;
|
||||||
|
param_count : uint16;
|
||||||
|
param_offset : uint16;
|
||||||
|
data_count : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
setup_count : uint8;
|
||||||
|
reserved3 : uint8;
|
||||||
|
|
||||||
|
# I suspect this needs a word_count check
|
||||||
|
#setup : uint16[setup_count];
|
||||||
|
sub_cmd : uint16;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
#stuff : bytestring &length=byte_count;
|
||||||
|
pad1 : padding to (param_offset - SMB_Header_length);
|
||||||
|
parameters : case sub_cmd of {
|
||||||
|
TRANS2_FIND_FIRST2 -> find_first2 : trans2_find_first2_request(header);
|
||||||
|
TRANS2_QUERY_FS_INFORMATION -> query_fs_info : trans2_query_fs_info_request(header);
|
||||||
|
TRANS2_QUERY_PATH_INFORMATION -> query_path_info : trans2_query_path_info_request(header);
|
||||||
|
TRANS2_QUERY_FILE_INFORMATION -> query_file_info : trans2_query_file_info_request(header);
|
||||||
|
TRANS2_SET_FILE_INFORMATION -> set_file_info : trans2_set_file_info_request(header);
|
||||||
|
TRANS2_GET_DFS_REFERRAL -> get_dfs_referral : trans2_get_dfs_referral_request(header);
|
||||||
|
default -> blah : bytestring &restofdata &transient;
|
||||||
|
};
|
||||||
|
#pad2 : padding to (data_offset - SMB_Header_length);
|
||||||
|
#data : bytestring &length=data_count;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_transaction2_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_transaction2_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
total_param_count : uint16;
|
||||||
|
total_data_count : uint16;
|
||||||
|
reserved1 : uint16;
|
||||||
|
param_count : uint16;
|
||||||
|
param_offset : uint16;
|
||||||
|
param_displacement : uint16;
|
||||||
|
data_count : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
data_displacement : uint16;
|
||||||
|
setup_count : uint8;
|
||||||
|
reserved2 : uint8;
|
||||||
|
#setup : uint16[setup_count];
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
stuff : bytestring &length=byte_count;
|
||||||
|
|
||||||
|
#pad1 : padding to (param_offset - SMB_Header_length);
|
||||||
|
#parameters : bytestring &length = byte_count;
|
||||||
|
#pad2 : padding to (data_offset - SMB_Header_length);
|
||||||
|
#data : bytestring &length = data_count; # TODO: make SMB1_transaction2_data structure -- SMB1_transaction_data(header, data_count, 0, SMB_UNKNOWN);
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_transaction2_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_trans2_find_first2_request(header: SMB_Header, val: trans2_find_first2_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_trans2_find_first2_request )
|
||||||
|
{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::SMB1::Find_First2_Request_Args);
|
||||||
|
result->Assign(0, new Val(${val.search_attrs}, TYPE_COUNT));
|
||||||
|
result->Assign(1, new Val(${val.search_count}, TYPE_COUNT));
|
||||||
|
result->Assign(2, new Val(${val.flags}, TYPE_COUNT));
|
||||||
|
result->Assign(3, new Val(${val.info_level}, TYPE_COUNT));
|
||||||
|
result->Assign(4, new Val(${val.search_storage_type}, TYPE_COUNT));
|
||||||
|
result->Assign(5, smb_string2stringval(${val.file_name}));
|
||||||
|
BifEvent::generate_smb1_trans2_find_first2_request(bro_analyzer(), bro_analyzer()->Conn(), \
|
||||||
|
BuildHeaderVal(header), result);
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_trans2_find_first2_response(header: SMB_Header, val: trans2_find_first2_response): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_find_first2 response!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_find_first2_request(header: SMB_Header) = record {
|
||||||
|
search_attrs : uint16;
|
||||||
|
search_count : uint16;
|
||||||
|
flags : uint16;
|
||||||
|
info_level : uint16;
|
||||||
|
search_storage_type : uint32;
|
||||||
|
file_name : SMB_string(header.unicode, offsetof(file_name));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_find_first2_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_find_first2_response(header: SMB_Header) = record {
|
||||||
|
sid : uint16;
|
||||||
|
search_count : uint16;
|
||||||
|
end_of_search : uint16;
|
||||||
|
ea_error_offset : uint16;
|
||||||
|
last_name_offset : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_find_first2_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_trans2_query_fs_info_request(header: SMB_Header, val: trans2_query_fs_info_request): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_query_fs_info request!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_trans2_query_fs_info_response(header: SMB_Header, val: trans2_query_fs_info_response): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_query_fs_info response!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_query_fs_info_request(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_query_fs_info_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_query_fs_info_response(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_query_fs_info_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_trans2_query_path_info_request(header: SMB_Header, val: trans2_query_path_info_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_trans2_query_path_info_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_trans2_query_path_info_request(bro_analyzer(), bro_analyzer()->Conn(), \
|
||||||
|
BuildHeaderVal(header), \
|
||||||
|
smb_string2stringval(${val.file_name}));
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_trans2_query_path_info_response(header: SMB_Header, val: trans2_query_path_info_response): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_query_path_info response!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_query_path_info_request(header: SMB_Header) = record {
|
||||||
|
information_level : uint16;
|
||||||
|
reserved : uint32;
|
||||||
|
file_name : SMB_string(header.unicode, offsetof(file_name));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_query_path_info_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_query_path_info_response(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_query_path_info_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_trans2_query_file_info_request(header: SMB_Header, val: trans2_query_file_info_request): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_query_file_info request!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_trans2_query_file_info_response(header: SMB_Header, val: trans2_query_file_info_response): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_query_file_info response!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_query_file_info_request(header: SMB_Header) = record {
|
||||||
|
file_id : uint16;
|
||||||
|
information_level : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_query_file_info_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_query_file_info_response(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_query_file_info_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_trans2_set_file_info_request(header: SMB_Header, val: trans2_set_file_info_request): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_set_file_info request!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_trans2_set_file_info_response(header: SMB_Header, val: trans2_set_file_info_response): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_set_file_info response!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_set_file_info_request(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_set_file_info_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_set_file_info_response(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_set_file_info_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_trans2_get_dfs_referral_request(header: SMB_Header, val: trans2_get_dfs_referral_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_trans2_get_dfs_referral_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_trans2_get_dfs_referral_request(bro_analyzer(), bro_analyzer()->Conn(), \
|
||||||
|
BuildHeaderVal(header), \
|
||||||
|
smb_string2stringval(${val.file_name}));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_trans2_get_dfs_referral_response(header: SMB_Header, val: trans2_get_dfs_referral_response): bool
|
||||||
|
%{
|
||||||
|
// TODO: implement this.
|
||||||
|
//printf("trans2_get_dfs_referral response!\n");
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_get_dfs_referral_request(header: SMB_Header) = record {
|
||||||
|
max_referral_level : uint16;
|
||||||
|
file_name : SMB_string(header.unicode, offsetof(file_name));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_get_dfs_referral_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type trans2_get_dfs_referral_response(header: SMB_Header) = record {
|
||||||
|
# TODO: implement this.
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_trans2_get_dfs_referral_response(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
###########################################
|
55
src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac
Normal file
55
src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_tree_connect_andx_request(header: SMB_Header, val: SMB1_tree_connect_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_tree_connect_andx_request )
|
||||||
|
BifEvent::generate_smb1_tree_connect_andx_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.path}),
|
||||||
|
smb_string2stringval(${val.service}));
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_tree_connect_andx_response(header: SMB_Header, val: SMB1_tree_connect_andx_response): bool
|
||||||
|
%{
|
||||||
|
set_tree_is_pipe(${header.tid}, strncmp((const char*) smb_string2stringval(${val.service})->Bytes(), "IPC", 3) == 0);
|
||||||
|
if ( smb1_tree_connect_andx_response )
|
||||||
|
BifEvent::generate_smb1_tree_connect_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
smb_string2stringval(${val.service}),
|
||||||
|
smb_string2stringval(${val.native_file_system}));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_tree_connect_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
flags : uint16;
|
||||||
|
password_length : uint16;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
password : uint8[password_length];
|
||||||
|
path : SMB_string(header.unicode, offsetof(path));
|
||||||
|
service : SMB_string(0, offsetof(service));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_tree_connect_andx_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_tree_connect_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
optional_support : uint16;
|
||||||
|
pad : padding[(word_count-3)*2];
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
service : SMB_string(0, offsetof(service));
|
||||||
|
native_file_system : SMB_string(header.unicode, offsetof(native_file_system));
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_tree_connect_andx_response(header, this);
|
||||||
|
};
|
||||||
|
|
21
src/analyzer/protocol/smb/smb1-com-tree-disconnect.pac
Normal file
21
src/analyzer/protocol/smb/smb1-com-tree-disconnect.pac
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_tree_disconnect(header: SMB_Header, val: SMB1_tree_disconnect): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_tree_disconnect )
|
||||||
|
BifEvent::generate_smb1_tree_disconnect(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header),
|
||||||
|
${val.is_orig});
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_tree_disconnect(header: SMB_Header, is_orig: bool) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb1_tree_disconnect(header, this);
|
||||||
|
};
|
78
src/analyzer/protocol/smb/smb1-com-write-andx.pac
Normal file
78
src/analyzer/protocol/smb/smb1-com-write-andx.pac
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
function proc_smb1_write_andx_request(h: SMB_Header, val: SMB1_write_andx_request): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_write_andx_request )
|
||||||
|
BifEvent::generate_smb1_write_andx_request(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.file_id},
|
||||||
|
${val.offset},
|
||||||
|
${val.data_len});
|
||||||
|
|
||||||
|
if ( ! ${val.is_pipe} && ${val.data}.length() > 0 )
|
||||||
|
{
|
||||||
|
file_mgr->DataIn(${val.data}.begin(), ${val.data}.length(),
|
||||||
|
${val.offset},
|
||||||
|
bro_analyzer()->GetAnalyzerTag(),
|
||||||
|
bro_analyzer()->Conn(), h->is_orig());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb1_write_andx_response(h: SMB_Header, val: SMB1_write_andx_response): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_write_andx_response )
|
||||||
|
BifEvent::generate_smb1_write_andx_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
${val.written_bytes});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_write_andx_request(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
file_id : uint16;
|
||||||
|
offset_low : uint32;
|
||||||
|
timeout : uint32;
|
||||||
|
write_mode : uint16;
|
||||||
|
remaining : uint16;
|
||||||
|
data_len_high : uint16;
|
||||||
|
data_len_low : uint16;
|
||||||
|
data_offset : uint16;
|
||||||
|
offset_high_u : case word_count of {
|
||||||
|
0x0E -> offset_high_tmp : uint32;
|
||||||
|
default -> null : empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
pad : padding to data_offset - SMB_Header_length;
|
||||||
|
data : bytestring &length=data_len;
|
||||||
|
} &let {
|
||||||
|
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid);
|
||||||
|
pipe_proc : bool = $context.connection.forward_dce_rpc(data, 0, true) &if(is_pipe);
|
||||||
|
|
||||||
|
data_len : uint32 = (data_len_high << 16) + data_len_low;
|
||||||
|
offset_high : uint32 = (word_count == 0x0E) ? offset_high_tmp : 0;
|
||||||
|
offset : uint64 = (offset_high * 0x10000) + offset_low;
|
||||||
|
proc : bool = $context.connection.proc_smb1_write_andx_request(header, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB1_write_andx_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
andx : SMB_andx;
|
||||||
|
written_low : uint16;
|
||||||
|
remaining : uint16;
|
||||||
|
written_high : uint16;
|
||||||
|
reserved : uint16;
|
||||||
|
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
written_bytes : uint32 = (written_high * 0x10000) + written_low;
|
||||||
|
proc : bool = $context.connection.proc_smb1_write_andx_response(header, this);
|
||||||
|
};
|
325
src/analyzer/protocol/smb/smb1-protocol.pac
Normal file
325
src/analyzer/protocol/smb/smb1-protocol.pac
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
%extern{
|
||||||
|
#include "file_analysis/Manager.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
function BuildHeaderVal(hdr: SMB_Header): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* r = new RecordVal(BifType::Record::SMB1::Header);
|
||||||
|
|
||||||
|
//unsigned int status = 0;
|
||||||
|
//
|
||||||
|
//try
|
||||||
|
// {
|
||||||
|
// // FIXME: does this work? We need to catch exceptions :-(
|
||||||
|
// // or use guard functions.
|
||||||
|
// status = ${hdr.status.error} ||
|
||||||
|
// ${hdr.status.dos_error.error_class} << 24 ||
|
||||||
|
// ${hdr.status.dos_error.error_class};
|
||||||
|
// }
|
||||||
|
//catch ( const binpac::Exception& )
|
||||||
|
// { // do nothing
|
||||||
|
// }
|
||||||
|
|
||||||
|
r->Assign(0, new Val(${hdr.command}, TYPE_COUNT));
|
||||||
|
r->Assign(1, new Val(${hdr.status}, TYPE_COUNT));
|
||||||
|
r->Assign(2, new Val(${hdr.flags}, TYPE_COUNT));
|
||||||
|
r->Assign(3, new Val(${hdr.flags2}, TYPE_COUNT));
|
||||||
|
r->Assign(4, new Val(${hdr.tid}, TYPE_COUNT));
|
||||||
|
r->Assign(5, new Val(${hdr.pid}, TYPE_COUNT));
|
||||||
|
r->Assign(6, new Val(${hdr.uid}, TYPE_COUNT));
|
||||||
|
r->Assign(7, new Val(${hdr.mid}, TYPE_COUNT));
|
||||||
|
|
||||||
|
return r;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb_message(h: SMB_Header, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_message )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_message(bro_analyzer(), bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h),
|
||||||
|
is_orig);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb_empty_response(header: SMB_Header): bool
|
||||||
|
%{
|
||||||
|
if ( smb1_empty_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_empty_response(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(header));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb_no_msg(h: SMB_Header, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
if ( ${h.status} == STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
if ( smb1_empty_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_empty_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BifEvent::generate_smb1_error(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
BuildHeaderVal(h), is_orig);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_dos_error = record {
|
||||||
|
error_class : uint8;
|
||||||
|
reserved : uint8;
|
||||||
|
error : uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_error(err_status_type: int) = case err_status_type of {
|
||||||
|
0 -> dos_error : SMB_dos_error;
|
||||||
|
default -> error : uint32;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_andx = record {
|
||||||
|
command : uint8;
|
||||||
|
reserved : uint8;
|
||||||
|
offset : uint16;
|
||||||
|
} &byteorder = littleendian;
|
||||||
|
|
||||||
|
type SMB_PDU(is_orig: bool, msg_len: uint32) = record {
|
||||||
|
header : SMB_Header(is_orig);
|
||||||
|
message : case msg_len of {
|
||||||
|
# Message length of 35 means that the actual message is
|
||||||
|
# only three bytes which means it's an empty response.
|
||||||
|
35 -> no_msg : SMB_No_Message(header, is_orig);
|
||||||
|
default -> msg : SMB_Message(header, header.command, is_orig);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_No_Message(header: SMB_Header, is_orig: bool) = record {
|
||||||
|
x : bytestring &length=3 &transient;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb_no_msg(header, is_orig);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_empty_response(header: SMB_Header) = record {
|
||||||
|
word_count : uint8;
|
||||||
|
byte_count : uint16;
|
||||||
|
} &let {
|
||||||
|
proc : bool = $context.connection.proc_smb_empty_response(header);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_Message(header: SMB_Header, command: uint8, is_orig: bool) = case is_orig of {
|
||||||
|
true -> request : SMB_Message_Request(header, command, is_orig);
|
||||||
|
false -> response : SMB_Message_Response(header, command, is_orig);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_andx_command(header: SMB_Header, is_orig: bool, command: uint8) = case command of {
|
||||||
|
0xff -> no_futher_commands : empty;
|
||||||
|
default -> message : SMB_Message(header, command, is_orig);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SMB_Message_Request(header: SMB_Header, command: uint8, is_orig: bool) = case command of {
|
||||||
|
# SMB1 Command Extensions
|
||||||
|
#SMB_COM_OPEN_ANDX -> open_andx : SMB_open_andx_request(header);
|
||||||
|
SMB_COM_READ_ANDX -> read_andx : SMB1_read_andx_request(header);
|
||||||
|
SMB_COM_WRITE_ANDX -> write_andx : SMB1_write_andx_request(header);
|
||||||
|
SMB_COM_TRANSACTION2 -> transaction2 : SMB1_transaction2_request(header);
|
||||||
|
SMB_COM_NEGOTIATE -> negotiate : SMB1_negotiate_request(header);
|
||||||
|
SMB_COM_SESSION_SETUP_ANDX -> session_setup_andx : SMB1_session_setup_andx_request(header);
|
||||||
|
SMB_COM_TREE_CONNECT_ANDX -> tree_connect_andx : SMB1_tree_connect_andx_request(header);
|
||||||
|
SMB_COM_NT_TRANSACT -> nt_transact : SMB1_nt_transact_request(header);
|
||||||
|
SMB_COM_NT_CREATE_ANDX -> nt_create_andx : SMB1_nt_create_andx_request(header);
|
||||||
|
|
||||||
|
# SMB_COM_CREATE_DIRECTORY -> create_directory : SMB1_create_directory_request(header);
|
||||||
|
# #SMB_COM_DELETE_DIRECTORY -> delete_directory : SMB_delete_directory_request(header);
|
||||||
|
# #SMB_COM_OPEN -> open : SMB_open_request(header);
|
||||||
|
# #SMB_COM_CREATE -> create : SMB_create_request(header);
|
||||||
|
SMB_COM_CLOSE -> close : SMB1_close_request(header);
|
||||||
|
# #SMB_COM_FLUSH -> flush : SMB_flush_request(header);
|
||||||
|
# #SMB_COM_DELETE -> delete : SMB_delete_request(header);
|
||||||
|
# #SMB_COM_RENAME -> rename : SMB_rename_request(header);
|
||||||
|
SMB_COM_QUERY_INFORMATION -> query_information : SMB1_query_information_request(header);
|
||||||
|
# #SMB_COM_SET_INFORMATION -> set_information : SMB_set_information_request(header);
|
||||||
|
# #SMB_COM_READ -> read : SMB_read_request(header);
|
||||||
|
# #SMB_COM_WRITE -> write : SMB_write_request(header);
|
||||||
|
# #SMB_COM_LOCK_BYTE_RANGE -> lock_byte_range : SMB_lock_byte_range_request(header);
|
||||||
|
# #SMB_COM_UNLOCK_BYTE_RANGE -> unlock_byte_range : SMB_unlock_byte_range_request(header);
|
||||||
|
# #SMB_COM_CREATE_TEMPORARY -> create_temporary : SMB_create_temporary_request(header);
|
||||||
|
# #SMB_COM_CREATE_NEW -> create_new : SMB_create_new_request(header);
|
||||||
|
SMB_COM_CHECK_DIRECTORY -> check_directory : SMB1_check_directory_request(header);
|
||||||
|
# #SMB_COM_PROCESS_EXIT -> process_exit : SMB_process_exit_request(header);
|
||||||
|
# #SMB_COM_SEEK -> seek : SMB_seek_request(header);
|
||||||
|
# #SMB_COM_LOCK_AND_READ -> lock_and_read : SMB_lock_and_read_request(header);
|
||||||
|
# #SMB_COM_WRITE_AND_UNLOCK -> write_and_unlock : SMB_write_and_unlock_request(header);
|
||||||
|
# #SMB_COM_READ_RAW -> read_raw : SMB_read_raw_request(header);
|
||||||
|
# #SMB_COM_READ_MPX -> read_mpx : SMB_read_mpx_request(header);
|
||||||
|
# #SMB_COM_READ_MPX_SECONDARY -> read_mpx_secondary : SMB_read_mpx_secondary_request(header);
|
||||||
|
# #SMB_COM_WRITE_RAW -> write_raw : SMB_write_raw_request(header);
|
||||||
|
# #SMB_COM_WRITE_MPX -> write_mpx : SMB_write_mpx_request(header);
|
||||||
|
# #SMB_COM_WRITE_MPX_SECONDARY -> write_mpx_secondary : SMB_write_mpx_secondary_request(header);
|
||||||
|
# #SMB_COM_WRITE_COMPLETE -> write_complete : SMB_write_complete_request(header);
|
||||||
|
# #SMB_COM_QUERY_SERVER -> query_server : SMB_query_server_request(header);
|
||||||
|
# #SMB_COM_SET_INFORMATION2 -> set_information2 : SMB_set_information2_request(header);
|
||||||
|
# #SMB_COM_QUERY_INFORMATION2 -> query_information2 : SMB_query_information2_request(header);
|
||||||
|
SMB_COM_LOCKING_ANDX -> locking_andx : SMB1_locking_andx_request(header);
|
||||||
|
SMB_COM_TRANSACTION -> transaction : SMB1_transaction_request(header);
|
||||||
|
# SMB_COM_TRANSACTION_SECONDARY -> transaction_secondary : SMB1_transaction_secondary_request(header);
|
||||||
|
# #SMB_COM_IOCTL -> ioctl : SMB_ioctl_request(header);
|
||||||
|
# #SMB_COM_IOCTL_SECONDARY -> ioctl_secondary : SMB_ioctl_secondary_request(header);
|
||||||
|
# #SMB_COM_COPY -> copy : SMB_copy_request(header);
|
||||||
|
# #SMB_COM_MOVE -> move : SMB_move_request(header);
|
||||||
|
SMB_COM_ECHO -> echo : SMB1_echo_request(header);
|
||||||
|
# #SMB_COM_WRITE_AND_CLOSE -> write_and_close : SMB_write_and_close_request(header);
|
||||||
|
# #SMB_COM_NEW_FILE_SIZE -> new_file_size : SMB_new_file_size_request(header);
|
||||||
|
# #SMB_COM_CLOSE_AND_TREE_DISC -> close_and_tree_disc : SMB_close_and_tree_disc_request(header);
|
||||||
|
# #SMB_COM_TRANSACTION2_SECONDARY -> transaction2_secondary : SMB1_transaction2_secondary_request(header);
|
||||||
|
# #SMB_COM_FIND_CLOSE2 -> find_close2 : SMB_find_close2_request(header);
|
||||||
|
# #SMB_COM_FIND_NOTIFY_CLOSE -> find_notify_close : SMB_find_notify_close_request(header);
|
||||||
|
# #SMB_COM_TREE_CONNECT -> tree_connect : SMB_tree_connect_request(header);
|
||||||
|
SMB_COM_TREE_DISCONNECT -> tree_disconnect : SMB1_tree_disconnect(header, is_orig);
|
||||||
|
SMB_COM_LOGOFF_ANDX -> logoff_andx : SMB1_logoff_andx(header, is_orig);
|
||||||
|
# #SMB_COM_QUERY_INFORMATION_DISK -> query_information_disk : SMB_query_information_disk_request(header);
|
||||||
|
# #SMB_COM_SEARCH -> search : SMB_search_request(header);
|
||||||
|
# #SMB_COM_FIND -> find : SMB_find_request(header);
|
||||||
|
# #SMB_COM_FIND_UNIQUE -> find_unique : SMB_find_unique_request(header);
|
||||||
|
# #SMB_COM_FIND_CLOSE -> find_close : SMB_find_close_request(header);
|
||||||
|
# #SMB_COM_NT_TRANSACT_SECONDARY -> nt_transact_secondary : SMB_nt_transact_secondary_request(header);
|
||||||
|
SMB_COM_NT_CANCEL -> nt_cancel : SMB1_nt_cancel_request(header);
|
||||||
|
# #SMB_COM_NT_RENAME -> nt_rename : SMB_nt_rename_request(header);
|
||||||
|
# #SMB_COM_OPEN_PRINT_FILE -> open_print_file : SMB_open_print_file_request(header);
|
||||||
|
# #SMB_COM_WRITE_PRINT_FILE -> write_print_file : SMB_write_print_file_request(header);
|
||||||
|
# #SMB_COM_CLOSE_PRINT_FILE -> close_print_file : SMB_close_print_file_request(header);
|
||||||
|
# #SMB_COM_GET_PRINT_QUEUE -> get_print_queue : SMB_get_print_queue_request(header);
|
||||||
|
# #SMB_COM_READ_BULK -> read_bulk : SMB_read_bulk_request(header);
|
||||||
|
# #SMB_COM_WRITE_BULK -> write_bulk : SMB_write_bulk_request(header);
|
||||||
|
# #SMB_COM_WRITE_BULK_DATA -> write_bulk_data : SMB_write_bulk_data_request(header);
|
||||||
|
default -> unknown_msg : bytestring &restofdata; # TODO: do something different here!
|
||||||
|
} &byteorder = littleendian;
|
||||||
|
|
||||||
|
type SMB_Message_Response(header: SMB_Header, command: uint8, is_orig: bool) = case command of {
|
||||||
|
# SMB1 Command Extensions
|
||||||
|
#SMB_COM_OPEN_ANDX -> open_andx : SMB_open_andx_response(header);
|
||||||
|
SMB_COM_READ_ANDX -> read_andx : SMB1_read_andx_response(header);
|
||||||
|
SMB_COM_WRITE_ANDX -> write_andx : SMB1_write_andx_response(header);
|
||||||
|
SMB_COM_TRANSACTION2 -> transaction2 : SMB1_transaction2_response(header);
|
||||||
|
SMB_COM_NEGOTIATE -> negotiate : SMB1_negotiate_response(header);
|
||||||
|
SMB_COM_SESSION_SETUP_ANDX -> session_setup_andx : SMB1_session_setup_andx_response(header);
|
||||||
|
SMB_COM_TREE_CONNECT_ANDX -> tree_connect_andx : SMB1_tree_connect_andx_response(header);
|
||||||
|
SMB_COM_NT_TRANSACT -> nt_transact : SMB1_nt_transact_response(header);
|
||||||
|
SMB_COM_NT_CREATE_ANDX -> nt_create_andx : SMB1_nt_create_andx_response(header);
|
||||||
|
|
||||||
|
# SMB_COM_CREATE_DIRECTORY -> create_directory : SMB1_create_directory_response(header);
|
||||||
|
# #SMB_COM_DELETE_DIRECTORY -> delete_directory : SMB_delete_directory_response(header);
|
||||||
|
# #SMB_COM_OPEN -> open : SMB_open_response(header);
|
||||||
|
# #SMB_COM_CREATE -> create : SMB_create_response(header);
|
||||||
|
SMB_COM_CLOSE -> close : SMB_empty_response(header);
|
||||||
|
# #SMB_COM_FLUSH -> flush : SMB_flush_response(header);
|
||||||
|
# #SMB_COM_DELETE -> delete : SMB_delete_response(header);
|
||||||
|
# #SMB_COM_RENAME -> rename : SMB_rename_response(header);
|
||||||
|
SMB_COM_QUERY_INFORMATION -> query_information : SMB1_query_information_response(header);
|
||||||
|
# #SMB_COM_SET_INFORMATION -> set_information : SMB_set_information_response(header);
|
||||||
|
# #SMB_COM_READ -> read : SMB_read_response(header);
|
||||||
|
# #SMB_COM_WRITE -> write : SMB_write_response(header);
|
||||||
|
# #SMB_COM_LOCK_BYTE_RANGE -> lock_byte_range : SMB_lock_byte_range_response(header);
|
||||||
|
# #SMB_COM_UNLOCK_BYTE_RANGE -> unlock_byte_range : SMB_unlock_byte_range_response(header);
|
||||||
|
# #SMB_COM_CREATE_TEMPORARY -> create_temporary : SMB_create_temporary_response(header);
|
||||||
|
# #SMB_COM_CREATE_NEW -> create_new : SMB_create_new_response(header);
|
||||||
|
SMB_COM_CHECK_DIRECTORY -> check_directory : SMB1_check_directory_response(header);
|
||||||
|
# #SMB_COM_PROCESS_EXIT -> process_exit : SMB_process_exit_response(header);
|
||||||
|
# #SMB_COM_SEEK -> seek : SMB_seek_response(header);
|
||||||
|
# #SMB_COM_LOCK_AND_READ -> lock_and_read : SMB_lock_and_read_response(header);
|
||||||
|
# #SMB_COM_WRITE_AND_UNLOCK -> write_and_unlock : SMB_write_and_unlock_response(header);
|
||||||
|
# #SMB_COM_READ_RAW -> read_raw : SMB_read_raw_response(header);
|
||||||
|
# #SMB_COM_READ_MPX -> read_mpx : SMB_read_mpx_response(header);
|
||||||
|
# #SMB_COM_READ_MPX_SECONDARY -> read_mpx_secondary : SMB_read_mpx_secondary_response(header);
|
||||||
|
# #SMB_COM_WRITE_RAW -> write_raw : SMB_write_raw_response(header);
|
||||||
|
# #SMB_COM_WRITE_MPX -> write_mpx : SMB_write_mpx_response(header);
|
||||||
|
# #SMB_COM_WRITE_MPX_SECONDARY -> write_mpx_secondary : SMB_write_mpx_secondary_response(header);
|
||||||
|
# #SMB_COM_WRITE_COMPLETE -> write_complete : SMB_write_complete_response(header);
|
||||||
|
# #SMB_COM_QUERY_SERVER -> query_server : SMB_query_server_response(header);
|
||||||
|
# #SMB_COM_SET_INFORMATION2 -> set_information2 : SMB_set_information2_response(header);
|
||||||
|
# #SMB_COM_QUERY_INFORMATION2 -> query_information2 : SMB_query_information2_response(header);
|
||||||
|
SMB_COM_LOCKING_ANDX -> locking_andx : SMB1_locking_andx_response(header);
|
||||||
|
SMB_COM_TRANSACTION -> transaction : SMB1_transaction_response(header);
|
||||||
|
# #SMB_COM_IOCTL -> ioctl : SMB_ioctl_response(header);
|
||||||
|
# #SMB_COM_IOCTL_SECONDARY -> ioctl_secondary : SMB_ioctl_secondary_response(header);
|
||||||
|
# #SMB_COM_COPY -> copy : SMB_copy_response(header);
|
||||||
|
# #SMB_COM_MOVE -> move : SMB_move_response(header);
|
||||||
|
SMB_COM_ECHO -> echo : SMB1_echo_response(header);
|
||||||
|
# #SMB_COM_WRITE_AND_CLOSE -> write_and_close : SMB_write_and_close_response(header);
|
||||||
|
# #SMB_COM_NEW_FILE_SIZE -> new_file_size : SMB_new_file_size_response(header);
|
||||||
|
# #SMB_COM_CLOSE_AND_TREE_DISC -> close_and_tree_disc : SMB_close_and_tree_disc_response(header);
|
||||||
|
# #SMB_COM_TRANSACTION2_SECONDARY -> transaction2_secondary : SMB1_transaction2_secondary_response(header);
|
||||||
|
# #SMB_COM_FIND_CLOSE2 -> find_close2 : SMB_find_close2_response(header);
|
||||||
|
# #SMB_COM_FIND_NOTIFY_CLOSE -> find_notify_close : SMB_find_notify_close_response(header);
|
||||||
|
# #SMB_COM_TREE_CONNECT -> tree_connect : SMB_tree_connect_response(header);
|
||||||
|
SMB_COM_TREE_DISCONNECT -> tree_disconnect : SMB1_tree_disconnect(header, is_orig);
|
||||||
|
SMB_COM_LOGOFF_ANDX -> logoff_andx : SMB1_logoff_andx(header, is_orig);
|
||||||
|
# #SMB_COM_QUERY_INFORMATION_DISK -> query_information_disk : SMB_query_information_disk_response(header);
|
||||||
|
# #SMB_COM_SEARCH -> search : SMB_search_response(header);
|
||||||
|
# #SMB_COM_FIND -> find : SMB_find_response(header);
|
||||||
|
# #SMB_COM_FIND_UNIQUE -> find_unique : SMB_find_unique_response(header);
|
||||||
|
# #SMB_COM_FIND_CLOSE -> find_close : SMB_find_close_response(header);
|
||||||
|
# #SMB_COM_NT_TRANSACT_SECONDARY -> nt_transact_secondary : SMB_nt_transact_secondary_response(header);
|
||||||
|
#SMB_COM_NT_CANCEL -> nt_cancel : SMB1_nt_cancel_response(header);
|
||||||
|
# #SMB_COM_NT_RENAME -> nt_rename : SMB_nt_rename_response(header);
|
||||||
|
# #SMB_COM_OPEN_PRINT_FILE -> open_print_file : SMB_open_print_file_response(header);
|
||||||
|
# #SMB_COM_WRITE_PRINT_FILE -> write_print_file : SMB_write_print_file_response(header);
|
||||||
|
# #SMB_COM_CLOSE_PRINT_FILE -> close_print_file : SMB_close_print_file_response(header);
|
||||||
|
# #SMB_COM_GET_PRINT_QUEUE -> get_print_queue : SMB_get_print_queue_response(header);
|
||||||
|
# #SMB_COM_READ_BULK -> read_bulk : SMB_read_bulk_response(header);
|
||||||
|
# #SMB_COM_WRITE_BULK -> write_bulk : SMB_write_bulk_response(header);
|
||||||
|
# #SMB_COM_WRITE_BULK_DATA -> write_bulk_data : SMB_write_bulk_data_response(header);
|
||||||
|
default -> unknown_msg : bytestring &restofdata;
|
||||||
|
} &byteorder = littleendian;
|
||||||
|
|
||||||
|
|
||||||
|
type SMB_Header(is_orig: bool) = record {
|
||||||
|
command : uint8;
|
||||||
|
#status : SMB_error(err_status_type);
|
||||||
|
status : uint32;
|
||||||
|
flags : uint8;
|
||||||
|
flags2 : uint16;
|
||||||
|
pid_high : uint16;
|
||||||
|
security_features : uint8[8];
|
||||||
|
reserved : uint16;
|
||||||
|
tid : uint16;
|
||||||
|
pid_low : uint16;
|
||||||
|
uid : uint16;
|
||||||
|
mid : uint16;
|
||||||
|
} &let {
|
||||||
|
err_status_type = (flags2 >> 14) & 1;
|
||||||
|
unicode = (flags2 >> 15) & 1;
|
||||||
|
pid = (pid_high * 0x10000) + pid_low;
|
||||||
|
proc : bool = $context.connection.proc_smb_message(this, is_orig);
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
# TODO: compute this as
|
||||||
|
# let SMB_Header_length = sizeof(SMB_Header);
|
||||||
|
let SMB_Header_length = 32;
|
||||||
|
|
||||||
|
|
||||||
|
refine connection SMB_Conn += {
|
||||||
|
|
||||||
|
%member{
|
||||||
|
int offset_len;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
// This needs to be set to some actual value.
|
||||||
|
// TODO: figure out where the hell to get this value from...
|
||||||
|
offset_len = 64;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function get_offset_len(): int
|
||||||
|
%{
|
||||||
|
return offset_len;
|
||||||
|
%}
|
||||||
|
};
|
15
src/analyzer/protocol/smb/smb1_com_check_directory.bif
Normal file
15
src/analyzer/protocol/smb/smb1_com_check_directory.bif
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
## Generated for SMB/CIFS requests of type *check directory*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
##
|
||||||
|
## directory_name: The directory name to check for existence.
|
||||||
|
event smb1_check_directory_request%(c: connection, hdr: SMB1::Header, directory_name: string%);
|
||||||
|
|
||||||
|
## Generated for SMB/CIFS responses of type *check directory*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
event smb1_check_directory_response%(c: connection, hdr: SMB1::Header%);
|
13
src/analyzer/protocol/smb/smb1_com_close.bif
Normal file
13
src/analyzer/protocol/smb/smb1_com_close.bif
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
## Generated for SMB/CIFS request messages of type *close*.
|
||||||
|
##
|
||||||
|
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
||||||
|
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
||||||
|
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
##
|
||||||
|
## file_id: The file identifier being closed.
|
||||||
|
event smb1_close_request%(c: connection, hdr: SMB1::Header, file_id: count%);
|
||||||
|
|
19
src/analyzer/protocol/smb/smb1_com_create_directory.bif
Normal file
19
src/analyzer/protocol/smb/smb1_com_create_directory.bif
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
## Generated for SMB/CIFS requests of type *create directory*. This is also
|
||||||
|
## a deprecated command which has been replaced by the trans2_create_directory
|
||||||
|
## subcommand.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
##
|
||||||
|
## directory_name: The name of the directory to create.
|
||||||
|
event smb1_create_directory_request%(c: connection, hdr: SMB1::Header, directory_name: string%);
|
||||||
|
|
||||||
|
## Generated for SMB/CIFS responses of type *create directory*. This is also
|
||||||
|
## a deprecated command which has been replaced by the trans2_create_directory
|
||||||
|
## subcommand.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
event smb1_create_directory_response%(c: connection, hdr: SMB1::Header%);
|
21
src/analyzer/protocol/smb/smb1_com_echo.bif
Normal file
21
src/analyzer/protocol/smb/smb1_com_echo.bif
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
## Generated for SMB/CIFS requests of type *echo*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
##
|
||||||
|
## echo_count: The number of times the server should echo the data back.
|
||||||
|
##
|
||||||
|
## data: The data for the server to echo.
|
||||||
|
event smb1_echo_request%(c: connection, echo_count: count, data: string%);
|
||||||
|
|
||||||
|
## Generated for SMB/CIFS responses of type *negotiate*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## hdr: The parsed header of the SMB message.
|
||||||
|
##
|
||||||
|
## seq_num: The sequence number of this echo reply.
|
||||||
|
##
|
||||||
|
## data: The data echoed back from the client.
|
||||||
|
event smb1_echo_response%(c: connection, seq_num: count, data: string%);
|
11
src/analyzer/protocol/smb/smb1_com_logoff_andx.bif
Normal file
11
src/analyzer/protocol/smb/smb1_com_logoff_andx.bif
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
## Generated for SMB/CIFS messages of type *logoff andx*.
|
||||||
|
##
|
||||||
|
## See `Wikipedia <http://en.wikipedia.org/wiki/Server_Message_Block>`__ for
|
||||||
|
## more information about the SMB/CIFS protocol. Bro's SMB/CIFS analyzer parses
|
||||||
|
## both SMB-over-NetBIOS on ports 138/139 and SMB-over-TCP on port 445.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## is_orig: Indicates which host sent the logoff message..
|
||||||
|
event smb1_logoff_andx%(c: connection, is_orig: bool%);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue