mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Merge remote-tracking branch 'origin/topic/seth/smb' into topic/robin/smb-merge
This commit is contained in:
commit
781fdfa5ba
159 changed files with 12388 additions and 3840 deletions
|
@ -93,7 +93,7 @@ signature file-ini {
|
|||
# Microsoft LNK files
|
||||
signature file-lnk {
|
||||
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
|
||||
|
@ -310,4 +310,4 @@ signature file-elf-sharedlib {
|
|||
signature file-elf-coredump {
|
||||
file-mime "application/x-coredump", 50
|
||||
file-magic /\x7fELF[\x01\x02](\x01.{10}\x04\x00|\x02.{10}\x00\x04)/
|
||||
}
|
||||
}
|
|
@ -2380,83 +2380,508 @@ type ntp_msg: record {
|
|||
};
|
||||
|
||||
|
||||
## Maps SMB command numbers to descriptive names.
|
||||
global samba_cmds: table[count] of string &redef
|
||||
&default = function(c: count): string
|
||||
{ return fmt("samba-unknown-%d", c); };
|
||||
module NTLM;
|
||||
|
||||
## An SMB command 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 smb_hdr : record {
|
||||
command: count; ##< The command number (see :bro:see:`samba_cmds`).
|
||||
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.
|
||||
};
|
||||
export {
|
||||
type NTLM::Version: record {
|
||||
## The major version of the Windows operating system in use
|
||||
major : count;
|
||||
## The minor version of the Windows operating system in use
|
||||
minor : count;
|
||||
## The build number of the Windows operating system in use
|
||||
build : count;
|
||||
## The current revision of NTLMSSP in use
|
||||
ntlmssp : count;
|
||||
};
|
||||
|
||||
## An SMB transaction.
|
||||
##
|
||||
## .. bro:see:: smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap
|
||||
## smb_com_transaction smb_com_transaction2
|
||||
type smb_trans : record {
|
||||
word_count: count; ##< TODO.
|
||||
total_param_count: count; ##< TODO.
|
||||
total_data_count: count; ##< TODO.
|
||||
max_param_count: count; ##< TODO.
|
||||
max_data_count: count; ##< TODO.
|
||||
max_setup_count: count; ##< TODO.
|
||||
# flags: count;
|
||||
# timeout: count;
|
||||
param_count: count; ##< TODO.
|
||||
param_offset: count; ##< TODO.
|
||||
data_count: count; ##< TODO.
|
||||
data_offset: count; ##< TODO.
|
||||
setup_count: count; ##< TODO.
|
||||
setup0: count; ##< TODO.
|
||||
setup1: count; ##< TODO.
|
||||
setup2: count; ##< TODO.
|
||||
setup3: count; ##< TODO.
|
||||
byte_count: count; ##< TODO.
|
||||
parameters: string; ##< TODO.
|
||||
};
|
||||
type NTLM::NegotiateFlags: record {
|
||||
## If set, requires 56-bit encryption
|
||||
negotiate_56 : bool;
|
||||
## If set, requests an explicit key exchange
|
||||
negotiate_key_exch : bool;
|
||||
## If set, requests 128-bit session key negotiation
|
||||
negotiate_128 : bool;
|
||||
## If set, requests the protocol version number
|
||||
negotiate_version : bool;
|
||||
## If set, indicates that the TargetInfo fields in the
|
||||
## CHALLENGE_MESSAGE are populated
|
||||
negotiate_target_info : bool;
|
||||
## If set, requests the usage of the LMOWF function
|
||||
request_non_nt_session_key : bool;
|
||||
## If set, requests and identify level token
|
||||
negotiate_identify : bool;
|
||||
## If set, requests usage of NTLM v2 session security
|
||||
## Note: NTML v2 session security is actually NTLM v1
|
||||
negotiate_extended_sessionsecurity : bool;
|
||||
## If set, TargetName must be a server name
|
||||
target_type_server : bool;
|
||||
## If set, TargetName must be a domain name
|
||||
target_type_domain : bool;
|
||||
|
||||
## 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.
|
||||
##
|
||||
## .. 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;
|
||||
};
|
||||
module SMB2;
|
||||
|
||||
## Deprecated.
|
||||
##
|
||||
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere
|
||||
## else.
|
||||
type smb_negotiate : table[count] of string;
|
||||
export {
|
||||
type SMB2::Header: record {
|
||||
credit_charge: count;
|
||||
status: count;
|
||||
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.
|
||||
##
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
@load base/frameworks/netcontrol
|
||||
|
||||
@load base/protocols/conn
|
||||
@load base/protocols/dce-rpc
|
||||
@load base/protocols/dhcp
|
||||
@load base/protocols/dnp3
|
||||
@load base/protocols/dns
|
||||
|
@ -53,12 +54,16 @@
|
|||
@load base/protocols/krb
|
||||
@load base/protocols/modbus
|
||||
@load base/protocols/mysql
|
||||
@load base/protocols/ntlm
|
||||
@load base/protocols/pop3
|
||||
@load base/protocols/radius
|
||||
@load base/protocols/rdp
|
||||
@load base/protocols/rfb
|
||||
@load base/protocols/sip
|
||||
@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/socks
|
||||
@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
|
1427
scripts/base/protocols/dce-rpc/consts.bro
Normal file
1427
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;
|
||||
}
|
||||
}
|
268
scripts/policy/protocols/smb/main.bro
Normal file
268
scripts/policy/protocols/smb/main.bro
Normal file
|
@ -0,0 +1,268 @@
|
|||
@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_CLOSE,
|
||||
|
||||
PIPE_OPEN,
|
||||
PIPE_CLOSE,
|
||||
|
||||
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;
|
||||
## 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);
|
||||
}
|
||||
}
|
||||
}
|
268
scripts/policy/protocols/smb/smb2-main.bro
Normal file
268
scripts/policy/protocols/smb/smb2-main.bro
Normal file
|
@ -0,0 +1,268 @@
|
|||
@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];
|
||||
SMB::write_file_log(c$smb_state);
|
||||
}
|
||||
|
||||
# This is commented out for now because the message type in the SMB analyzer
|
||||
# is no where near complete.
|
||||
#event smb2_set_info_request(c: connection, hdr: SMB2::Header, request: SMB2::SetInfoRequest) &priority=5
|
||||
# {
|
||||
# c$smb_state$current_file$size = request$eof;
|
||||
# }
|
||||
|
||||
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::UNKNOWN_OPEN;
|
||||
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_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
|
||||
# this adds the link-layer address for each connection endpoint to the conn.log file.
|
||||
# @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
|
||||
|
|
|
@ -74,6 +74,11 @@
|
|||
@load protocols/modbus/track-memmap.bro
|
||||
@load protocols/mysql/software.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/detect-suspicious-orig.bro
|
||||
@load protocols/smtp/entities-excerpt.bro
|
||||
|
|
|
@ -23,6 +23,7 @@ TableType* string_set;
|
|||
TableType* string_array;
|
||||
TableType* count_set;
|
||||
VectorType* string_vec;
|
||||
VectorType* index_vec;
|
||||
VectorType* mime_matches;
|
||||
RecordType* mime_match;
|
||||
|
||||
|
@ -105,13 +106,6 @@ RecordType* pm_callit_request;
|
|||
|
||||
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* entropy_test_result;
|
||||
|
@ -331,6 +325,7 @@ void init_net_var()
|
|||
string_set = internal_type("string_set")->AsTableType();
|
||||
string_array = internal_type("string_array")->AsTableType();
|
||||
string_vec = internal_type("string_vec")->AsVectorType();
|
||||
index_vec = internal_type("index_vec")->AsVectorType();
|
||||
mime_match = internal_type("mime_match")->AsRecordType();
|
||||
mime_matches = internal_type("mime_matches")->AsVectorType();
|
||||
|
||||
|
@ -427,13 +422,6 @@ void init_net_var()
|
|||
|
||||
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();
|
||||
|
||||
entropy_test_result = internal_type("entropy_test_result")->AsRecordType();
|
||||
|
|
|
@ -26,6 +26,7 @@ extern TableType* string_set;
|
|||
extern TableType* string_array;
|
||||
extern TableType* count_set;
|
||||
extern VectorType* string_vec;
|
||||
extern VectorType* index_vec;
|
||||
extern VectorType* mime_matches;
|
||||
extern RecordType* mime_match;
|
||||
|
||||
|
@ -108,13 +109,6 @@ extern RecordType* pm_callit_request;
|
|||
|
||||
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* entropy_test_result;
|
||||
|
|
|
@ -12,6 +12,7 @@ add_subdirectory(file)
|
|||
add_subdirectory(finger)
|
||||
add_subdirectory(ftp)
|
||||
add_subdirectory(gnutella)
|
||||
add_subdirectory(gssapi)
|
||||
add_subdirectory(gtpv1)
|
||||
add_subdirectory(http)
|
||||
add_subdirectory(icmp)
|
||||
|
@ -26,6 +27,7 @@ add_subdirectory(modbus)
|
|||
add_subdirectory(mysql)
|
||||
add_subdirectory(ncp)
|
||||
add_subdirectory(netbios)
|
||||
add_subdirectory(ntlm)
|
||||
add_subdirectory(ntp)
|
||||
add_subdirectory(pia)
|
||||
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_cc(DCE_RPC.cc Plugin.cc)
|
||||
bro_plugin_bif(events.bif)
|
||||
bro_plugin_pac(dce_rpc.pac dce_rpc-protocol.pac dce_rpc-analyzer.pac epmapper.pac)
|
||||
bro_plugin_pac(dce_rpc_simple.pac dce_rpc-protocol.pac epmapper.pac)
|
||||
bro_plugin_bif(types.bif events.bif)
|
||||
bro_plugin_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()
|
||||
|
||||
|
|
|
@ -9,580 +9,52 @@
|
|||
using namespace std;
|
||||
|
||||
#include "DCE_RPC.h"
|
||||
#include "Sessions.h"
|
||||
|
||||
#include "analyzer/Manager.h"
|
||||
|
||||
#include "events.bif.h"
|
||||
|
||||
using namespace analyzer::dce_rpc;
|
||||
|
||||
#define xbyte(b, n) (((const u_char*) (b))[n])
|
||||
|
||||
#define extract_uint16(little_endian, bytes) \
|
||||
((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)
|
||||
DCE_RPC_Analyzer::DCE_RPC_Analyzer(Connection *conn)
|
||||
: tcp::TCP_ApplicationAnalyzer("DCE_RPC", conn)
|
||||
{
|
||||
session = new DCE_RPC_Session(this);
|
||||
speculative = arg_speculative;
|
||||
|
||||
AddSupportAnalyzer(new Contents_DCE_RPC_Analyzer(conn, true, session,
|
||||
speculative));
|
||||
AddSupportAnalyzer(new Contents_DCE_RPC_Analyzer(conn, false, session,
|
||||
speculative));
|
||||
interp = new binpac::DCE_RPC::DCE_RPC_Conn(this);
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
#include "analyzer/protocol/dce-rpc/events.bif.h"
|
||||
#include "IPAddr.h"
|
||||
|
||||
#include "dce_rpc_simple_pac.h"
|
||||
#include "dce_rpc_pac.h"
|
||||
|
||||
|
||||
namespace analyzer { namespace dce_rpc {
|
||||
|
||||
class UUID {
|
||||
/* class UUID {
|
||||
public:
|
||||
UUID();
|
||||
UUID(const u_char data[16]);
|
||||
|
@ -35,7 +35,7 @@ protected:
|
|||
string s;
|
||||
};
|
||||
|
||||
const char* uuid_to_string(const u_char* uuid_data);
|
||||
//const char* uuid_to_string(const u_char* uuid_data);
|
||||
|
||||
struct dce_rpc_endpoint_addr {
|
||||
// All fields are in host byteorder.
|
||||
|
@ -75,7 +75,7 @@ struct dce_rpc_endpoint_addr {
|
|||
|
||||
return string(buf);
|
||||
}
|
||||
};
|
||||
}; */
|
||||
|
||||
/*
|
||||
enum DCE_RPC_PTYPE {
|
||||
|
@ -88,6 +88,7 @@ enum DCE_RPC_PTYPE {
|
|||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DCE_RPC_HEADER_LENGTH 16
|
||||
|
||||
class DCE_RPC_Header {
|
||||
|
@ -125,22 +126,22 @@ public:
|
|||
{ 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 DeliverBind(const binpac::DCE_RPC::DCE_RPC_PDU* pdu);
|
||||
void DeliverRequest(const binpac::DCE_RPC::DCE_RPC_PDU* pdu);
|
||||
void DeliverResponse(const binpac::DCE_RPC::DCE_RPC_PDU* pdu);
|
||||
|
||||
void DeliverEpmapperRequest(
|
||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
||||
const binpac::DCE_RPC_Simple::DCE_RPC_Request* req);
|
||||
const binpac::DCE_RPC::DCE_RPC_PDU* pdu,
|
||||
const binpac::DCE_RPC::DCE_RPC_Request* req);
|
||||
void DeliverEpmapperResponse(
|
||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
||||
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp);
|
||||
const binpac::DCE_RPC::DCE_RPC_PDU* pdu,
|
||||
const binpac::DCE_RPC::DCE_RPC_Response* resp);
|
||||
void DeliverEpmapperMapResponse(
|
||||
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
|
||||
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp);
|
||||
const binpac::DCE_RPC::DCE_RPC_PDU* pdu,
|
||||
const binpac::DCE_RPC::DCE_RPC_Response* resp);
|
||||
|
||||
analyzer::Analyzer* analyzer;
|
||||
UUID if_uuid;
|
||||
UUID uuid;
|
||||
BifEnum::dce_rpc_if_id if_id;
|
||||
int opnum;
|
||||
struct {
|
||||
|
@ -172,20 +173,28 @@ protected:
|
|||
|
||||
DCE_RPC_Session* session;
|
||||
};
|
||||
*/
|
||||
|
||||
class DCE_RPC_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
DCE_RPC_Analyzer(Connection* conn, bool speculative = false);
|
||||
DCE_RPC_Analyzer(Connection* conn);
|
||||
~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)
|
||||
{ return new DCE_RPC_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
DCE_RPC_Session* session;
|
||||
bool speculative;
|
||||
binpac::DCE_RPC::DCE_RPC_Conn* interp;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif /* dce_rpc_h */
|
||||
|
|
|
@ -13,7 +13,6 @@ public:
|
|||
plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new ::analyzer::Component("DCE_RPC", ::analyzer::dce_rpc::DCE_RPC_Analyzer::Instantiate));
|
||||
AddComponent(new ::analyzer::Component("Contents_DCE_RPC", 0));
|
||||
|
||||
plugin::Configuration config;
|
||||
config.name = "Bro::DCE_RPC";
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
# DCE/RPC protocol data unit.
|
||||
|
||||
type DCE_RPC_PDU = record {
|
||||
# Set header's byteorder to little-endian (or big-endian) to
|
||||
# avoid cyclic dependency.
|
||||
header : DCE_RPC_Header;
|
||||
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
|
||||
refine connection DCE_RPC_Conn += {
|
||||
%member{
|
||||
map<uint16, uint16> cont_id_opnum_map;
|
||||
uint64 fid;
|
||||
%}
|
||||
|
||||
%init{
|
||||
fid=0;
|
||||
%}
|
||||
|
||||
connection DCE_RPC_Conn(bro_analyzer: BroAnalyzer) {
|
||||
upflow = DCE_RPC_Flow(true);
|
||||
downflow = DCE_RPC_Flow(false);
|
||||
function set_file_id(fid_in: uint64): bool
|
||||
%{
|
||||
fid = fid_in;
|
||||
return true;
|
||||
%}
|
||||
|
||||
function get_cont_id_opnum_map(cont_id: uint16): uint16
|
||||
%{
|
||||
|
@ -33,102 +26,162 @@ connection DCE_RPC_Conn(bro_analyzer: BroAnalyzer) {
|
|||
return true;
|
||||
%}
|
||||
|
||||
%member{
|
||||
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
|
||||
function proc_dce_rpc_pdu(pdu: DCE_RPC_PDU): 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;
|
||||
// If a whole pdu message parsed ok, let's confirm the protocol
|
||||
bro_analyzer()->ProtocolConfirmation();
|
||||
return true;
|
||||
%}
|
||||
|
||||
function reassembled_body(): const_bytestring
|
||||
function proc_dce_rpc_message(header: DCE_RPC_Header): bool
|
||||
%{
|
||||
return const_bytestring(
|
||||
frag_reassembler_.begin(),
|
||||
frag_reassembler_.end());
|
||||
if ( dce_rpc_message )
|
||||
{
|
||||
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
|
||||
%{
|
||||
$const_def{bind_elems = bind.p_context_elem};
|
||||
|
||||
if ( ${bind_elems.n_context_elem} > 1 ) {
|
||||
${connection.bro_analyzer}->Weird(
|
||||
"DCE_RPC_bind_to_multiple_interfaces");
|
||||
}
|
||||
|
||||
if ( dce_rpc_bind ) {
|
||||
if ( dce_rpc_bind )
|
||||
{
|
||||
// Go over the elements, each having a UUID
|
||||
for ( int i = 0; i < ${bind_elems.n_context_elem}; ++i ) {
|
||||
$const_def{if_uuid =
|
||||
bind_elems.p_cont_elem[i].abstract_syntax.if_uuid};
|
||||
$const_def{bind_elems = bind.context_list};
|
||||
for ( int i = 0; i < ${bind_elems.num_contexts}; ++i )
|
||||
{
|
||||
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
|
||||
BifEvent::generate_dce_rpc_bind(
|
||||
${connection.bro_analyzer},
|
||||
${connection.bro_analyzer}->Conn(),
|
||||
bytestring_to_val(${if_uuid}));
|
||||
|
||||
// Set the connection's UUID
|
||||
// ${connection}->set_uuid(${if_uuid});
|
||||
// Queue the event
|
||||
BifEvent::generate_dce_rpc_bind(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
fid,
|
||||
bytestring_to_val(${uuid}),
|
||||
${ver_major},
|
||||
${ver_minor});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
%{
|
||||
if ( dce_rpc_request )
|
||||
{
|
||||
BifEvent::generate_dce_rpc_request(
|
||||
${connection.bro_analyzer},
|
||||
${connection.bro_analyzer}->Conn(),
|
||||
${req.opnum},
|
||||
bytestring_to_val(${req.stub}));
|
||||
BifEvent::generate_dce_rpc_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
fid,
|
||||
${req.opnum},
|
||||
${req.stub}.length());
|
||||
}
|
||||
|
||||
${connection}->set_cont_id_opnum_map(${req.p_cont_id},
|
||||
${req.opnum});
|
||||
|
||||
set_cont_id_opnum_map(${req.context_id},
|
||||
${req.opnum});
|
||||
return true;
|
||||
%}
|
||||
|
||||
# Response.
|
||||
function process_dce_rpc_response(resp: DCE_RPC_Response): bool
|
||||
%{
|
||||
if ( dce_rpc_response )
|
||||
{
|
||||
BifEvent::generate_dce_rpc_response(
|
||||
${connection.bro_analyzer},
|
||||
${connection.bro_analyzer}->Conn(),
|
||||
${connection}->get_cont_id_opnum_map(${resp.p_cont_id}),
|
||||
bytestring_to_val(${resp.stub}));
|
||||
BifEvent::generate_dce_rpc_response(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
fid,
|
||||
get_cont_id_opnum_map(${resp.context_id}),
|
||||
${resp.stub}.length());
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
50
src/analyzer/protocol/dce-rpc/dce_rpc-auth.pac
Normal file
50
src/analyzer/protocol/dce-rpc/dce_rpc-auth.pac
Normal file
|
@ -0,0 +1,50 @@
|
|||
%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 )
|
||||
delete gssapi;
|
||||
if ( ntlm )
|
||||
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 context_handle = record {
|
||||
cxt_attributes: uint32;
|
||||
cxt_uuid: uuid;
|
||||
attrs : uint32;
|
||||
uuid : bytestring &length = 16;
|
||||
};
|
||||
|
||||
type rpc_if_id_t = record {
|
||||
if_uuid : uuid;
|
||||
vers_major : uint16;
|
||||
vers_minor : uint16;
|
||||
};
|
||||
type DCE_RPC_PDU(is_orig: bool) = record {
|
||||
# Set header's byteorder to little-endian (or big-endian) to
|
||||
# avoid cyclic dependency.
|
||||
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 {
|
||||
intchar : uint8;
|
||||
floatspec : uint8;
|
||||
reserved : padding[2];
|
||||
intchar : uint8;
|
||||
floatspec : uint8;
|
||||
reserved : padding[2];
|
||||
} &let {
|
||||
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.
|
||||
|
||||
type DCE_RPC_Header = record {
|
||||
rpc_vers : uint8 &check(rpc_vers == 5);
|
||||
rpc_vers_minor : uint8;
|
||||
PTYPE : uint8;
|
||||
pfc_flags : uint8;
|
||||
packed_drep : NDR_Format;
|
||||
frag_length : uint16;
|
||||
auth_length : uint16;
|
||||
call_id : uint32;
|
||||
type DCE_RPC_Header(is_orig: bool) = record {
|
||||
rpc_vers : uint8 &check(rpc_vers == 5);
|
||||
rpc_vers_minor : uint8;
|
||||
PTYPE : uint8;
|
||||
pfc_flags : uint8;
|
||||
packed_drep : NDR_Format;
|
||||
frag_length : uint16;
|
||||
auth_length : uint16;
|
||||
call_id : uint32;
|
||||
} &let {
|
||||
frag = pfc_flags & 4;
|
||||
lastfrag = (! frag) || (pfc_flags & 2);
|
||||
} &byteorder = packed_drep.byteorder;
|
||||
|
||||
type p_context_id_t = uint16;
|
||||
|
||||
type p_syntax_id_t = record {
|
||||
if_uuid : uuid;
|
||||
if_version : uint32;
|
||||
type Syntax = record {
|
||||
uuid : bytestring &length = 16;
|
||||
ver_major : uint16;
|
||||
ver_minor : uint16;
|
||||
};
|
||||
|
||||
type p_cont_elem_t = record {
|
||||
p_cont_id : p_context_id_t;
|
||||
n_transfer_syn : uint8;
|
||||
reserved : padding[1];
|
||||
abstract_syntax : p_syntax_id_t;
|
||||
transfer_syntaxes : p_syntax_id_t[n_transfer_syn];
|
||||
type ContextRequest = record {
|
||||
id : uint16;
|
||||
num_syntaxes : uint8;
|
||||
reserved : padding[1];
|
||||
abstract_syntax : Syntax;
|
||||
transfer_syntaxes : Syntax[num_syntaxes];
|
||||
};
|
||||
|
||||
type p_cont_list_t = record {
|
||||
n_context_elem : uint8;
|
||||
reserved : padding[3];
|
||||
p_cont_elem : p_cont_elem_t[n_context_elem];
|
||||
type ContextReply = record {
|
||||
ack_result : uint16;
|
||||
ack_reason : uint16;
|
||||
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 {
|
||||
max_xmit_frag : uint16;
|
||||
max_recv_frag : uint16;
|
||||
assoc_group_id : uint32;
|
||||
p_context_elem : p_cont_list_t;
|
||||
max_xmit_frag : uint16;
|
||||
max_recv_frag : uint16;
|
||||
assoc_group_id : uint32;
|
||||
context_list : ContextList(1);
|
||||
};
|
||||
|
||||
type DCE_RPC_AlterContext = record {
|
||||
max_xmit_frag : uint16;
|
||||
max_recv_frag : uint16;
|
||||
assoc_group_id : uint32;
|
||||
p_context_elem : p_cont_list_t;
|
||||
type DCE_RPC_Bind_Ack = record {
|
||||
max_xmit_frag : uint16;
|
||||
max_recv_frag : uint16;
|
||||
assoc_group_id : uint32;
|
||||
sec_addr_length : uint16;
|
||||
sec_addr : bytestring &length=sec_addr_length;
|
||||
pad : padding align 4;
|
||||
contexts : ContextList(0);
|
||||
};
|
||||
|
||||
type DCE_RPC_Request = record {
|
||||
alloc_hint : uint32;
|
||||
p_cont_id : p_context_id_t;
|
||||
opnum : uint16;
|
||||
# object : uuid;
|
||||
# stub_pad_0 : padding align 8;
|
||||
stub : bytestring &restofdata;
|
||||
alloc_hint : uint32;
|
||||
context_id : uint16;
|
||||
opnum : uint16;
|
||||
# object : uuid;
|
||||
# stub_pad_0 : padding align 8;
|
||||
stub : bytestring &restofdata;
|
||||
};
|
||||
|
||||
type DCE_RPC_Response = record {
|
||||
alloc_hint : uint32;
|
||||
p_cont_id : p_context_id_t;
|
||||
cancel_count : uint8;
|
||||
reserved : uint8;
|
||||
# stub_pad_0 : padding align 8;
|
||||
stub : bytestring &restofdata;
|
||||
alloc_hint : uint32;
|
||||
context_id : uint16;
|
||||
cancel_count : uint8;
|
||||
reserved : uint8;
|
||||
# stub_pad_0 : padding align 8;
|
||||
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 {
|
||||
DCE_RPC_BIND -> bind : DCE_RPC_Bind;
|
||||
DCE_RPC_REQUEST -> request : DCE_RPC_Request;
|
||||
DCE_RPC_RESPONSE -> response : DCE_RPC_Response;
|
||||
default -> other : bytestring &restofdata;
|
||||
DCE_RPC_BIND -> bind : DCE_RPC_Bind;
|
||||
DCE_RPC_BIND_ACK -> bind_ack : DCE_RPC_Bind_Ack;
|
||||
DCE_RPC_REQUEST -> request : DCE_RPC_Request;
|
||||
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];
|
||||
|
||||
%include epmapper.pac
|
||||
type DCE_RPC_Auth(header: DCE_RPC_Header) = record {
|
||||
type : uint8;
|
||||
level : uint8;
|
||||
pad_len : uint8;
|
||||
reserved : uint8;
|
||||
context_id : uint32;
|
||||
blob : bytestring &length=header.auth_length;
|
||||
};
|
||||
|
|
|
@ -2,13 +2,27 @@
|
|||
%include bro.pac
|
||||
|
||||
%extern{
|
||||
#include "types.bif.h"
|
||||
#include "events.bif.h"
|
||||
%}
|
||||
|
||||
analyzer DCE_RPC withcontext {
|
||||
connection: DCE_RPC_Conn;
|
||||
flow: DCE_RPC_Flow;
|
||||
connection : DCE_RPC_Conn;
|
||||
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
|
||||
|
||||
# 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-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
|
||||
## dce_rpc_response rpc_timeout
|
||||
## c: The connection.
|
||||
##
|
||||
## .. 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 dce_rpc_message%(c: connection, is_orig: bool, ptype: dce_rpc_ptype, msg: string%);
|
||||
## is_orig: True if the message was sent by the originator of the TCP connection.
|
||||
##
|
||||
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||
## DCE-RPC was not transported over a pipe.
|
||||
##
|
||||
## 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
|
||||
## dce_rpc_response rpc_timeout
|
||||
## c: The connection.
|
||||
##
|
||||
## .. 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 dce_rpc_bind%(c: connection, uuid: string%);
|
||||
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||
## DCE-RPC was not transported over a pipe.
|
||||
##
|
||||
## uuid: The string interpretted uuid of the endpoint being requested.
|
||||
##
|
||||
## 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
|
||||
## dce_rpc_response rpc_timeout
|
||||
## c: The connection.
|
||||
##
|
||||
## .. 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 dce_rpc_request%(c: connection, opnum: count, stub: string%);
|
||||
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||
## DCE-RPC was not transported over a pipe.
|
||||
##
|
||||
## sec_addr: Secondary address for the ack.
|
||||
##
|
||||
## .. 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
|
||||
## dce_rpc_request rpc_timeout
|
||||
## c: The connection.
|
||||
##
|
||||
## .. 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 dce_rpc_response%(c: connection, opnum: count, stub: string%);
|
||||
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||
## DCE-RPC was not transported over a pipe.
|
||||
##
|
||||
## opnum: Number of the RPC operation.
|
||||
##
|
||||
## 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
|
||||
## dce_rpc_request dce_rpc_response rpc_timeout
|
||||
## c: The connection.
|
||||
##
|
||||
## .. 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 epm_map_response%(c: connection, uuid: string, p: port, h: addr%);
|
||||
## fid: File ID of the PIPE that carried the DCE-RPC message. Zero will be used if the
|
||||
## DCE-RPC was not transported over a pipe.
|
||||
##
|
||||
## opnum: Number of the RPC operation.
|
||||
##
|
||||
## 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
|
0
src/analyzer/protocol/gssapi/types.bif
Normal file
0
src/analyzer/protocol/gssapi/types.bif
Normal file
|
@ -47,11 +47,10 @@ NetbiosDGM_RawMsgHdr::NetbiosDGM_RawMsgHdr(const u_char*& data, int& len)
|
|||
}
|
||||
|
||||
|
||||
NetbiosSSN_Interpreter::NetbiosSSN_Interpreter(analyzer::Analyzer* arg_analyzer,
|
||||
smb::SMB_Session* arg_smb_session)
|
||||
NetbiosSSN_Interpreter::NetbiosSSN_Interpreter(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,
|
||||
|
@ -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 is_query)
|
||||
{
|
||||
if ( smb_session )
|
||||
{
|
||||
smb_session->Deliver(is_query, len, data);
|
||||
return 0;
|
||||
}
|
||||
//if ( smb_session )
|
||||
// {
|
||||
// smb_session->Deliver(is_query, len, data);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,8 +131,8 @@ int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
|
|||
delete srcname;
|
||||
delete dstname;
|
||||
|
||||
if ( smb_session )
|
||||
smb_session->Deliver(is_query, len, data);
|
||||
//if ( smb_session )
|
||||
// smb_session->Deliver(is_query, len, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -188,12 +187,12 @@ int NetbiosSSN_Interpreter::ParseSessionMsg(const u_char* data, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ( smb_session )
|
||||
{
|
||||
smb_session->Deliver(is_query, len, data);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
//if ( smb_session )
|
||||
// {
|
||||
// smb_session->Deliver(is_query, len, data);
|
||||
// return 0;
|
||||
// }
|
||||
//else
|
||||
{
|
||||
analyzer->Weird("no_smb_session_using_parsesambamsg");
|
||||
data += 4;
|
||||
|
@ -458,8 +457,8 @@ void Contents_NetbiosSSN::DeliverStream(int len, const u_char* data, bool orig)
|
|||
NetbiosSSN_Analyzer::NetbiosSSN_Analyzer(Connection* conn)
|
||||
: tcp::TCP_ApplicationAnalyzer("NETBIOS", conn)
|
||||
{
|
||||
smb_session = new smb::SMB_Session(this);
|
||||
interp = new NetbiosSSN_Interpreter(this, smb_session);
|
||||
//smb_session = new SMB_Session(this);
|
||||
interp = new NetbiosSSN_Interpreter(this);
|
||||
orig_netbios = resp_netbios = 0;
|
||||
did_session_done = 0;
|
||||
|
||||
|
@ -481,7 +480,7 @@ NetbiosSSN_Analyzer::NetbiosSSN_Analyzer(Connection* conn)
|
|||
NetbiosSSN_Analyzer::~NetbiosSSN_Analyzer()
|
||||
{
|
||||
delete interp;
|
||||
delete smb_session;
|
||||
//delete smb_session;
|
||||
}
|
||||
|
||||
void NetbiosSSN_Analyzer::Done()
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "analyzer/protocol/udp/UDP.h"
|
||||
#include "analyzer/protocol/tcp/TCP.h"
|
||||
#include "analyzer/protocol/smb/SMB.h"
|
||||
//#include "analyzer/protocol/smb/SMB.h"
|
||||
|
||||
namespace analyzer { namespace netbios_ssn {
|
||||
|
||||
|
@ -64,7 +64,7 @@ struct NetbiosDGM_RawMsgHdr {
|
|||
|
||||
class NetbiosSSN_Interpreter {
|
||||
public:
|
||||
NetbiosSSN_Interpreter(analyzer::Analyzer* analyzer, smb::SMB_Session* smb_session);
|
||||
NetbiosSSN_Interpreter(Analyzer* analyzer);
|
||||
|
||||
int ParseMessage(unsigned int type, unsigned int flags,
|
||||
const u_char* data, int len, int is_query);
|
||||
|
@ -99,8 +99,8 @@ protected:
|
|||
u_char*& xname, int& xlen);
|
||||
|
||||
protected:
|
||||
analyzer::Analyzer* analyzer;
|
||||
smb::SMB_Session* smb_session;
|
||||
Analyzer* analyzer;
|
||||
//SMB_Session* smb_session;
|
||||
};
|
||||
|
||||
|
||||
|
@ -124,7 +124,7 @@ public:
|
|||
NetbiosSSN_State State() const { return state; }
|
||||
|
||||
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;
|
||||
|
||||
|
@ -144,22 +144,22 @@ public:
|
|||
NetbiosSSN_Analyzer(Connection* conn);
|
||||
~NetbiosSSN_Analyzer();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverPacket(int len, const u_char* data, bool orig,
|
||||
uint64 seq, const IP_Hdr* ip, int caplen);
|
||||
void Done() override;
|
||||
void DeliverPacket(int len, const u_char* data, bool orig,
|
||||
uint64 seq, const IP_Hdr* ip, int caplen) override;
|
||||
|
||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||
{ return new NetbiosSSN_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
virtual void ConnectionClosed(tcp::TCP_Endpoint* endpoint,
|
||||
tcp::TCP_Endpoint* peer, int gen_event);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
void ConnectionClosed(tcp::TCP_Endpoint* endpoint,
|
||||
tcp::TCP_Endpoint* peer, int gen_event) override;
|
||||
void EndpointEOF(bool is_orig) override;
|
||||
|
||||
void ExpireTimer(double t);
|
||||
|
||||
NetbiosSSN_Interpreter* interp;
|
||||
smb::SMB_Session* smb_session;
|
||||
//SMB_Session* smb_session;
|
||||
Contents_NetbiosSSN* orig_netbios;
|
||||
Contents_NetbiosSSN* resp_netbios;
|
||||
int did_session_done;
|
||||
|
@ -168,6 +168,6 @@ protected:
|
|||
// FIXME: Doesn't really fit into new analyzer structure. What to do?
|
||||
int IsReuse(double t, const u_char* pkt);
|
||||
|
||||
} } // namespace analyzer::*
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif
|
||||
|
|
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{
|
||||
#include "ConvertUTF.h"
|
||||
#include "file_analysis/Manager.h"
|
||||
#include "types.bif.h"
|
||||
%}
|
||||
|
||||
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
|
||||
%{
|
||||
if ( rdp_connect_request )
|
||||
|
@ -125,18 +80,18 @@ refine flow RDP_Flow += {
|
|||
ccd->Assign(5, new Val(${ccore.sas_sequence}, TYPE_COUNT));
|
||||
ccd->Assign(6, new Val(${ccore.keyboard_layout}, 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(10, new Val(${ccore.keyboard_sub}, 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(14, new Val(${ccore.client_product_id}, 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(17, new Val(${ccore.supported_color_depths}, TYPE_COUNT));
|
||||
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(),
|
||||
connection()->bro_analyzer()->Conn(),
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
include(BroPlugin)
|
||||
|
||||
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_cc(SMB.cc Plugin.cc)
|
||||
bro_plugin_bif(events.bif)
|
||||
bro_plugin_pac(smb.pac smb-protocol.pac smb-pipe.pac smb-mailslot.pac)
|
||||
bro_plugin_bif(
|
||||
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()
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,3 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef ANALYZER_PROTOCOL_SMB_SMB_H
|
||||
#define ANALYZER_PROTOCOL_SMB_SMB_H
|
||||
|
||||
|
@ -7,196 +5,70 @@
|
|||
// Reference: http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf
|
||||
|
||||
#include "analyzer/protocol/tcp/TCP.h"
|
||||
#include "analyzer/protocol/dce-rpc/DCE_RPC.h"
|
||||
#include "analyzer/protocol/rpc/RPC.h"
|
||||
#include "smb_pac.h"
|
||||
|
||||
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(Connection* conn, bool orig);
|
||||
~Contents_SMB();
|
||||
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||
|
||||
protected:
|
||||
void InitMsgBuf();
|
||||
typedef enum {
|
||||
WAIT_FOR_HDR,
|
||||
WAIT_FOR_DATA
|
||||
} state_t;
|
||||
typedef enum {
|
||||
NEED_RESYNC,
|
||||
INSYNC,
|
||||
} resync_state_t;
|
||||
void Init() override;
|
||||
virtual bool CheckResync(int& len, const u_char*& data, bool orig);
|
||||
void Undelivered(uint64 seq, int len, bool orig) override;
|
||||
virtual void NeedResync() {
|
||||
resync_state = NEED_RESYNC;
|
||||
state = WAIT_FOR_HDR;
|
||||
}
|
||||
|
||||
bool HasSMBHeader(int len, const u_char* data);
|
||||
|
||||
void DeliverSMB(int len, const u_char* data);
|
||||
|
||||
SMB_Session* smb_session;
|
||||
u_char dshdr[4];
|
||||
u_char* msg_buf;
|
||||
rpc::RPC_Reasm_Buffer hdr_buf; // Reassembles the NetBIOS length and glue.
|
||||
rpc::RPC_Reasm_Buffer msg_buf; // Reassembles the SMB message.
|
||||
int msg_len;
|
||||
int buf_n; // number of bytes in msg_buf
|
||||
int buf_len; // size off msg_buf
|
||||
int msg_type;
|
||||
double first_time; // timestamp of first packet of current message
|
||||
double last_time; // timestamp of last pakcet of current message
|
||||
state_t state;
|
||||
resync_state_t resync_state;
|
||||
};
|
||||
|
||||
class SMB_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
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;
|
||||
|
||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||
{ return new SMB_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
SMB_Session* smb_session;
|
||||
Contents_SMB* o_smb;
|
||||
Contents_SMB* r_smb;
|
||||
binpac::SMB::SMB_Conn* interp;
|
||||
|
||||
// Count the number of chunks received by the analyzer
|
||||
// but only used to count the first few.
|
||||
uint8 chunks;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif
|
||||
|
|
|
@ -73,3 +73,5 @@ 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)
|
||||
SMB_COMMAND(SMB_COM_INVALID, 0xFE)
|
||||
SMB_COMMAND(SMB_COM_NO_ANDX_COMMAND, 0xFF)
|
|
@ -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%);
|
||||
|
69
src/analyzer/protocol/smb/pipe-mssql-tds.pac
Normal file
69
src/analyzer/protocol/smb/pipe-mssql-tds.pac
Normal file
|
@ -0,0 +1,69 @@
|
|||
# Packet Documentation
|
||||
# http://msdn.microsoft.com/en-us/library/dd305039.aspx
|
||||
|
||||
type TDS_PDU = record {
|
||||
header: TDS_Header;
|
||||
message: TDS_Message(header);
|
||||
} &byteorder=bigendian &length=header.len;
|
||||
|
||||
type TDS_Header = record {
|
||||
message_type: uint8; # http://msdn.microsoft.com/en-us/library/dd304214.aspx
|
||||
status: uint8; # http://msdn.microsoft.com/en-us/library/dd358342.aspx
|
||||
len: uint16;
|
||||
spid: uint16; # process id. server needs to send it. client can too.
|
||||
packet_id: uint8;
|
||||
window: uint8; # should be 0
|
||||
} &let {
|
||||
eom: bool = ((status>>1) & 1) == 1;
|
||||
};
|
||||
|
||||
type TDS_Message(h: TDS_Header) = case h.message_type of {
|
||||
0x01 -> sql_batch: SQL_Batch(h);
|
||||
# 0x04 -> token_stream: TDS_Token[];
|
||||
default -> blah : bytestring &transient &restofdata;
|
||||
};
|
||||
|
||||
function proc_testing(a: SQL_Batch): bool
|
||||
%{
|
||||
printf("%.6f query: %s\n", network_time(), smb2_string2stringval(${a.query})->CheckString());
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
type SQL_Batch(h: TDS_Header) = record {
|
||||
#total_len : uint32;
|
||||
#
|
||||
#header_len : uint32;
|
||||
#header_type : uint16;
|
||||
#trans_descriptor : uint64;
|
||||
#outstanding_requests : uint32;
|
||||
|
||||
#query: SMB2_string(total_len-header_len);
|
||||
query: SMB2_string(h.len-8);
|
||||
} &let {
|
||||
proc: bool = proc_testing(this);
|
||||
};
|
||||
|
||||
|
||||
type TDS_Token = record {
|
||||
token_type: uint8;
|
||||
token: case token_type of {
|
||||
0xE3 -> envchange : TDS_Token_EnvChange;
|
||||
0xAB -> info : TDS_Token_Info;
|
||||
default -> blah : bytestring &transient &restofdata;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
type TDS_Token_EnvChange = record {
|
||||
len: uint16;
|
||||
envchange_type: uint8;
|
||||
new_value: bytestring &length=len-2;
|
||||
#tab: RE/\x09/;
|
||||
#old_value: bytestring &length=
|
||||
};
|
||||
|
||||
type TDS_Token_Info = record {
|
||||
|
||||
};
|
||||
|
280
src/analyzer/protocol/smb/smb-common.pac
Normal file
280
src/analyzer/protocol/smb/smb-common.pac
Normal file
|
@ -0,0 +1,280 @@
|
|||
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
|
||||
%{
|
||||
// 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;
|
||||
// }
|
||||
//
|
||||
//if ( bytestring_caseprefix( extract_string(name), "\\MAILSLOT\\LANMAN" ) )
|
||||
// {
|
||||
// return SMB_MAILSLOT_LANMAN;
|
||||
// //return SMB_MAILSLOT_BROWSE;
|
||||
// }
|
||||
//
|
||||
//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 deprecated packet format that handles
|
||||
// * old windows logon
|
||||
// */
|
||||
// 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;
|
||||
}
|
||||
|
||||
//if ( setup_count == 3 ||
|
||||
// bytestring_caseprefix( extract_string(name), "\\MAILSLOT\\" ) )
|
||||
// {
|
||||
// return SMB_MAILSLOT_BROWSE;
|
||||
// }
|
||||
|
||||
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 {
|
||||
HOST_ANNOUNCEMENT = 1,
|
||||
ANNOUCEMENT_REQUEST = 2,
|
||||
|
|
|
@ -1,19 +1,56 @@
|
|||
# this won't work correctly yet, since sometimes the parameters
|
||||
# field in the transaction takes up all of the data field
|
||||
%extern{
|
||||
#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
|
||||
# not the real length of the rest of the packet
|
||||
data : bytestring &restofdata;
|
||||
%cleanup{
|
||||
// Iterate all of the analyzers and destroy them.
|
||||
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;
|
||||
param_desc : SMB_string(unicode, offsetof(param_desc) );
|
||||
data_desc : SMB_string(unicode, offsetof(data_desc) );
|
||||
data : bytestring &restofdata;
|
||||
function set_tree_is_pipe(tree_id: uint16, is_pipe: bool): bool
|
||||
%{
|
||||
tree_is_pipe_map[tree_id] = is_pipe;
|
||||
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,135 @@
|
|||
%include bro.pac
|
||||
|
||||
%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_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-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);
|
||||
};
|
103
src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac
Normal file
103
src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac
Normal file
|
@ -0,0 +1,103 @@
|
|||
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 )
|
||||
{
|
||||
// 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)) &length=name_length;
|
||||
|
||||
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;
|
79
src/analyzer/protocol/smb/smb1-com-open-andx.pcap
Normal file
79
src/analyzer/protocol/smb/smb1-com-open-andx.pcap
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Copyright (c) Broala LLC. All Rights Reserved. No use or distribution without permission.
|
||||
|
||||
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