mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
SMB & NTLM analyzers.
This commit is contained in:
parent
3cea6ab1eb
commit
6a34de5dd8
84 changed files with 8133 additions and 1428 deletions
|
@ -2235,83 +2235,476 @@ 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 SMB;
|
||||
|
||||
## 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`).
|
||||
export {
|
||||
## MAC times for a file.
|
||||
type SMB::MACTimes: record {
|
||||
modified : time &log;
|
||||
accessed : time &log;
|
||||
created : time &log;
|
||||
changed : time &log;
|
||||
} &log;
|
||||
|
||||
type SMB::NTLMVersion: 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;
|
||||
};
|
||||
|
||||
type SMB::NTLMNegotiateFlags: 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 SMB::NTLMNegotiate: record {
|
||||
## The negotiate flags
|
||||
flags : SMB::NTLMNegotiateFlags;
|
||||
## 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 : SMB::NTLMVersion &optional;
|
||||
};
|
||||
|
||||
type SMB::NTLMAVs: 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
|
||||
## mess achine 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 SMB::NTLMChallenge: record {
|
||||
## The negotiate flags
|
||||
flags : SMB::NTLMNegotiateFlags;
|
||||
## 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 : SMB::NTLMVersion &optional;
|
||||
## Attribute-value pairs specified by the server
|
||||
target_info : SMB::NTLMAVs &optional;
|
||||
};
|
||||
|
||||
type SMB::NTLMAuthenticate: record {
|
||||
## The negotiate flags
|
||||
flags : SMB::NTLMNegotiateFlags;
|
||||
## 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 : SMB::NTLMVersion &optional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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; ##< TODO.
|
||||
tid: count; ##< Tree ID.
|
||||
pid: count; ##< Process ID.
|
||||
uid: count; ##< User ID.
|
||||
mid: count; ##< TODO.
|
||||
};
|
||||
mid: count; ##< Multiplex ID.
|
||||
};
|
||||
|
||||
## 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 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 {
|
||||
## Count of parameter words (should be 1)
|
||||
word_count : count;
|
||||
## 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;
|
||||
};
|
||||
|
||||
|
||||
## 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 {
|
||||
module SMB2;
|
||||
|
||||
export {
|
||||
type SMB2::Header: record {
|
||||
credit_charge: count;
|
||||
status: count;
|
||||
command: count;
|
||||
credits: count;
|
||||
flags: count;
|
||||
password: string;
|
||||
path: string;
|
||||
service: string;
|
||||
};
|
||||
message_id: count;
|
||||
process_id: count;
|
||||
tree_id: count;
|
||||
session_id: count;
|
||||
signature: string;
|
||||
};
|
||||
|
||||
## Deprecated.
|
||||
##
|
||||
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere
|
||||
## else.
|
||||
type smb_negotiate : table[count] of 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::TreeConnectResponse: record {
|
||||
share_type: count;
|
||||
};
|
||||
}
|
||||
|
||||
module GLOBAL;
|
||||
|
||||
## A list of router addresses offered by a DHCP server.
|
||||
##
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
@load base/protocols/modbus
|
||||
@load base/protocols/pop3
|
||||
@load base/protocols/radius
|
||||
@load base/protocols/smb
|
||||
@load base/protocols/snmp
|
||||
@load base/protocols/smtp
|
||||
@load base/protocols/socks
|
||||
|
|
8
scripts/base/protocols/smb/__load__.bro
Normal file
8
scripts/base/protocols/smb/__load__.bro
Normal file
|
@ -0,0 +1,8 @@
|
|||
@load ./consts
|
||||
@load ./const-dos-error
|
||||
@load ./const-nt-status
|
||||
@load ./main
|
||||
@load ./pipe
|
||||
@load ./smb1-main
|
||||
@load ./smb2-main
|
||||
@load ./files
|
131
scripts/base/protocols/smb/const-dos-error.bro
Normal file
131
scripts/base/protocols/smb/const-dos-error.bro
Normal file
|
@ -0,0 +1,131 @@
|
|||
# DOS error codes.
|
||||
|
||||
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."],
|
||||
};
|
1792
scripts/base/protocols/smb/const-nt-status.bro
Normal file
1792
scripts/base/protocols/smb/const-nt-status.bro
Normal file
File diff suppressed because it is too large
Load diff
130
scripts/base/protocols/smb/consts.bro
Normal file
130
scripts/base/protocols/smb/consts.bro
Normal file
|
@ -0,0 +1,130 @@
|
|||
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]; };
|
||||
}
|
||||
|
||||
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); };
|
||||
}
|
||||
|
||||
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); };
|
||||
}
|
63
scripts/base/protocols/smb/files.bro
Normal file
63
scripts/base/protocols/smb/files.bro
Normal file
|
@ -0,0 +1,63 @@
|
|||
@load base/frameworks/files
|
||||
|
||||
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?$current_file &&
|
||||
((c$smb$current_file?$name && c$smb$current_file$name !in pipe_names) ||
|
||||
c$smb$current_file?$path)) )
|
||||
{
|
||||
# TODO: figure out what are the cases where this happens.
|
||||
return "";
|
||||
}
|
||||
|
||||
local current_file = c$smb$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 = current_file?$times ? current_file$times$modified : double_to_time(0.0);
|
||||
return 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 && info$smb?$current_file && info$smb$current_file?$name )
|
||||
return info$smb$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 && c$smb?$current_file )
|
||||
{
|
||||
c$smb$current_file$fuid = f$id;
|
||||
|
||||
if ( c$smb$current_file?$name )
|
||||
f$info$filename = c$smb$current_file$name;
|
||||
}
|
||||
}
|
199
scripts/base/protocols/smb/main.bro
Normal file
199
scripts/base/protocols/smb/main.bro
Normal file
|
@ -0,0 +1,199 @@
|
|||
module SMB;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += {
|
||||
CMD_LOG,
|
||||
MAPPING_LOG,
|
||||
FILES_LOG
|
||||
};
|
||||
|
||||
## Abstracted actions for SMB file actions.
|
||||
type FileAction: enum {
|
||||
FILE_READ,
|
||||
FILE_WRITE,
|
||||
FILE_OPEN,
|
||||
FILE_CLOSE,
|
||||
FILE_UNKNOWN,
|
||||
};
|
||||
|
||||
const logged_file_actions: set[FileAction] = {
|
||||
FILE_OPEN,
|
||||
FILE_READ,
|
||||
FILE_WRITE,
|
||||
};
|
||||
|
||||
## 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",
|
||||
};
|
||||
|
||||
type FileInfo: record {
|
||||
## Time when the file was first discovered.
|
||||
ts : time &log;
|
||||
uid : string &log;
|
||||
id : conn_id &log;
|
||||
fuid : string &log;
|
||||
|
||||
## Action this log record represents.
|
||||
action : FileAction &log &default=FILE_UNKNOWN;
|
||||
|
||||
## 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;
|
||||
};
|
||||
|
||||
type TreeInfo: record {
|
||||
## Time when the tree was mapped.
|
||||
ts : time &log &optional;
|
||||
|
||||
uid : string &log;
|
||||
id : conn_id &log;
|
||||
|
||||
## Name of the tree path.
|
||||
path : string &log &optional;
|
||||
service : string &log &optional;
|
||||
native_file_system : string &log &optional;
|
||||
|
||||
## If this is SMB2, a share type will be included.
|
||||
share_type : string &log &optional;
|
||||
};
|
||||
|
||||
type CmdInfo: record {
|
||||
## The command.
|
||||
command : string &optional;
|
||||
|
||||
## If the command referenced a file, store it here.
|
||||
referenced_file : FileInfo &optional;
|
||||
## If the command referenced a tree, store it here.
|
||||
referenced_tree : TreeInfo &optional;
|
||||
};
|
||||
|
||||
type Info: record {
|
||||
ts: time &log;
|
||||
uid: string &log;
|
||||
id: conn_id &log;
|
||||
|
||||
## Version of SMB for the command.
|
||||
version: string &log;
|
||||
|
||||
## Command sent by the client.
|
||||
command: string &log &optional;
|
||||
|
||||
## Server reply to the client's command
|
||||
status: 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 negotiated dialect for the connection.
|
||||
dialect: string &log &optional;
|
||||
|
||||
## Round trip time from the request to the response.
|
||||
rtt: interval &log &optional;
|
||||
|
||||
## 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;
|
||||
};
|
||||
|
||||
redef record connection += {
|
||||
smb : Info &optional;
|
||||
};
|
||||
|
||||
## This is an internally used function.
|
||||
const set_current_file: function(smb: Info, file_id: count) &redef;
|
||||
|
||||
## This is an internally used function.
|
||||
const write_file_log: function(f: FileInfo) &redef;
|
||||
}
|
||||
|
||||
redef record connection += {
|
||||
smb_pending_cmds : table[count, count] of Info &default=table();
|
||||
};
|
||||
|
||||
redef record FileInfo += {
|
||||
## ID referencing this file.
|
||||
fid : count &optional;
|
||||
|
||||
## Maintain a reference to the file record.
|
||||
f : fa_file &optional;
|
||||
};
|
||||
|
||||
const ports = { 139/tcp, 445/tcp };
|
||||
redef likely_server_ports += { ports };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(CMD_LOG, [$columns=SMB::Info]);
|
||||
Log::create_stream(FILES_LOG, [$columns=SMB::FileInfo]);
|
||||
Log::create_stream(MAPPING_LOG, [$columns=SMB::TreeInfo]);
|
||||
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SMB, ports);
|
||||
}
|
||||
|
||||
function set_current_file(smb: Info, file_id: count)
|
||||
{
|
||||
if ( file_id !in smb$fid_map )
|
||||
{
|
||||
smb$fid_map[file_id] = smb$current_cmd$referenced_file;
|
||||
smb$fid_map[file_id]$fid = file_id;
|
||||
}
|
||||
|
||||
smb$current_file = smb$fid_map[file_id];
|
||||
}
|
||||
|
||||
function write_file_log(f: FileInfo)
|
||||
{
|
||||
if ( f?$name &&
|
||||
f$name !in pipe_names &&
|
||||
f$action in logged_file_actions )
|
||||
{
|
||||
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 && c$smb?$current_file)
|
||||
{
|
||||
write_file_log(c$smb$current_file);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
59
scripts/base/protocols/smb/pipe.bro
Normal file
59
scripts/base/protocols/smb/pipe.bro
Normal file
|
@ -0,0 +1,59 @@
|
|||
module SMB;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += {
|
||||
ATSVC_LOG,
|
||||
};
|
||||
|
||||
type ATSvcInfo: record {
|
||||
## Time of the request
|
||||
ts : time &log;
|
||||
## UID of the connection
|
||||
uid : string &log;
|
||||
## Connection info
|
||||
id : conn_id &log;
|
||||
## Command (add, enum, delete, etc.)
|
||||
command : string &log;
|
||||
## Argument
|
||||
arg : string &log;
|
||||
## Server the command was issued to
|
||||
server : string &log;
|
||||
## Result of the command
|
||||
result : string &log &optional;
|
||||
};
|
||||
}
|
||||
|
||||
redef record connection += {
|
||||
smb_atsvc: ATSvcInfo &optional;
|
||||
};
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(ATSVC_LOG, [$columns=ATSvcInfo]);
|
||||
}
|
||||
|
||||
event smb_atsvc_job_add(c: connection, server: string, job: string)
|
||||
{
|
||||
local info: ATSvcInfo;
|
||||
info$ts = network_time();
|
||||
info$uid = c$uid;
|
||||
info$id = c$id;
|
||||
info$command = "Add job";
|
||||
info$arg = job;
|
||||
info$server = server;
|
||||
|
||||
c$smb_atsvc = info;
|
||||
}
|
||||
|
||||
event smb_atsvc_job_id(c: connection, id: count, status: count)
|
||||
{
|
||||
if ( !c?$smb_atsvc )
|
||||
return;
|
||||
if ( status == 0 )
|
||||
c$smb_atsvc$result = "success";
|
||||
else
|
||||
c$smb_atsvc$result = "failed";
|
||||
|
||||
Log::write(ATSVC_LOG, c$smb_atsvc);
|
||||
delete c$smb_atsvc;
|
||||
}
|
194
scripts/base/protocols/smb/smb1-main.bro
Normal file
194
scripts/base/protocols/smb/smb1-main.bro
Normal file
|
@ -0,0 +1,194 @@
|
|||
module SMB1;
|
||||
|
||||
redef record SMB::Info += {
|
||||
smb1_offered_dialects: string_vec &optional;
|
||||
};
|
||||
|
||||
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=5
|
||||
{
|
||||
if ( ! c?$smb )
|
||||
{
|
||||
local info: SMB::Info = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB1"];
|
||||
info$fid_map = table();
|
||||
info$tid_map = table();
|
||||
info$pending_cmds = table();
|
||||
c$smb = info;
|
||||
}
|
||||
|
||||
local smb = c$smb;
|
||||
local tid = hdr$tid;
|
||||
local pid = hdr$pid;
|
||||
local uid = hdr$uid;
|
||||
local mid = hdr$mid;
|
||||
|
||||
if ( tid !in smb$tid_map )
|
||||
{
|
||||
local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id];
|
||||
smb$tid_map[tid] = tmp_tree;
|
||||
}
|
||||
smb$current_tree = smb$tid_map[tid];
|
||||
|
||||
if ( mid !in smb$pending_cmds )
|
||||
{
|
||||
local tmp_cmd: SMB::CmdInfo;
|
||||
tmp_cmd$command = SMB1::commands[hdr$command];
|
||||
|
||||
local tmp_file: SMB::FileInfo;
|
||||
tmp_file$ts = network_time();
|
||||
tmp_file$id = c$id;
|
||||
tmp_file$uid = c$uid;
|
||||
tmp_cmd$referenced_file = tmp_file;
|
||||
tmp_cmd$referenced_tree = smb$current_tree;
|
||||
|
||||
smb$pending_cmds[mid] = tmp_cmd;
|
||||
}
|
||||
|
||||
smb$current_cmd = smb$pending_cmds[mid];
|
||||
smb$command = smb$current_cmd$command;
|
||||
|
||||
if ( is_orig )
|
||||
{
|
||||
smb$ts = network_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
smb$rtt = network_time() - smb$ts;
|
||||
smb$status = SMB::statuses[hdr$status]$id;
|
||||
}
|
||||
}
|
||||
|
||||
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=-5
|
||||
{
|
||||
if ( !is_orig )
|
||||
# This is a response and the command is no longer pending
|
||||
# so let's get rid of it.
|
||||
delete c$smb$pending_cmds[hdr$mid];
|
||||
|
||||
if ( c?$smb )
|
||||
Log::write(SMB::CMD_LOG, c$smb);
|
||||
}
|
||||
|
||||
|
||||
event smb1_negotiate_request(c: connection, hdr: SMB1::Header, dialects: string_vec) &priority=5
|
||||
{
|
||||
c$smb$smb1_offered_dialects = dialects;
|
||||
}
|
||||
|
||||
event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=5
|
||||
{
|
||||
if ( c$smb?$smb1_offered_dialects )
|
||||
{
|
||||
if ( response?$ntlm )
|
||||
c$smb$dialect = c$smb$smb1_offered_dialects[response$ntlm$dialect_index];
|
||||
delete c$smb$smb1_offered_dialects;
|
||||
}
|
||||
}
|
||||
|
||||
event smb1_tree_connect_andx_request(c: connection, hdr: SMB1::Header, path: string, service: string) &priority=5
|
||||
{
|
||||
c$smb$current_cmd$referenced_tree$path = path;
|
||||
c$smb$current_cmd$referenced_tree$service = service;
|
||||
c$smb$current_tree$ts=network_time();
|
||||
}
|
||||
|
||||
event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=5
|
||||
{
|
||||
c$smb$current_cmd$referenced_tree$native_file_system = native_file_system;
|
||||
c$smb$current_tree = c$smb$current_cmd$referenced_tree;
|
||||
c$smb$tid_map[hdr$tid] = c$smb$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$current_tree);
|
||||
}
|
||||
|
||||
event smb1_nt_create_andx_request(c: connection, hdr: SMB1::Header, name: string) &priority=5
|
||||
{
|
||||
c$smb$current_cmd$referenced_file$name = name;
|
||||
c$smb$current_file = c$smb$current_cmd$referenced_file;
|
||||
c$smb$current_file$action = SMB::FILE_OPEN;
|
||||
}
|
||||
|
||||
event smb1_nt_create_andx_response(c: connection, hdr: SMB1::Header, file_id: count, file_size: count, times: SMB::MACTimes) &priority=5
|
||||
{
|
||||
if ( ! c$smb?$current_file )
|
||||
{
|
||||
c$smb$current_file = c$smb$current_cmd$referenced_file;
|
||||
c$smb$current_file$action = SMB::FILE_OPEN;
|
||||
}
|
||||
c$smb$current_file$fid = file_id;
|
||||
c$smb$current_file$size = file_size;
|
||||
|
||||
# I'm seeing negative data from IPC tree transfers
|
||||
if ( time_to_double(times$modified) > 0.0 )
|
||||
c$smb$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$fid_map[file_id] = c$smb$current_file;
|
||||
|
||||
SMB::write_file_log(c$smb$current_file);
|
||||
}
|
||||
|
||||
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, file_id);
|
||||
c$smb$current_file$action = SMB::FILE_READ;
|
||||
|
||||
if ( c$smb$current_tree?$path && !c$smb$current_file?$path )
|
||||
c$smb$current_file$path = c$smb$current_tree$path;
|
||||
|
||||
#write_file_log(c$smb$current_file);
|
||||
}
|
||||
|
||||
event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5
|
||||
{
|
||||
#print "read andx response!";
|
||||
}
|
||||
|
||||
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, file_id);
|
||||
c$smb$current_file$action = SMB::FILE_WRITE;
|
||||
}
|
||||
|
||||
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=-5
|
||||
{
|
||||
if ( c$smb$current_tree?$path && !c$smb$current_file?$path )
|
||||
c$smb$current_file$path = c$smb$current_tree$path;
|
||||
|
||||
#write_file_log(c$smb$current_file);
|
||||
}
|
||||
|
||||
#event smb1_write_andx_response(c: connection, hdr: SMB1::Header, written_bytes: count) &priority=5
|
||||
# {
|
||||
# # Do i really need to do anything here? Maybe do a weird if the number of bytes written is odd?
|
||||
# }
|
||||
|
||||
event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=5
|
||||
{
|
||||
SMB::set_current_file(c$smb, file_id);
|
||||
c$smb$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$fid_map )
|
||||
{
|
||||
local fl = c$smb$fid_map[file_id];
|
||||
fl$uid = c$uid;
|
||||
fl$id = c$id;
|
||||
# Need to check for existence of path in case tree connect message wasn't seen.
|
||||
if ( c$smb$current_tree?$path )
|
||||
fl$path = c$smb$current_tree$path;
|
||||
delete c$smb$fid_map[file_id];
|
||||
|
||||
SMB::write_file_log(fl);
|
||||
}
|
||||
else
|
||||
{
|
||||
# A reporter message is not right...
|
||||
#Reporter::warning("attempting to close an unknown file!");
|
||||
}
|
||||
}
|
183
scripts/base/protocols/smb/smb2-main.bro
Normal file
183
scripts/base/protocols/smb/smb2-main.bro
Normal file
|
@ -0,0 +1,183 @@
|
|||
module SMB2;
|
||||
|
||||
redef record SMB::Info += {
|
||||
smb2_offered_dialects: index_vec &optional;
|
||||
};
|
||||
|
||||
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=5
|
||||
{
|
||||
if ( ! c?$smb )
|
||||
{
|
||||
local info: SMB::Info = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB2"];
|
||||
info$fid_map = table();
|
||||
info$tid_map = table();
|
||||
info$pending_cmds = table();
|
||||
c$smb = info;
|
||||
}
|
||||
|
||||
local smb = c$smb;
|
||||
local tid = hdr$tree_id;
|
||||
local pid = hdr$process_id;
|
||||
local mid = hdr$message_id;
|
||||
local sid = hdr$session_id;
|
||||
|
||||
if ( tid !in smb$tid_map )
|
||||
{
|
||||
local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id];
|
||||
smb$tid_map[tid] = tmp_tree;
|
||||
}
|
||||
smb$current_tree = smb$tid_map[tid];
|
||||
|
||||
if ( mid !in smb$pending_cmds )
|
||||
{
|
||||
local tmp_cmd: SMB::CmdInfo;
|
||||
tmp_cmd$command = SMB2::commands[hdr$command];
|
||||
|
||||
local tmp_file: SMB::FileInfo;
|
||||
tmp_file$ts = network_time();
|
||||
tmp_file$id = c$id;
|
||||
tmp_file$uid = c$uid;
|
||||
tmp_cmd$referenced_file = tmp_file;
|
||||
tmp_cmd$referenced_tree = smb$current_tree;
|
||||
|
||||
smb$pending_cmds[mid] = tmp_cmd;
|
||||
}
|
||||
|
||||
smb$current_cmd = smb$pending_cmds[mid];
|
||||
smb$command = smb$current_cmd$command;
|
||||
|
||||
if ( is_orig )
|
||||
{
|
||||
smb$ts = network_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
smb$rtt = network_time() - smb$ts;
|
||||
smb$status = SMB::statuses[hdr$status]$id;
|
||||
}
|
||||
}
|
||||
|
||||
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=-5
|
||||
{
|
||||
if ( !is_orig )
|
||||
# This is a response and the command is no longer pending
|
||||
# so let's get rid of it.
|
||||
delete c$smb$pending_cmds[hdr$message_id];
|
||||
|
||||
if ( c?$smb )
|
||||
Log::write(SMB::CMD_LOG, c$smb);
|
||||
}
|
||||
|
||||
event smb2_negotiate_request(c: connection, hdr: SMB2::Header, dialects: index_vec) &priority=5
|
||||
{
|
||||
c$smb$smb2_offered_dialects = dialects;
|
||||
}
|
||||
|
||||
event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse)
|
||||
{
|
||||
if ( c$smb?$smb2_offered_dialects )
|
||||
{
|
||||
for ( i in c$smb$smb2_offered_dialects )
|
||||
{
|
||||
if ( response$dialect_revision == c$smb$smb2_offered_dialects[i] )
|
||||
{
|
||||
c$smb$dialect = SMB2::dialects[response$dialect_revision];
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete c$smb$smb2_offered_dialects;
|
||||
}
|
||||
}
|
||||
|
||||
event smb2_tree_connect_request(c: connection, hdr: SMB2::Header, path: string) &priority=5
|
||||
{
|
||||
c$smb$current_cmd$referenced_tree$path = path;
|
||||
c$smb$current_tree$ts=network_time();
|
||||
}
|
||||
|
||||
event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=5
|
||||
{
|
||||
c$smb$current_tree = c$smb$current_cmd$referenced_tree;
|
||||
c$smb$current_tree$share_type = SMB2::share_types[response$share_type];
|
||||
c$smb$tid_map[hdr$tree_id] = c$smb$current_tree;
|
||||
}
|
||||
|
||||
event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=-5
|
||||
{
|
||||
Log::write(SMB::MAPPING_LOG, c$smb$current_tree);
|
||||
}
|
||||
|
||||
event smb2_create_request(c: connection, hdr: SMB2::Header, name: string) &priority=5
|
||||
{
|
||||
c$smb$current_cmd$referenced_file$name = name;
|
||||
c$smb$current_file = c$smb$current_cmd$referenced_file;
|
||||
c$smb$current_file$action = SMB::FILE_OPEN;
|
||||
}
|
||||
|
||||
event smb2_create_response(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, file_size: count, times: SMB::MACTimes, attrs: SMB2::FileAttrs) &priority=5
|
||||
{
|
||||
if ( ! c$smb?$current_file )
|
||||
{
|
||||
c$smb$current_file = c$smb$current_cmd$referenced_file;
|
||||
c$smb$current_file$action = SMB::FILE_OPEN;
|
||||
}
|
||||
c$smb$current_file$fid = file_id$persistent+file_id$volatile;
|
||||
c$smb$current_file$size = file_size;
|
||||
|
||||
# I'm seeing negative data from IPC tree transfers
|
||||
if ( time_to_double(times$modified) > 0.0 )
|
||||
c$smb$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$fid_map[file_id$persistent+file_id$volatile] = c$smb$current_file;
|
||||
|
||||
SMB::write_file_log(c$smb$current_file);
|
||||
}
|
||||
|
||||
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, file_id$persistent+file_id$volatile);
|
||||
c$smb$current_file$action = SMB::FILE_READ;
|
||||
|
||||
if ( c$smb$current_tree?$path && !c$smb$current_file?$path )
|
||||
c$smb$current_file$path = c$smb$current_tree$path;
|
||||
|
||||
#write_file_log(c$smb$current_file);
|
||||
}
|
||||
|
||||
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, file_id$persistent+file_id$volatile);
|
||||
c$smb$current_file$action = SMB::FILE_WRITE;
|
||||
|
||||
if ( c$smb$current_tree?$path && ! c$smb$current_file?$path )
|
||||
c$smb$current_file$path = c$smb$current_tree$path;
|
||||
}
|
||||
|
||||
event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=5
|
||||
{
|
||||
SMB::set_current_file(c$smb, file_id$persistent+file_id$volatile);
|
||||
c$smb$current_file$action = SMB::FILE_CLOSE;
|
||||
}
|
||||
|
||||
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$fid_map )
|
||||
{
|
||||
local fl = c$smb$fid_map[file_id$persistent+file_id$volatile];
|
||||
fl$uid = c$uid;
|
||||
fl$id = c$id;
|
||||
# Need to check for existence of path in case tree connect message wasn't seen.
|
||||
if ( c$smb$current_tree?$path )
|
||||
fl$path = c$smb$current_tree$path;
|
||||
delete c$smb$fid_map[file_id$persistent+file_id$volatile];
|
||||
|
||||
SMB::write_file_log(fl);
|
||||
}
|
||||
else
|
||||
{
|
||||
# A reporter message is not right...
|
||||
#Reporter::warning("attempting to close an unknown file!");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
include(BroPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
@ -6,6 +5,75 @@ 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(
|
||||
smb_ntlmssp.bif
|
||||
smb_pipe.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_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_negotiate.bif
|
||||
smb2_com_read.bif
|
||||
smb2_com_session_setup.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-mailslot.pac
|
||||
smb-ntlmssp.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-negotiate.pac
|
||||
smb2-com-read.pac
|
||||
smb2-com-session-setup.pac
|
||||
smb2-com-tree-connect.pac
|
||||
smb2-com-tree-disconnect.pac
|
||||
smb2-com-write.pac
|
||||
)
|
||||
bro_plugin_end()
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "plugin/Plugin.h"
|
||||
|
||||
#include "SMB.h"
|
||||
|
@ -7,5 +6,36 @@ BRO_PLUGIN_BEGIN(Bro, SMB)
|
|||
BRO_PLUGIN_DESCRIPTION("SMB analyzer");
|
||||
BRO_PLUGIN_ANALYZER("SMB", smb::SMB_Analyzer);
|
||||
BRO_PLUGIN_SUPPORT_ANALYZER("Contents_SMB");
|
||||
BRO_PLUGIN_BIF_FILE(events);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_events);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_events);
|
||||
|
||||
BRO_PLUGIN_BIF_FILE(smb_ntlmssp);
|
||||
BRO_PLUGIN_BIF_FILE(smb_pipe);
|
||||
|
||||
BRO_PLUGIN_BIF_FILE(types);
|
||||
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_check_directory);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_close);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_create_directory);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_echo);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_logoff_andx);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_negotiate);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_nt_create_andx);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_nt_cancel);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_query_information);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_read_andx);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_session_setup_andx);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_tree_connect_andx);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_tree_disconnect);
|
||||
BRO_PLUGIN_BIF_FILE(smb1_com_write_andx);
|
||||
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_close);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_create);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_negotiate);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_read);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_session_setup);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_tree_connect);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_tree_disconnect);
|
||||
BRO_PLUGIN_BIF_FILE(smb2_com_write);
|
||||
|
||||
BRO_PLUGIN_END
|
||||
|
|
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,7 +5,7 @@
|
|||
// 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 {
|
||||
|
@ -19,182 +17,68 @@ enum IPC_named_pipe {
|
|||
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);
|
||||
|
||||
protected:
|
||||
void InitMsgBuf();
|
||||
typedef enum {
|
||||
WAIT_FOR_HDR,
|
||||
WAIT_FOR_DATA
|
||||
} state_t;
|
||||
typedef enum {
|
||||
NEED_RESYNC,
|
||||
INSYNC,
|
||||
} resync_state_t;
|
||||
virtual void Init();
|
||||
virtual bool CheckResync(int& len, const u_char*& data, bool orig);
|
||||
virtual void Undelivered(uint64 seq, int len, bool orig);
|
||||
virtual void NeedResync() {
|
||||
resync_state = NEED_RESYNC;
|
||||
state = WAIT_FOR_HDR;
|
||||
}
|
||||
|
||||
bool HasSMBHeader(const u_char* data);
|
||||
|
||||
void DeliverSMB(int len, const u_char* data);
|
||||
|
||||
SMB_Session* smb_session;
|
||||
u_char dshdr[4];
|
||||
u_char* msg_buf;
|
||||
binpac::SMB::SMB_Conn* smb_session;
|
||||
|
||||
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();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(uint64 seq, int len, bool orig);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new SMB_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
SMB_Session* smb_session;
|
||||
binpac::SMB::SMB_Conn* interp;
|
||||
Contents_SMB* o_smb;
|
||||
Contents_SMB* r_smb;
|
||||
|
||||
// Count the number of chunks received by the analyzer
|
||||
// but only used to count the first few.
|
||||
uint8 chunks;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
|
|
|
@ -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)
|
125
src/analyzer/protocol/smb/dce_rpc-protocol.pac
Normal file
125
src/analyzer/protocol/smb/dce_rpc-protocol.pac
Normal file
|
@ -0,0 +1,125 @@
|
|||
# Definitions for DCE RPC.
|
||||
|
||||
enum dce_rpc_ptype {
|
||||
DCE_RPC_REQUEST,
|
||||
DCE_RPC_PING,
|
||||
DCE_RPC_RESPONSE,
|
||||
DCE_RPC_FAULT,
|
||||
DCE_RPC_WORKING,
|
||||
DCE_RPC_NOCALL,
|
||||
DCE_RPC_REJECT,
|
||||
DCE_RPC_ACK,
|
||||
DCE_RPC_CL_CANCEL,
|
||||
DCE_RPC_FACK,
|
||||
DCE_RPC_CANCEL_ACK,
|
||||
DCE_RPC_BIND,
|
||||
DCE_RPC_BIND_ACK,
|
||||
DCE_RPC_BIND_NAK,
|
||||
DCE_RPC_ALTER_CONTEXT,
|
||||
DCE_RPC_ALTER_CONTEXT_RESP,
|
||||
DCE_RPC_SHUTDOWN,
|
||||
DCE_RPC_CO_CANCEL,
|
||||
DCE_RPC_ORPHANED,
|
||||
};
|
||||
|
||||
type uuid = bytestring &length = 16;
|
||||
|
||||
type context_handle = record {
|
||||
cxt_attributes: uint32;
|
||||
cxt_uuid: uuid;
|
||||
};
|
||||
|
||||
type rpc_if_id_t = record {
|
||||
if_uuid : uuid;
|
||||
vers_major : uint16;
|
||||
vers_minor : uint16;
|
||||
};
|
||||
|
||||
type NDR_Format = record {
|
||||
intchar : uint8;
|
||||
floatspec : uint8;
|
||||
reserved : padding[2];
|
||||
} &let {
|
||||
byteorder = (intchar >> 4) ? littleendian : bigendian;
|
||||
};
|
||||
|
||||
#### 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;
|
||||
} &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 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 p_cont_list_t = record {
|
||||
n_context_elem : uint8;
|
||||
reserved : padding[3];
|
||||
p_cont_elem : p_cont_elem_t[n_context_elem];
|
||||
};
|
||||
|
||||
type DCE_RPC_Bind = record {
|
||||
max_xmit_frag : uint16;
|
||||
max_recv_frag : uint16;
|
||||
assoc_group_id : uint32;
|
||||
p_context_elem : p_cont_list_t;
|
||||
};
|
||||
|
||||
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_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;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
type DCE_RPC_Auth(header: DCE_RPC_Header) = uint8[header.auth_length];
|
||||
|
||||
|
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;
|
||||
%}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
enum SMB_MailSlot_opcode {
|
||||
HOST_ANNOUNCEMENT = 1,
|
||||
ANNOUCEMENT_REQUEST = 2,
|
||||
|
|
399
src/analyzer/protocol/smb/smb-ntlmssp.pac
Normal file
399
src/analyzer/protocol/smb/smb-ntlmssp.pac
Normal file
|
@ -0,0 +1,399 @@
|
|||
refine connection SMB_Conn += {
|
||||
function unicode_to_ascii(s: bytestring, length: uint16, is_unicode: bool): bytestring
|
||||
%{
|
||||
if ( !is_unicode ) return s;
|
||||
|
||||
char* buf;
|
||||
|
||||
buf = new char[(length/2) + 1];
|
||||
|
||||
for ( int i = 0; i < length; i += 2 )
|
||||
buf[i/2] = s[i];
|
||||
buf[length/2] = 0;
|
||||
return bytestring((uint8*) buf, (length/2));
|
||||
%}
|
||||
|
||||
function build_negotiate_flag_record(val: SMB_NTLM_Negotiate_Flags): BroVal
|
||||
%{
|
||||
RecordVal* flags = new RecordVal(BifType::Record::SMB::NTLMNegotiateFlags);
|
||||
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 build_version_record(val: SMB_NTLM_Version): BroVal
|
||||
%{
|
||||
RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMVersion);
|
||||
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: SMB_NTLM_AV_Pair_Sequence): BroVal
|
||||
%{
|
||||
RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMAVs);
|
||||
for ( uint i = 0; ${val.pairs[i].id} != 0; i++ ) {
|
||||
switch ( ${val.pairs[i].id} ) {
|
||||
case 1:
|
||||
result->Assign(0, bytestring_to_val(${val.pairs[i].nb_computer_name.data}));
|
||||
break;
|
||||
case 2:
|
||||
result->Assign(1, bytestring_to_val(${val.pairs[i].nb_domain_name.data}));
|
||||
break;
|
||||
case 3:
|
||||
result->Assign(2, bytestring_to_val(${val.pairs[i].dns_computer_name.data}));
|
||||
break;
|
||||
case 4:
|
||||
result->Assign(3, bytestring_to_val(${val.pairs[i].dns_domain_name.data}));
|
||||
break;
|
||||
case 5:
|
||||
result->Assign(4, bytestring_to_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, bytestring_to_val(${val.pairs[i].target_name.data}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
%}
|
||||
|
||||
function proc_smb_ntlm_accept(header: SMB_Header): bool
|
||||
%{
|
||||
BifEvent::generate_smb_ntlm_accepted(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header));
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb_ntlm_negotiate(header: SMB_Header, val: SMB_NTLM_Negotiate): bool
|
||||
%{
|
||||
RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMNegotiate);
|
||||
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||
if ( ${val.flags.negotiate_oem_domain_supplied} ) result->Assign(1, bytestring_to_val(${val.domain_name.string.data}));
|
||||
if ( ${val.flags.negotiate_oem_workstation_supplied} ) result->Assign(2, bytestring_to_val(${val.workstation.string.data}));
|
||||
if ( ${val.flags.negotiate_version} ) result->Assign(3, build_version_record(${val.version}));
|
||||
|
||||
BifEvent::generate_smb_ntlm_negotiate(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), result);
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb_ntlm_challenge(header: SMB_Header, val: SMB_NTLM_Challenge): bool
|
||||
%{
|
||||
RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMChallenge);
|
||||
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||
if ( ${val.flags.request_target} ) result->Assign(1, bytestring_to_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_smb_ntlm_challenge(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), result);
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb_ntlm_authenticate(header: SMB_Header, val: SMB_NTLM_Authenticate): bool
|
||||
%{
|
||||
RecordVal* result = new RecordVal(BifType::Record::SMB::NTLMAuthenticate);
|
||||
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||
result->Assign(1, bytestring_to_val(${val.domain_name.string.data}));
|
||||
result->Assign(2, bytestring_to_val(${val.user_name.string.data}));
|
||||
result->Assign(3, bytestring_to_val(${val.workstation.string.data}));
|
||||
if ( ${val.flags.negotiate_version} ) result->Assign(4, build_version_record(${val.version}));
|
||||
|
||||
BifEvent::generate_smb_ntlm_authenticate(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), result);
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function convert_der_num(is_long: bool, first: uint8, fields: bytestring): uint64
|
||||
%{
|
||||
if (!is_long) return first;
|
||||
|
||||
int result;
|
||||
result = 0;
|
||||
|
||||
for (uint i = 0; i < fields.length(); i++)
|
||||
{
|
||||
result << 8;
|
||||
result += ${fields[i]};
|
||||
}
|
||||
return result;
|
||||
%}
|
||||
|
||||
function test_accepted(m: SMB_NTLM_SSP): bool
|
||||
%{
|
||||
if ( ${m.gssapi}->size() < 4 )
|
||||
return false;
|
||||
return ( ${m.gssapi[3].tag} == 10 && ${m.gssapi[3].value} == "\x00" );
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
type DER_Length = record {
|
||||
first : uint8;
|
||||
rest : bytestring &length=size;
|
||||
} &let {
|
||||
is_long_form : bool = (first >= 128);
|
||||
size : uint8 = is_long_form ? first % 128 : 0;
|
||||
value : uint64 = $context.connection.convert_der_num(is_long_form, first, rest);
|
||||
};
|
||||
|
||||
type DER_ASN = record {
|
||||
tag: uint8;
|
||||
length: DER_Length;
|
||||
skip_constructed: case (is_primitive && (tag != 0x04) ) of {
|
||||
true -> value: bytestring &length=length.value;
|
||||
false -> nothing: empty;
|
||||
} &requires(is_primitive);
|
||||
} &let {
|
||||
is_primitive: bool = (tag & 0x20) == 0;
|
||||
last: bool = tag == 0x04;
|
||||
};
|
||||
|
||||
type SMB_NTLM_SSP(header: SMB_Header) = record {
|
||||
gssapi : DER_ASN[] &until ($element.last);
|
||||
skip_accepted: case ( is_accepted ) of {
|
||||
true -> nothing: empty;
|
||||
false -> token: SMB_NTLM_Neg_Token(header);
|
||||
} &requires(is_accepted);
|
||||
} &let {
|
||||
is_accepted: bool = $context.connection.test_accepted(this);
|
||||
proc: bool = $context.connection.proc_smb_ntlm_accept(header) &if(is_accepted);
|
||||
};
|
||||
|
||||
type SMB_NTLM_Neg_Token(header: SMB_Header) = record {
|
||||
identifier : bytestring &length=8;
|
||||
msg_type : uint32;
|
||||
msg : case msg_type of {
|
||||
0 -> accept : empty;
|
||||
1 -> negotiate : SMB_NTLM_Negotiate(header, 12);
|
||||
2 -> challenge : SMB_NTLM_Challenge(header, 12);
|
||||
3 -> authenticate : SMB_NTLM_Authenticate(header, 12);
|
||||
};
|
||||
} &let {
|
||||
is_accept : bool = (msg_type == 0);
|
||||
is_negotiate : bool = (msg_type == 1);
|
||||
is_challenge : bool = (msg_type == 2);
|
||||
is_authenticate : bool = (msg_type == 3);
|
||||
proc : bool = $context.connection.proc_smb_ntlm_accept(header) &if is_accept;
|
||||
};
|
||||
|
||||
type SMB_NTLM_Negotiate(header: SMB_Header, offset: uint16) = record {
|
||||
flags : SMB_NTLM_Negotiate_Flags;
|
||||
domain_name_fields : SMB_NTLM_StringData;
|
||||
workstation_fields : SMB_NTLM_StringData;
|
||||
version_present : case flags.negotiate_version of {
|
||||
true -> version: SMB_NTLM_Version;
|
||||
false -> no_version: empty;
|
||||
};
|
||||
payload : bytestring &restofdata;
|
||||
} &let {
|
||||
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||
domain_name : SMB_NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_domain_supplied);
|
||||
workstation : SMB_NTLM_String(workstation_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_workstation_supplied);
|
||||
proc : bool = $context.connection.proc_smb_ntlm_negotiate(header, this);
|
||||
};
|
||||
|
||||
type SMB_NTLM_Challenge(header: SMB_Header, offset: uint16) = record {
|
||||
target_name_fields : SMB_NTLM_StringData;
|
||||
flags : SMB_NTLM_Negotiate_Flags;
|
||||
challenge : uint64;
|
||||
reserved : padding[8];
|
||||
target_info_fields : SMB_NTLM_StringData;
|
||||
version_present : case flags.negotiate_version of {
|
||||
true -> version: SMB_NTLM_Version;
|
||||
false -> no_version: empty;
|
||||
};
|
||||
payload : bytestring &restofdata;
|
||||
} &let {
|
||||
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||
target_name : SMB_NTLM_String(target_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.request_target);
|
||||
target_info : SMB_NTLM_AV_Pair_Sequence(target_info_fields.offset - absolute_offset) withinput payload &if(flags.negotiate_target_info);
|
||||
proc : bool = $context.connection.proc_smb_ntlm_challenge(header, this);
|
||||
};
|
||||
|
||||
type SMB_NTLM_Authenticate(header: SMB_Header, offset: uint16) = record {
|
||||
lm_challenge_response_fields : SMB_NTLM_StringData;
|
||||
nt_challenge_response_fields : SMB_NTLM_StringData;
|
||||
domain_name_fields : SMB_NTLM_StringData;
|
||||
user_name_fields : SMB_NTLM_StringData;
|
||||
workstation_fields : SMB_NTLM_StringData;
|
||||
encrypted_session_key_fields : SMB_NTLM_StringData;
|
||||
flags : SMB_NTLM_Negotiate_Flags;
|
||||
version_present : case flags.negotiate_version of {
|
||||
true -> version: SMB_NTLM_Version;
|
||||
false -> no_version: empty;
|
||||
};
|
||||
mic : bytestring &length=16;
|
||||
payload : bytestring &restofdata;
|
||||
} &let {
|
||||
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||
domain_name : SMB_NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload;
|
||||
user_name : SMB_NTLM_String(user_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload;
|
||||
workstation : SMB_NTLM_String(workstation_fields, absolute_offset , flags.negotiate_unicode) withinput payload;
|
||||
encrypted_session_key : SMB_NTLM_String(workstation_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_key_exch);
|
||||
# lm_response : SMB_LM_Response(lm_challenge_response_fields.offset - absolute_offset) withinput payload &if(lm_challenge_response_fields.length > 0);
|
||||
# ntlm_response : SMB_NTLM_Response(nt_challenge_response_fields.offset - absolute_offset) withinput payload &if(nt_challenge_response_fields.length == 24);
|
||||
# ntlmv2_response : SMB_NTLM_Response(nt_challenge_response_fields.offset - absolute_offset) withinput payload &if(nt_challenge_response_fields.length > 24);
|
||||
proc : bool = $context.connection.proc_smb_ntlm_authenticate(header, this);
|
||||
};
|
||||
|
||||
type SMB_NTLM_Version = record {
|
||||
major_version : uint8;
|
||||
minor_version : uint8;
|
||||
build_number : uint16;
|
||||
reserved : padding[3];
|
||||
ntlm_revision : uint8;
|
||||
};
|
||||
|
||||
type SMB_NTLM_StringData = record {
|
||||
length : uint16;
|
||||
max_length : uint16;
|
||||
offset : uint32;
|
||||
};
|
||||
|
||||
type SMB_Fixed_Length_String(unicode: bool) = record {
|
||||
s: bytestring &restofdata;
|
||||
} &let {
|
||||
data: bytestring = $context.connection.unicode_to_ascii(s, sizeof(s), unicode);
|
||||
};
|
||||
|
||||
type SMB_NTLM_String(fields: SMB_NTLM_StringData, offset: uint16, unicode: bool) = record {
|
||||
: padding to fields.offset - offset;
|
||||
string: SMB_Fixed_Length_String(unicode) &length=fields.length;
|
||||
};
|
||||
|
||||
type SMB_NTLM_AV_Pair_Sequence(offset: uint16) = record {
|
||||
: padding to offset;
|
||||
pairs: SMB_NTLM_AV_Pair[] &until ($element.last);
|
||||
};
|
||||
|
||||
type SMB_NTLM_AV_Pair = record {
|
||||
id : uint16;
|
||||
length : uint16;
|
||||
value_case : case id of {
|
||||
0x0000 -> av_eol : empty;
|
||||
0x0001 -> nb_computer_name : SMB_Fixed_Length_String(true) &length=length;
|
||||
0x0002 -> nb_domain_name : SMB_Fixed_Length_String(true) &length=length;
|
||||
0x0003 -> dns_computer_name : SMB_Fixed_Length_String(true) &length=length;
|
||||
0x0004 -> dns_domain_name : SMB_Fixed_Length_String(true) &length=length;
|
||||
0x0005 -> dns_tree_name : SMB_Fixed_Length_String(true) &length=length;
|
||||
0x0006 -> av_flags : uint32;
|
||||
0x0007 -> timestamp : uint64;
|
||||
0x0008 -> single_host : SMB_NTLM_Single_Host;
|
||||
0x0009 -> target_name : SMB_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 SMB_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 SMB_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 SMB_NTLM_Response(offset: uint16) = record {
|
||||
padpad : padding to offset;
|
||||
response : bytestring &length=24;
|
||||
};
|
||||
|
||||
type SMB_NTLMv2_Response(flags: SMB_NTLM_Negotiate_Flags, offset: uint16) = record {
|
||||
padpad : padding to offset;
|
||||
response : bytestring &length=16;
|
||||
client_challenge : SMB_NTLMv2_Client_Challenge(flags);
|
||||
};
|
||||
|
||||
type SMB_NTLMv2_Client_Challenge(flags: SMB_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 : SMB_NTLM_AV_Pair_Sequence(0);
|
||||
};
|
||||
|
||||
type SMB_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;
|
||||
};
|
|
@ -1,12 +1,46 @@
|
|||
# this won't work correctly yet, since sometimes the parameters
|
||||
# field in the transaction takes up all of the data field
|
||||
|
||||
%include dce_rpc-protocol.pac
|
||||
|
||||
refine connection SMB_Conn += {
|
||||
function proc_smb_atsvc_job_add(val: AT_SVC_NetrJobAdd): bool
|
||||
%{
|
||||
if ( smb_atsvc_job_add )
|
||||
{
|
||||
BifEvent::generate_smb_atsvc_job_add(bro_analyzer(), bro_analyzer()->Conn(), smb_string2stringval(${val.server.string}), smb_string2stringval(${val.command.string}));
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb_atsvc_job_id(val: AT_SVC_JobID): bool
|
||||
%{
|
||||
if ( smb_atsvc_job_id )
|
||||
{
|
||||
BifEvent::generate_smb_atsvc_job_id(bro_analyzer(), bro_analyzer()->Conn(), ${val.id}, ${val.status});
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function determine_pipe_msg_type(hdr: DCE_RPC_Header, opnum: uint8): uint8
|
||||
%{
|
||||
if ( !is_atsvc ) return 0;
|
||||
if ( ${hdr.PTYPE} == 0 && ${opnum} == 0 ) return 1;
|
||||
if ( ${hdr.PTYPE} == 2 && ${opnum} == 0 ) return 2;
|
||||
return 0;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
type SMB_Pipe_message( unicode: bool, byte_count: uint16, sub_cmd: uint16 ) = record {
|
||||
|
||||
# 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;
|
||||
|
||||
rpc : DCE_RPC_Header;
|
||||
todo : padding[6]; # These fields are currently missing from DCE/RPC for some reason.
|
||||
opnum : uint8;
|
||||
pipe_type: case $context.connection.determine_pipe_msg_type(rpc, opnum) of {
|
||||
1 -> atsvc_request : AT_SVC_Request(unicode, opnum);
|
||||
2 -> atsvc_reply : AT_SVC_Reply(unicode, opnum);
|
||||
default -> unknown : bytestring &restofdata;
|
||||
};
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record {
|
||||
|
@ -17,3 +51,46 @@ type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record {
|
|||
data : bytestring &restofdata;
|
||||
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type AT_SVC_Request(unicode: bool, opnum: uint8) = record {
|
||||
empty: padding[1];
|
||||
op: case opnum of {
|
||||
0 -> add: AT_SVC_NetrJobAdd(unicode);
|
||||
default -> unknown: bytestring &restofdata;
|
||||
};
|
||||
};
|
||||
|
||||
type AT_SVC_String_Pointer(unicode: bool) = record {
|
||||
referent_id : uint32;
|
||||
max_count : uint32;
|
||||
offset : uint32;
|
||||
actual_count: uint32;
|
||||
string : SMB_string(unicode, offsetof(string));
|
||||
};
|
||||
|
||||
type AT_SVC_NetrJobAdd(unicode: bool) = record {
|
||||
server : AT_SVC_String_Pointer(unicode);
|
||||
unknown : padding[2];
|
||||
job_time : uint32;
|
||||
days_of_month: uint32;
|
||||
days_of_week : uint8;
|
||||
flags : uint8;
|
||||
unknown2 : padding[2];
|
||||
command : AT_SVC_String_Pointer(unicode);
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb_atsvc_job_add(this);
|
||||
};
|
||||
|
||||
type AT_SVC_Reply(unicode: bool, opnum: uint16) = record {
|
||||
op: case opnum of {
|
||||
0 -> add: AT_SVC_JobID(unicode);
|
||||
default -> unknown: bytestring &restofdata;
|
||||
};
|
||||
};
|
||||
|
||||
type AT_SVC_JobID(unicode: bool) = record {
|
||||
id: uint32;
|
||||
status: uint32;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb_atsvc_job_id(this);
|
||||
};
|
||||
|
|
|
@ -336,7 +336,7 @@ type SMB_read_andx_response = record {
|
|||
byte_count : uint16;
|
||||
pad : padding[padding_length];
|
||||
data : bytestring &length = data_length;
|
||||
# Chris: the length here is causing problems - could we be having
|
||||
# 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.
|
||||
|
|
144
src/analyzer/protocol/smb/smb-strings.pac
Normal file
144
src/analyzer/protocol/smb/smb-strings.pac
Normal file
|
@ -0,0 +1,144 @@
|
|||
function uint8s_to_stringval(s: uint8[]): StringVal
|
||||
%{
|
||||
int length = 0;
|
||||
|
||||
const char* sp;
|
||||
bool ascii = true;
|
||||
|
||||
vector<uint8>* data = s;
|
||||
length = data->size();
|
||||
// Scan the string once to see if it's all ascii
|
||||
// embedded in UCS-2 (16 bit unicode).
|
||||
for( int i = 1; i < length; i=i+2 )
|
||||
{
|
||||
// Find characters in odd positions that aren't null.
|
||||
if ( (*data)[i] != 0x00 )
|
||||
{
|
||||
ascii = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *buf = new char[length];
|
||||
|
||||
for ( int i = 0; i < length; i=i+2)
|
||||
{
|
||||
if ( ascii )
|
||||
{
|
||||
int j = i/2;
|
||||
buf[j] = (*data)[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flip the bytes because they are transferred in little endian.
|
||||
buf[i] = (*data)[i+1];
|
||||
buf[i+1] = (*data)[i];
|
||||
}
|
||||
}
|
||||
|
||||
if ( ascii )
|
||||
{
|
||||
length = length / 2;
|
||||
if ( length > 0 && buf[length-1] == 0x00 )
|
||||
--length;
|
||||
}
|
||||
else if ( length >= 2 && buf[length-1] == 0 && buf[length-2] == 0 )
|
||||
{
|
||||
// If the last 2 bytes are nulls, cut them with the length.
|
||||
length = length-2;
|
||||
}
|
||||
|
||||
StringVal *output = new StringVal(length, buf);
|
||||
delete [] buf;
|
||||
return output;
|
||||
%}
|
||||
|
||||
function extract_string(s: SMB_string) : StringVal
|
||||
%{
|
||||
int length = 0;
|
||||
|
||||
const char* sp;
|
||||
bool ascii = true;
|
||||
|
||||
if ( s->val_case_index() == 0 )
|
||||
{
|
||||
length = s->a()->size();
|
||||
char *buf = new char[length];
|
||||
|
||||
for ( int i = 0; i < length; i++)
|
||||
{
|
||||
unsigned char t = (*(s->a()))[i];
|
||||
buf[i] = t;
|
||||
}
|
||||
|
||||
if ( length > 0 && buf[length] == 0x00 )
|
||||
length--;
|
||||
|
||||
StringVal *ret = new StringVal(length, buf);
|
||||
delete [] buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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());
|
||||
%}
|
||||
|
||||
type SMB_ascii_string = uint8[] &until($element == 0x00);
|
||||
|
||||
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_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];
|
||||
};
|
44
src/analyzer/protocol/smb/smb-time.pac
Normal file
44
src/analyzer/protocol/smb/smb-time.pac
Normal file
|
@ -0,0 +1,44 @@
|
|||
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;
|
||||
%}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
#type SMB2_timestamp = record {
|
||||
# lowbits : uint32;
|
||||
# highbits : uint32;
|
||||
#} &byteorder = littleendian;
|
||||
#
|
|
@ -2,11 +2,130 @@
|
|||
%include bro.pac
|
||||
|
||||
%extern{
|
||||
#include "events.bif.h"
|
||||
#include "smb1_events.bif.h"
|
||||
#include "smb2_events.bif.h"
|
||||
|
||||
#include "types.bif.h"
|
||||
|
||||
#include "smb_ntlmssp.bif.h"
|
||||
#include "smb_pipe.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_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_negotiate.bif.h"
|
||||
#include "smb2_com_read.bif.h"
|
||||
#include "smb2_com_session_setup.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;
|
||||
};
|
||||
|
||||
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-ntlmssp.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
|
||||
|
||||
%include smb-protocol.pac
|
||||
%include smb-mailslot.pac
|
||||
%include smb-pipe.pac
|
||||
|
||||
# SMB2 Commands
|
||||
%include smb2-com-close.pac
|
||||
%include smb2-com-create.pac
|
||||
%include smb2-com-negotiate.pac
|
||||
%include smb2-com-read.pac
|
||||
%include smb2-com-session-setup.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);
|
||||
};
|
36
src/analyzer/protocol/smb/smb1-com-close.pac
Normal file
36
src/analyzer/protocol/smb/smb1-com-close.pac
Normal file
|
@ -0,0 +1,36 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb1_close_request(h: SMB_Header, val: SMB1_close_request): bool
|
||||
%{
|
||||
is_atsvc = false;
|
||||
|
||||
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);
|
||||
};
|
||||
|
41
src/analyzer/protocol/smb/smb1-com-echo.pac
Normal file
41
src/analyzer/protocol/smb/smb1-com-echo.pac
Normal file
|
@ -0,0 +1,41 @@
|
|||
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(), 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(), 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);
|
||||
};
|
281
src/analyzer/protocol/smb/smb1-com-negotiate.pac
Normal file
281
src/analyzer/protocol/smb/smb1-com-negotiate.pac
Normal file
|
@ -0,0 +1,281 @@
|
|||
# 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.
|
||||
|
||||
%header{
|
||||
double time_from_lanman(const uint16 two_seconds, const uint16 minutes, const uint16 hours,
|
||||
const uint16 day, const uint16 month, const uint16 year, const uint16 tz);
|
||||
double time_from_ntlm(const uint64 time, const uint16 tz);
|
||||
%}
|
||||
|
||||
%code{
|
||||
|
||||
double time_from_lanman(const uint16 two_seconds, const uint16 minutes, const uint16 hours,
|
||||
const uint16 day, const uint16 month, const uint16 year, const uint16 tz)
|
||||
{
|
||||
tm lTime;
|
||||
lTime.tm_sec = two_seconds * 2;
|
||||
lTime.tm_min = minutes;
|
||||
lTime.tm_hour = hours;
|
||||
lTime.tm_mday = day;
|
||||
lTime.tm_mon = month;
|
||||
lTime.tm_year = 1980 + year;
|
||||
time_t lResult = mktime(&lTime);
|
||||
return lResult + tz;
|
||||
}
|
||||
|
||||
double time_from_ntlm(const uint64 time, const uint16 tz)
|
||||
{
|
||||
return (time - 11644473600)/100000000.0;
|
||||
}
|
||||
%}
|
||||
|
||||
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.word_count}, TYPE_COUNT));
|
||||
core->Assign(1, new Val(${val.dialect_index}, TYPE_COUNT));
|
||||
core->Assign(2, new Val(${val.core.byte_count}, 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, new Val(time_from_lanman(${val.lanman.server_time.two_seconds}, ${val.lanman.server_time.minutes},
|
||||
${val.lanman.server_time.hours}, ${val.lanman.server_date.day},
|
||||
${val.lanman.server_date.month}, ${val.lanman.server_date.year},
|
||||
${val.lanman.server_tz}), TYPE_TIME));
|
||||
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, new Val(time_from_ntlm(${val.ntlm.server_time}, ${val.ntlm.server_tz}), TYPE_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}));
|
||||
// ntlm->Assign(13, bytestring_to_val(${val.ntlm.security_blob}));
|
||||
}
|
||||
|
||||
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: SMB_NTLM_SSP(header) &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;
|
||||
};
|
||||
|
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);
|
||||
};
|
120
src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac
Normal file
120
src/analyzer/protocol/smb/smb1-com-nt-create-andx.pac
Normal file
|
@ -0,0 +1,120 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
%member{
|
||||
bool is_atsvc;
|
||||
%}
|
||||
|
||||
%init{
|
||||
is_atsvc = false;
|
||||
%}
|
||||
|
||||
function isATSVC(): bool
|
||||
%{
|
||||
return is_atsvc;
|
||||
%}
|
||||
|
||||
function proc_smb1_nt_create_andx_request(header: SMB_Header, val: SMB1_nt_create_andx_request): bool
|
||||
%{
|
||||
if ( ${val.filename.u.s}->size() == 14 && ${val.filename.u.s[0]} == '\\' && ${val.filename.u.s[2]} == 'a' && ${val.filename.u.s[4]} == 't' && ${val.filename.u.s[6]} == 's' && ${val.filename.u.s[8]} == 'v' && ${val.filename.u.s[10]} == 'c' )
|
||||
is_atsvc = true;
|
||||
|
||||
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;
|
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);
|
||||
};
|
||||
|
88
src/analyzer/protocol/smb/smb1-com-read-andx.pac
Normal file
88
src/analyzer/protocol/smb/smb1-com-read-andx.pac
Normal file
|
@ -0,0 +1,88 @@
|
|||
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.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 {
|
||||
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;
|
229
src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac
Normal file
229
src/analyzer/protocol/smb/smb1-com-session-setup-andx.pac
Normal file
|
@ -0,0 +1,229 @@
|
|||
## 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(12, bytestring_to_val(${val.ntlm_extended_security.security_blob}));
|
||||
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;
|
||||
case 0: // 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 : SMB_NTLM_SSP(header) &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);
|
||||
};
|
||||
|
||||
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 : SMB_NTLM_SSP(header) &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;
|
||||
};
|
||||
|
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, data_count, 0, SMB_UNKNOWN);
|
||||
};
|
90
src/analyzer/protocol/smb/smb1-com-transaction.pac
Normal file
90
src/analyzer/protocol/smb/smb1-com-transaction.pac
Normal file
|
@ -0,0 +1,90 @@
|
|||
enum Trans_subcommands {
|
||||
NT_TRANSACT_QUERY_QUOTA = 0x0007,
|
||||
NT_TRANSACT_SET_QUOTA = 0x0008,
|
||||
NT_TRANSACT_CREATE2 = 0x0009,
|
||||
};
|
||||
|
||||
|
||||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb1_transaction_request(header: SMB_Header, val: SMB1_transaction_request): bool
|
||||
%{
|
||||
//printf("transaction_request\n");
|
||||
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, count: uint16, sub_cmd: uint16,
|
||||
trans_type: TransactionType ) = 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, sub_cmd);
|
||||
SMB_PIPE -> pipe : SMB_Pipe_message(header.unicode, count, sub_cmd);
|
||||
# SMB_UNKNOWN -> unknown : bytestring &restofdata;
|
||||
# default -> data : bytestring &restofdata;
|
||||
};
|
||||
|
||||
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 : uint16[setup_count];
|
||||
|
||||
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, data_count, sub_cmd, determine_transaction_type(setup_count, name));
|
||||
} &let {
|
||||
sub_cmd : uint16 = setup_count ? setup[0] : 0;
|
||||
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;
|
||||
handle_response : case $context.connection.isATSVC() of {
|
||||
true -> pipe_data : SMB1_transaction_data(header, data_count, 0, SMB_PIPE);
|
||||
# false -> unk_data : SMB1_transaction_data(header, data_count, 0, SMB_UNKNOWN);
|
||||
};
|
||||
} &let {
|
||||
proc : bool = $context.connection.proc_smb1_transaction_response(header, this);
|
||||
};
|
308
src/analyzer/protocol/smb/smb1-com-transaction2.pac
Normal file
308
src/analyzer/protocol/smb/smb1-com-transaction2.pac
Normal file
|
@ -0,0 +1,308 @@
|
|||
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
|
||||
%{
|
||||
//printf("transaction2_request sub command: %d\n", ${val.sub_cmd});
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb1_transaction2_response(header: SMB_Header, val: SMB1_transaction2_response): bool
|
||||
%{
|
||||
//printf("transaction2_response sub command: %d\n", ${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
|
||||
%{
|
||||
// TODO: implement this.
|
||||
//printf("trans2_find_first2 request!\n");
|
||||
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
|
||||
%{
|
||||
// TODO: implement this.
|
||||
//printf("trans2_query_path_info request!\n");
|
||||
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 {
|
||||
level_of_interest : 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;
|
||||
level_of_interest : 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
|
||||
%{
|
||||
// TODO: implement this.
|
||||
//printf("trans2_get_dfs_referral request!\n");
|
||||
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);
|
||||
};
|
||||
|
||||
###########################################
|
54
src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac
Normal file
54
src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac
Normal file
|
@ -0,0 +1,54 @@
|
|||
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
|
||||
%{
|
||||
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);
|
||||
};
|
75
src/analyzer/protocol/smb/smb1-com-write-andx.pac
Normal file
75
src/analyzer/protocol/smb/smb1-com-write-andx.pac
Normal file
|
@ -0,0 +1,75 @@
|
|||
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.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 {
|
||||
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));
|
||||
}
|
||||
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;
|
||||
%}
|
||||
};
|
5
src/analyzer/protocol/smb/smb1_com_check_directory.bif
Normal file
5
src/analyzer/protocol/smb/smb1_com_check_directory.bif
Normal file
|
@ -0,0 +1,5 @@
|
|||
## TODO
|
||||
event smb1_check_directory_request%(c: connection, hdr: SMB1::Header, directory_name: string%);
|
||||
|
||||
## TODO
|
||||
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%);
|
||||
|
5
src/analyzer/protocol/smb/smb1_com_create_directory.bif
Normal file
5
src/analyzer/protocol/smb/smb1_com_create_directory.bif
Normal file
|
@ -0,0 +1,5 @@
|
|||
## TODO
|
||||
event smb1_create_directory_request%(c: connection, hdr: SMB1::Header, directory_name: string%);
|
||||
|
||||
## TODO
|
||||
event smb1_create_directory_response%(c: connection, hdr: SMB1::Header%);
|
5
src/analyzer/protocol/smb/smb1_com_echo.bif
Normal file
5
src/analyzer/protocol/smb/smb1_com_echo.bif
Normal file
|
@ -0,0 +1,5 @@
|
|||
## TODO
|
||||
event smb1_echo_request%(c: connection, data: string%);
|
||||
|
||||
## TODO
|
||||
event smb1_echo_response%(c: connection, 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.
|
||||
##
|
||||
## hdr: The parsed header of the SMB message.
|
||||
event smb1_logoff_andx%(c: connection, is_orig: bool%);
|
||||
|
33
src/analyzer/protocol/smb/smb1_com_negotiate.bif
Normal file
33
src/analyzer/protocol/smb/smb1_com_negotiate.bif
Normal file
|
@ -0,0 +1,33 @@
|
|||
## 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.
|
||||
event smb1_negotiate_request%(c: connection, hdr: SMB1::Header, dialects: string_vec%);
|
||||
|
||||
## 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.
|
||||
event smb1_negotiate_response%(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse%);
|
||||
|
||||
#### Types
|
||||
|
||||
type SMB1::NegotiateResponse: record;
|
||||
type SMB1::NegotiateResponseCore: record;
|
||||
type SMB1::NegotiateResponseLANMAN: record;
|
||||
type SMB1::NegotiateResponseNTLM: record;
|
||||
type SMB1::NegotiateResponseSecurity: record;
|
||||
type SMB1::NegotiateRawMode: record;
|
||||
type SMB1::NegotiateCapabilities: record;
|
2
src/analyzer/protocol/smb/smb1_com_nt_cancel.bif
Normal file
2
src/analyzer/protocol/smb/smb1_com_nt_cancel.bif
Normal file
|
@ -0,0 +1,2 @@
|
|||
## TODO
|
||||
event smb1_nt_cancel_request%(c: connection, hdr: SMB1::Header%);
|
15
src/analyzer/protocol/smb/smb1_com_nt_create_andx.bif
Normal file
15
src/analyzer/protocol/smb/smb1_com_nt_create_andx.bif
Normal file
|
@ -0,0 +1,15 @@
|
|||
## 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.
|
||||
event smb1_nt_create_andx_request%(c: connection, hdr: SMB1::Header, file_name: string%);
|
||||
event smb1_nt_create_andx_response%(c: connection, hdr: SMB1::Header, file_id: count, file_size: count, times: SMB::MACTimes%);
|
||||
|
||||
|
38
src/analyzer/protocol/smb/smb1_com_open_andx.bif
Normal file
38
src/analyzer/protocol/smb/smb1_com_open_andx.bif
Normal file
|
@ -0,0 +1,38 @@
|
|||
## Generated for SMB/CIFS request messages of type *open 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.
|
||||
##
|
||||
## flags: Flags requesting attribute data and locking.
|
||||
##
|
||||
## access_mode: The requested access mode.
|
||||
##
|
||||
## search_attrs: The set of attributes that the file MUST have in order to be found.
|
||||
##
|
||||
## file_attrs: The set of attributes that the file is to have if the file needs to be created.
|
||||
##
|
||||
## creation_time: The time of creation if the file is created.
|
||||
##
|
||||
## open_mode: The way a file s
|
||||
##
|
||||
## length: The number of bytes being requested.
|
||||
event smb1_open_andx_request%(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count%);
|
||||
|
||||
## Generated for SMB/CIFS response messages of type *open 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_len: The length of data from the requested file.
|
||||
event smb1_open_andx_response%(c: connection, hdr: SMB1::Header, data_len: count%);
|
||||
|
3
src/analyzer/protocol/smb/smb1_com_query_information.bif
Normal file
3
src/analyzer/protocol/smb/smb1_com_query_information.bif
Normal file
|
@ -0,0 +1,3 @@
|
|||
# TODO
|
||||
event smb1_query_information_request%(c: connection, hdr: SMB1::Header, filename: string%);
|
||||
|
30
src/analyzer/protocol/smb/smb1_com_read_andx.bif
Normal file
30
src/analyzer/protocol/smb/smb1_com_read_andx.bif
Normal file
|
@ -0,0 +1,30 @@
|
|||
## Generated for SMB/CIFS request 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.
|
||||
##
|
||||
## file_id: The file identifier being written to.
|
||||
##
|
||||
## offset: The byte offset the requested read begins at.
|
||||
##
|
||||
## length: The number of bytes being requested.
|
||||
event smb1_read_andx_request%(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count%);
|
||||
|
||||
## Generated for SMB/CIFS response 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_len: The length of data from the requested file.
|
||||
event smb1_read_andx_response%(c: connection, hdr: SMB1::Header, data_len: count%);
|
||||
|
33
src/analyzer/protocol/smb/smb1_com_session_setup_andx.bif
Normal file
33
src/analyzer/protocol/smb/smb1_com_session_setup_andx.bif
Normal file
|
@ -0,0 +1,33 @@
|
|||
## Generated for SMB/CIFS requests 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.
|
||||
##
|
||||
## request: The parsed request data of the SMB message. See init-bare for more details.
|
||||
##
|
||||
event smb1_session_setup_andx_request%(c: connection, hdr: SMB1::Header, request: SMB1::SessionSetupAndXRequest%);
|
||||
|
||||
## Generated for SMB/CIFS responses 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.
|
||||
##
|
||||
## response: The parsed response data of the SMB message. See init-bare for more details.
|
||||
##
|
||||
event smb1_session_setup_andx_response%(c: connection, hdr: SMB1::Header, response: SMB1::SessionSetupAndXResponse%);
|
||||
|
||||
#### Types
|
||||
|
||||
type SMB1::SessionSetupAndXRequest: record;
|
||||
type SMB1::SessionSetupAndXResponse: record;
|
||||
type SMB1::SessionSetupAndXCapabilities: record;
|
16
src/analyzer/protocol/smb/smb1_com_tree_connect_andx.bif
Normal file
16
src/analyzer/protocol/smb/smb1_com_tree_connect_andx.bif
Normal file
|
@ -0,0 +1,16 @@
|
|||
## 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.
|
||||
event smb1_tree_connect_andx_request%(c: connection, hdr: SMB1::Header, path: string, service: string%);
|
||||
event smb1_tree_connect_andx_response%(c: connection, hdr: SMB1::Header, service: string, native_file_system: string%);
|
||||
|
9
src/analyzer/protocol/smb/smb1_com_tree_disconnect.bif
Normal file
9
src/analyzer/protocol/smb/smb1_com_tree_disconnect.bif
Normal file
|
@ -0,0 +1,9 @@
|
|||
## 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.
|
||||
event smb1_tree_disconnect%(c: connection, hdr: SMB1::Header, is_orig: bool%);
|
||||
|
27
src/analyzer/protocol/smb/smb1_com_write_andx.bif
Normal file
27
src/analyzer/protocol/smb/smb1_com_write_andx.bif
Normal file
|
@ -0,0 +1,27 @@
|
|||
## Generated for SMB/CIFS request messages of type *write 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.
|
||||
##
|
||||
## offset: The byte offset into the referenced file data is being written.
|
||||
##
|
||||
## data: The data being written.
|
||||
event smb1_write_andx_request%(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count%);
|
||||
|
||||
## Generated for SMB/CIFS response messages of type *write 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.
|
||||
##
|
||||
## written_bytes: The number of bytes the server reported having actually written.
|
||||
event smb1_write_andx_response%(c: connection, hdr: SMB1::Header, written_bytes: count%);
|
29
src/analyzer/protocol/smb/smb1_events.bif
Normal file
29
src/analyzer/protocol/smb/smb1_events.bif
Normal file
|
@ -0,0 +1,29 @@
|
|||
## 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.
|
||||
event smb1_message%(c: connection, hdr: SMB1::Header, is_orig: bool%);
|
||||
|
||||
## Generated when there is an SMB response with no message body.
|
||||
##
|
||||
## c: The connection.
|
||||
##
|
||||
## hdr: The parsed header of the SMB message.
|
||||
event smb1_empty_response%(c: connection, hdr: SMB1::Header%);
|
||||
|
||||
## 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.
|
||||
event smb1_error%(c: connection, hdr: SMB1::Header%);
|
||||
|
63
src/analyzer/protocol/smb/smb2-com-close.pac
Normal file
63
src/analyzer/protocol/smb/smb2-com-close.pac
Normal file
|
@ -0,0 +1,63 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb2_close_request(h: SMB2_Header, val: SMB2_close_request): bool
|
||||
%{
|
||||
if ( smb2_close_request )
|
||||
{
|
||||
BifEvent::generate_smb2_close_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
BuildSMB2GUID(${val.file_id}));
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_close_response(h: SMB2_Header, val: SMB2_close_response): bool
|
||||
%{
|
||||
if ( smb2_close_response )
|
||||
{
|
||||
RecordVal* resp = new RecordVal(BifType::Record::SMB2::CloseResponse);
|
||||
|
||||
resp->Assign(0, new Val(${val.alloc_size}, TYPE_COUNT));
|
||||
resp->Assign(1, new Val(${val.eof}, TYPE_COUNT));
|
||||
resp->Assign(2, SMB_BuildMACTimes(${val.last_write_time},
|
||||
${val.last_access_time},
|
||||
${val.creation_time},
|
||||
${val.change_time}));
|
||||
resp->Assign(3, smb2_file_attrs_to_bro(${val.file_attrs}));
|
||||
|
||||
BifEvent::generate_smb2_close_response(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
resp);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
type SMB2_close_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
flags : uint16;
|
||||
reserved : uint32;
|
||||
file_id : SMB2_guid;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_close_request(header, this);
|
||||
};
|
||||
|
||||
type SMB2_close_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
flags : uint16;
|
||||
reserved : uint32;
|
||||
|
||||
creation_time : SMB_timestamp;
|
||||
last_access_time : SMB_timestamp;
|
||||
last_write_time : SMB_timestamp;
|
||||
change_time : SMB_timestamp;
|
||||
alloc_size : uint64;
|
||||
eof : uint64;
|
||||
file_attrs : SMB2_file_attributes;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_close_response(header, this);
|
||||
};
|
115
src/analyzer/protocol/smb/smb2-com-create.pac
Normal file
115
src/analyzer/protocol/smb/smb2-com-create.pac
Normal file
|
@ -0,0 +1,115 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb2_create_request(h: SMB2_Header, val: SMB2_create_request): bool
|
||||
%{
|
||||
if ( smb2_create_request )
|
||||
{
|
||||
BifEvent::generate_smb2_create_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
smb2_string2stringval(${val.filename}));
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_create_response(h: SMB2_Header, val: SMB2_create_response): bool
|
||||
%{
|
||||
if ( smb2_create_response )
|
||||
{
|
||||
BifEvent::generate_smb2_create_response(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
BuildSMB2GUID(${val.file_id}),
|
||||
${val.eof},
|
||||
SMB_BuildMACTimes(${val.last_write_time},
|
||||
${val.last_access_time},
|
||||
${val.creation_time},
|
||||
${val.change_time}),
|
||||
smb2_file_attrs_to_bro(${val.file_attrs}));
|
||||
}
|
||||
|
||||
if ( ${val.eof} > 0 )
|
||||
{
|
||||
file_mgr->SetSize(${val.eof},
|
||||
bro_analyzer()->GetAnalyzerTag(),
|
||||
bro_analyzer()->Conn(),
|
||||
h->is_orig());
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
type SMB2_create_context = record {
|
||||
next_offset : uint32;
|
||||
name_offset : uint16;
|
||||
name_len : uint16;
|
||||
reserved : uint16;
|
||||
data_offset : uint16;
|
||||
data_len : uint32;
|
||||
name_pad : padding to name_offset;
|
||||
name : SMB2_string(name_len);
|
||||
data_pad : padding to data_offset;
|
||||
data : SMB2_string(data_len);
|
||||
next_context_pad : padding to next_offset;
|
||||
};
|
||||
|
||||
type SMB2_create_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
sec_flags_reserved : uint8; # ignored
|
||||
oplock : uint8;
|
||||
impersonation_level : uint32;
|
||||
flags : bytestring &length=8; # ignored
|
||||
reserved : bytestring &length=8; # ignored
|
||||
access_mask : uint32;
|
||||
file_attrs : SMB2_file_attributes;
|
||||
share_access : uint32;
|
||||
disposition : uint32;
|
||||
create_options : uint32;
|
||||
filename_offset : uint16;
|
||||
filename_len : uint16;
|
||||
context_offset : uint32;
|
||||
context_len : uint32;
|
||||
filename_pad : padding to filename_offset - header.head_length;
|
||||
filename : SMB2_string(filename_len);
|
||||
# If there are no context records, the context_offset will
|
||||
# be set to zero so we need to deal with that to avoid
|
||||
# negative wrap around in the padding.
|
||||
context_pad : padding to (context_offset==0 ? 0 : context_offset - header.head_length);
|
||||
create : case context_len of {
|
||||
0 -> blank : empty;
|
||||
default -> contexts : SMB2_create_context[] &length=context_len;
|
||||
};
|
||||
} &let {
|
||||
proc : bool = $context.connection.proc_smb2_create_request(header, this);
|
||||
};
|
||||
|
||||
|
||||
type SMB2_create_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
oplock : uint8;
|
||||
reserved : uint8;
|
||||
create_action : uint32;
|
||||
creation_time : SMB_timestamp;
|
||||
last_access_time : SMB_timestamp;
|
||||
last_write_time : SMB_timestamp;
|
||||
change_time : SMB_timestamp;
|
||||
alloc_size : uint64;
|
||||
eof : uint64;
|
||||
file_attrs : SMB2_file_attributes;
|
||||
reserved2 : uint32;
|
||||
file_id : SMB2_guid;
|
||||
context_offset : uint32;
|
||||
context_len : uint32;
|
||||
# If there are no context records, the context_offset will
|
||||
# be set to zero so we need to deal with that to avoid
|
||||
# negative wrap around in the padding.
|
||||
context_pad : padding to (context_offset==0 ? 0 : context_offset - header.head_length);
|
||||
create : case context_len of {
|
||||
0 -> blank : empty;
|
||||
default -> contexts : SMB2_create_context[] &length=context_len;
|
||||
};
|
||||
} &let {
|
||||
proc : bool = $context.connection.proc_smb2_create_response(header, this);
|
||||
};
|
68
src/analyzer/protocol/smb/smb2-com-negotiate.pac
Normal file
68
src/analyzer/protocol/smb/smb2-com-negotiate.pac
Normal file
|
@ -0,0 +1,68 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb2_negotiate_request(h: SMB2_Header, val: SMB2_negotiate_request) : bool
|
||||
%{
|
||||
if ( smb2_negotiate_request )
|
||||
{
|
||||
VectorVal* dialects = new VectorVal(index_vec);
|
||||
for ( unsigned int i = 0; i < ${val.dialects}->size(); ++i )
|
||||
{
|
||||
dialects->Assign(i, new Val((*${val.dialects})[i], TYPE_COUNT));
|
||||
}
|
||||
BifEvent::generate_smb2_negotiate_request(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
dialects);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_negotiate_response(h: SMB2_Header, val: SMB2_negotiate_response) : bool
|
||||
%{
|
||||
if ( smb2_negotiate_response )
|
||||
{
|
||||
RecordVal* nr = new RecordVal(BifType::Record::SMB2::NegotiateResponse);
|
||||
|
||||
nr->Assign(0, new Val(${val.dialect_revision}, TYPE_COUNT));
|
||||
nr->Assign(1, new Val(${val.security_mode}, TYPE_COUNT));
|
||||
nr->Assign(2, BuildSMB2GUID(${val.server_guid})),
|
||||
nr->Assign(3, filetime2brotime(${val.system_time}));
|
||||
nr->Assign(4, filetime2brotime(${val.server_start_time}));
|
||||
BifEvent::generate_smb2_negotiate_response(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
nr);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
type SMB2_negotiate_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16; # client MUST set this to 36
|
||||
dialect_count : uint16; # must be > 0
|
||||
security_mode : uint16; # there is a list of required modes
|
||||
reserved : padding[2]; # must be set to 0
|
||||
capabilities : uint32; # must be set to 0
|
||||
client_guid : SMB2_guid; # guid if client implements SMB 2.1 dialect, otherwise set to 0
|
||||
client_start_time : SMB_timestamp; # must be set to 0
|
||||
dialects : uint16[dialect_count];
|
||||
} &byteorder=littleendian, &let {
|
||||
proc : bool = $context.connection.proc_smb2_negotiate_request(header, this);
|
||||
};
|
||||
|
||||
type SMB2_negotiate_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
security_mode : uint16;
|
||||
dialect_revision : uint16;
|
||||
reserved : padding[2];
|
||||
server_guid : SMB2_guid;
|
||||
capabilities : uint32;
|
||||
max_transact_size : uint32;
|
||||
max_read_size : uint32;
|
||||
max_write_size : uint32;
|
||||
system_time : SMB_timestamp;
|
||||
server_start_time : SMB_timestamp;
|
||||
security : SMB2_security;
|
||||
} &byteorder=littleendian, &let {
|
||||
proc : bool = $context.connection.proc_smb2_negotiate_response(header, this);
|
||||
};
|
73
src/analyzer/protocol/smb/smb2-com-read.pac
Normal file
73
src/analyzer/protocol/smb/smb2-com-read.pac
Normal file
|
@ -0,0 +1,73 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
%member{
|
||||
// Track read offsets to provide correct
|
||||
// offsets for file manager.
|
||||
std::map<uint16,uint64> smb2_read_offsets;
|
||||
%}
|
||||
|
||||
function proc_smb2_read_request(h: SMB2_Header, val: SMB2_read_request) : bool
|
||||
%{
|
||||
if ( smb2_read_request )
|
||||
{
|
||||
BifEvent::generate_smb2_read_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
BuildSMB2GUID(${val.file_id}),
|
||||
${val.offset},
|
||||
${val.read_len});
|
||||
}
|
||||
|
||||
smb2_read_offsets[${h.message_id}] = ${val.offset};
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_read_response(h: SMB2_Header, val: SMB2_read_response) : bool
|
||||
%{
|
||||
if ( ${val.data_len} > 0 )
|
||||
{
|
||||
uint64 offset = smb2_read_offsets[${h.message_id}];
|
||||
smb2_read_offsets.erase(${h.message_id});
|
||||
|
||||
file_mgr->DataIn(${val.data}.begin(), ${val.data_len}, offset,
|
||||
bro_analyzer()->GetAnalyzerTag(),
|
||||
bro_analyzer()->Conn(), h->is_orig());
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
type SMB2_read_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
pad : uint8;
|
||||
reserved : uint8;
|
||||
read_len : uint32;
|
||||
offset : uint64;
|
||||
file_id : SMB2_guid;
|
||||
minimum_count : uint32;
|
||||
channel : uint32;
|
||||
remaining_bytes : uint32;
|
||||
channel_info_offset : uint16;
|
||||
channel_info_len : uint16;
|
||||
|
||||
# These aren't used.
|
||||
pad : padding to channel_info_offset - header.head_length;
|
||||
buffer : bytestring &length = channel_info_len;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_read_request(header, this);
|
||||
};
|
||||
|
||||
type SMB2_read_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
data_offset : uint16;
|
||||
data_len : uint32;
|
||||
data_remaining : uint32;
|
||||
reserved : uint32;
|
||||
pad : padding to data_offset - header.head_length;
|
||||
data : bytestring &length=data_len;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_read_response(header, this);
|
||||
};
|
64
src/analyzer/protocol/smb/smb2-com-session-setup.pac
Normal file
64
src/analyzer/protocol/smb/smb2-com-session-setup.pac
Normal file
|
@ -0,0 +1,64 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb2_session_setup_request(h: SMB2_Header, val: SMB2_session_setup_request): bool
|
||||
%{
|
||||
if ( smb2_session_setup_request )
|
||||
{
|
||||
RecordVal* req = new RecordVal(BifType::Record::SMB2::SessionSetupRequest);
|
||||
req->Assign(0, new Val(${val.security_mode}, TYPE_COUNT));
|
||||
|
||||
BifEvent::generate_smb2_session_setup_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
req);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_session_setup_response(h: SMB2_Header, val: SMB2_session_setup_response): bool
|
||||
%{
|
||||
if ( smb2_session_setup_response )
|
||||
{
|
||||
RecordVal* flags = new RecordVal(BifType::Record::SMB2::SessionSetupFlags);
|
||||
flags->Assign(0, new Val(${val.flag_guest}, TYPE_BOOL));
|
||||
flags->Assign(1, new Val(${val.flag_anonymous}, TYPE_BOOL));
|
||||
flags->Assign(2, new Val(${val.flag_encrypt}, TYPE_BOOL));
|
||||
|
||||
RecordVal* resp = new RecordVal(BifType::Record::SMB2::SessionSetupResponse);
|
||||
resp->Assign(0, flags);
|
||||
|
||||
BifEvent::generate_smb2_session_setup_response(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
resp);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
|
||||
type SMB2_session_setup_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
vc_number : uint8;
|
||||
security_mode : uint8;
|
||||
capabilities : uint32;
|
||||
channel : uint32;
|
||||
security : SMB2_security;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_session_setup_request(header, this);
|
||||
};
|
||||
|
||||
type SMB2_session_setup_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
session_flags : uint16;
|
||||
security : SMB2_security;
|
||||
} &let {
|
||||
flag_guest = (session_flags & 0x1) > 0;
|
||||
flag_anonymous = (session_flags & 0x2) > 0;
|
||||
flag_encrypt = (session_flags & 0x4) > 0;
|
||||
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_session_setup_response(header, this);
|
||||
};
|
55
src/analyzer/protocol/smb/smb2-com-tree-connect.pac
Normal file
55
src/analyzer/protocol/smb/smb2-com-tree-connect.pac
Normal file
|
@ -0,0 +1,55 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb2_tree_connect_request(header: SMB2_Header, val: SMB2_tree_connect_request): bool
|
||||
%{
|
||||
if ( smb2_tree_connect_request )
|
||||
BifEvent::generate_smb2_tree_connect_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(header),
|
||||
smb2_string2stringval(${val.path}));
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_tree_connect_response(header: SMB2_Header, val: SMB2_tree_connect_response): bool
|
||||
%{
|
||||
if ( smb2_tree_connect_response )
|
||||
{
|
||||
RecordVal* resp = new RecordVal(BifType::Record::SMB2::TreeConnectResponse);
|
||||
|
||||
resp->Assign(0, new Val(${val.share_type}, TYPE_COUNT));
|
||||
|
||||
BifEvent::generate_smb2_tree_connect_response(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(header),
|
||||
resp);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
type SMB2_tree_connect_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : padding[2];
|
||||
path_offset : uint16;
|
||||
path_length : uint16;
|
||||
|
||||
pad : padding to path_offset - header.head_length;
|
||||
path : SMB2_string(path_length);
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_tree_connect_request(header, this);
|
||||
};
|
||||
|
||||
type SMB2_tree_connect_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
share_type : uint8;
|
||||
reserved : padding[1];
|
||||
share_flags : uint32;
|
||||
capabilities : uint32;
|
||||
maximal_access : uint32;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_smb2_tree_connect_response(header, this);
|
||||
};
|
||||
|
9
src/analyzer/protocol/smb/smb2-com-tree-disconnect.pac
Normal file
9
src/analyzer/protocol/smb/smb2-com-tree-disconnect.pac
Normal file
|
@ -0,0 +1,9 @@
|
|||
type SMB2_tree_disconnect_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
||||
|
||||
type SMB2_tree_disconnect_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
60
src/analyzer/protocol/smb/smb2-com-write.pac
Normal file
60
src/analyzer/protocol/smb/smb2-com-write.pac
Normal file
|
@ -0,0 +1,60 @@
|
|||
refine connection SMB_Conn += {
|
||||
|
||||
function proc_smb2_write_request(h: SMB2_Header, val: SMB2_write_request) : bool
|
||||
%{
|
||||
if ( smb2_write_request )
|
||||
{
|
||||
BifEvent::generate_smb2_write_request(bro_analyzer(),
|
||||
bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
BuildSMB2GUID(${val.file_id}),
|
||||
${val.offset},
|
||||
${val.data_len});
|
||||
}
|
||||
|
||||
if ( ${val.data}.length() > 0 )
|
||||
{
|
||||
file_mgr->DataIn(${val.data}.begin(), ${val.data_len}, ${val.offset},
|
||||
bro_analyzer()->GetAnalyzerTag(),
|
||||
bro_analyzer()->Conn(), h->is_orig());
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_smb2_write_response(h: SMB2_Header, val: SMB2_write_response) : bool
|
||||
%{
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
|
||||
type SMB2_write_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
data_offset : uint16;
|
||||
data_len : uint32;
|
||||
offset : uint64;
|
||||
file_id : SMB2_guid;
|
||||
channel : uint32; # ignore
|
||||
data_remaining : uint32;
|
||||
channel_info_offset : uint16; # ignore
|
||||
channel_info_len : uint16; # ignore
|
||||
flags : uint32;
|
||||
pad : padding to data_offset - header.head_length;
|
||||
data : bytestring &length=data_len;
|
||||
} &let {
|
||||
proc : bool = $context.connection.proc_smb2_write_request(header, this);
|
||||
};
|
||||
|
||||
type SMB2_write_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
write_count : uint32;
|
||||
remaining : uint32;
|
||||
channel_info_offset : uint16;
|
||||
channel_info_len : uint16;
|
||||
} &let {
|
||||
proc : bool = $context.connection.proc_smb2_write_response(header, this);
|
||||
};
|
426
src/analyzer/protocol/smb/smb2-protocol.pac
Normal file
426
src/analyzer/protocol/smb/smb2-protocol.pac
Normal file
|
@ -0,0 +1,426 @@
|
|||
# Documentation for SMB2 protocol from here:
|
||||
# http://msdn.microsoft.com/en-us/library/cc246497(v=PROT.13).aspx
|
||||
|
||||
enum smb2_commands {
|
||||
SMB2_NEGOTIATE_PROTOCOL = 0,
|
||||
SMB2_SESSION_SETUP = 1,
|
||||
SMB2_LOGOFF = 2,
|
||||
SMB2_TREE_CONNECT = 3,
|
||||
SMB2_TREE_DISCONNECT = 4,
|
||||
SMB2_CREATE = 5,
|
||||
SMB2_CLOSE = 6,
|
||||
SMB2_FLUSH = 7,
|
||||
SMB2_READ = 8,
|
||||
SMB2_WRITE = 9,
|
||||
SMB2_LOCK = 10,
|
||||
SMB2_IOCTL = 11,
|
||||
SMB2_CANCEL = 12,
|
||||
SMB2_ECHO = 13,
|
||||
SMB2_QUERY_DIRECTORY = 14,
|
||||
SMB2_CHANGE_NOTIFY = 15,
|
||||
SMB2_QUERY_INFO = 16,
|
||||
SMB2_SET_INFO = 17,
|
||||
SMB2_OPLOCK_BREAK = 18,
|
||||
};
|
||||
|
||||
type SMB2_PDU(is_orig: bool) = record {
|
||||
header : SMB2_Header(is_orig);
|
||||
message : case header.status of {
|
||||
# Status 0 indicates success. In the case of a
|
||||
# request this should just happen to work out due to
|
||||
# how the fields are set.
|
||||
0 -> msg : SMB2_Message(header, is_orig);
|
||||
0xC0000016 -> more_processing_required : SMB2_Message(header, is_orig);
|
||||
default -> err : SMB2_error_response(header);
|
||||
};
|
||||
};
|
||||
|
||||
type SMB2_Message(header: SMB2_Header, is_orig: bool) = case is_orig of {
|
||||
true -> request : SMB2_Message_Request(header);
|
||||
false -> response : SMB2_Message_Response(header);
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type SMB2_Message_Request(header: SMB2_Header) = case header.command of {
|
||||
SMB2_NEGOTIATE_PROTOCOL -> negotiate_protocol : SMB2_negotiate_request(header);
|
||||
SMB2_SESSION_SETUP -> session_setup : SMB2_session_setup_request(header);
|
||||
SMB2_TREE_CONNECT -> tree_connect : SMB2_tree_connect_request(header);
|
||||
SMB2_TREE_DISCONNECT -> tree_disconnect : SMB2_tree_disconnect_request(header);
|
||||
SMB2_CREATE -> create : SMB2_create_request(header);
|
||||
SMB2_CLOSE -> close : SMB2_close_request(header);
|
||||
SMB2_FLUSH -> flush : SMB2_flush_request(header);
|
||||
SMB2_READ -> read : SMB2_read_request(header);
|
||||
SMB2_WRITE -> write : SMB2_write_request(header);
|
||||
SMB2_LOCK -> lock : SMB2_lock_request(header);
|
||||
SMB2_IOCTL -> ioctl : SMB2_ioctl_request(header);
|
||||
SMB2_CANCEL -> cancel : SMB2_cancel_request(header);
|
||||
SMB2_ECHO -> echo : SMB2_echo_request(header);
|
||||
SMB2_QUERY_DIRECTORY -> query_directory : SMB2_query_directory_request(header);
|
||||
SMB2_CHANGE_NOTIFY -> change_notify : SMB2_change_notify_request(header);
|
||||
SMB2_QUERY_INFO -> query_info : SMB2_query_info_request(header);
|
||||
SMB2_SET_INFO -> set_info : SMB2_set_info_request(header);
|
||||
SMB2_OPLOCK_BREAK -> oplock_break : SMB2_oplock_break(header);
|
||||
|
||||
default -> unknown_msg : empty; # TODO: do something different here!
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type SMB2_Message_Response(header: SMB2_Header) = case header.command of {
|
||||
SMB2_NEGOTIATE_PROTOCOL -> negotiate_protocol : SMB2_negotiate_response(header);
|
||||
SMB2_SESSION_SETUP -> session_setup : SMB2_session_setup_response(header);
|
||||
SMB2_TREE_CONNECT -> tree_connect : SMB2_tree_connect_response(header);
|
||||
SMB2_TREE_DISCONNECT -> tree_disconnect : SMB2_tree_disconnect_response(header);
|
||||
SMB2_CREATE -> create : SMB2_create_response(header);
|
||||
SMB2_CLOSE -> close : SMB2_close_response(header);
|
||||
SMB2_FLUSH -> flush : SMB2_flush_response(header);
|
||||
SMB2_READ -> read : SMB2_read_response(header);
|
||||
SMB2_WRITE -> write : SMB2_write_response(header);
|
||||
SMB2_LOCK -> lock : SMB2_lock_response(header);
|
||||
SMB2_IOCTL -> ioctl : SMB2_ioctl_response(header);
|
||||
SMB2_ECHO -> echo : SMB2_echo_response(header);
|
||||
SMB2_QUERY_DIRECTORY -> query_directory : SMB2_query_directory_response(header);
|
||||
SMB2_CHANGE_NOTIFY -> change_notify : SMB2_change_notify_response(header);
|
||||
SMB2_QUERY_INFO -> query_info : SMB2_query_info_response(header);
|
||||
SMB2_SET_INFO -> set_info : SMB2_set_info_response(header);
|
||||
SMB2_OPLOCK_BREAK -> oplock_break : SMB2_oplock_break(header);
|
||||
|
||||
default -> unknown_msg : empty; # TODO: do something different here!
|
||||
} &byteorder=littleendian;
|
||||
|
||||
refine connection SMB_Conn += {
|
||||
|
||||
function BuildSMB2HeaderVal(hdr: SMB2_Header): BroVal
|
||||
%{
|
||||
RecordVal* r = new RecordVal(BifType::Record::SMB2::Header);
|
||||
|
||||
r->Assign(0, new Val(${hdr.credit_charge}, TYPE_COUNT));
|
||||
r->Assign(1, new Val(${hdr.status}, TYPE_COUNT));
|
||||
r->Assign(2, new Val(${hdr.command}, TYPE_COUNT));
|
||||
r->Assign(3, new Val(${hdr.credits}, TYPE_COUNT));
|
||||
r->Assign(4, new Val(${hdr.flags}, TYPE_COUNT));
|
||||
r->Assign(5, new Val(${hdr.message_id}, TYPE_COUNT));
|
||||
r->Assign(6, new Val(${hdr.process_id}, TYPE_COUNT));
|
||||
r->Assign(7, new Val(${hdr.tree_id}, TYPE_COUNT));
|
||||
r->Assign(8, new Val(${hdr.session_id}, TYPE_COUNT));
|
||||
r->Assign(9, bytestring_to_val(${hdr.signature}));
|
||||
|
||||
return r;
|
||||
%}
|
||||
|
||||
function BuildSMB2GUID(file_id: SMB2_guid): BroVal
|
||||
%{
|
||||
RecordVal* r = new RecordVal(BifType::Record::SMB2::GUID);
|
||||
|
||||
r->Assign(0, new Val(${file_id.persistent}, TYPE_COUNT));
|
||||
r->Assign(1, new Val(${file_id._volatile}, TYPE_COUNT));
|
||||
|
||||
return r;
|
||||
%}
|
||||
|
||||
function proc_smb2_message(h: SMB2_Header, is_orig: bool): bool
|
||||
%{
|
||||
//if ( ${h.command} == SMB2_READ )
|
||||
// printf("got a read %s command\n", is_orig ? "request" : "response");
|
||||
|
||||
if ( smb2_message )
|
||||
{
|
||||
BifEvent::generate_smb2_message(bro_analyzer(), bro_analyzer()->Conn(),
|
||||
BuildSMB2HeaderVal(h),
|
||||
is_orig);
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
function smb2_file_attrs_to_bro(val: SMB2_file_attributes): BroVal
|
||||
%{
|
||||
RecordVal* r = new RecordVal(BifType::Record::SMB2::FileAttrs);
|
||||
|
||||
r->Assign(0, new Val(${val.read_only}, TYPE_BOOL));
|
||||
r->Assign(1, new Val(${val.hidden}, TYPE_BOOL));
|
||||
r->Assign(2, new Val(${val.system}, TYPE_BOOL));
|
||||
r->Assign(3, new Val(${val.directory}, TYPE_BOOL));
|
||||
r->Assign(4, new Val(${val.archive}, TYPE_BOOL));
|
||||
r->Assign(5, new Val(${val.normal}, TYPE_BOOL));
|
||||
r->Assign(6, new Val(${val.temporary}, TYPE_BOOL));
|
||||
r->Assign(7, new Val(${val.sparse_file}, TYPE_BOOL));
|
||||
r->Assign(8, new Val(${val.reparse_point}, TYPE_BOOL));
|
||||
r->Assign(9, new Val(${val.compressed}, TYPE_BOOL));
|
||||
r->Assign(10, new Val(${val.offline}, TYPE_BOOL));
|
||||
r->Assign(11, new Val(${val.not_content_indexed}, TYPE_BOOL));
|
||||
r->Assign(12, new Val(${val.encrypted}, TYPE_BOOL));
|
||||
r->Assign(13, new Val(${val.integrity_stream}, TYPE_BOOL));
|
||||
r->Assign(14, new Val(${val.no_scrub_data}, TYPE_BOOL));
|
||||
|
||||
return r;
|
||||
%}
|
||||
|
||||
type SMB2_file_attributes = record {
|
||||
flags : uint32;
|
||||
} &let {
|
||||
read_only : bool = ( flags & 0x00000001 ) > 0;
|
||||
hidden : bool = ( flags & 0x00000002 ) > 0;
|
||||
system : bool = ( flags & 0x00000004 ) > 0;
|
||||
directory : bool = ( flags & 0x00000010 ) > 0;
|
||||
archive : bool = ( flags & 0x00000020 ) > 0;
|
||||
normal : bool = ( flags & 0x00000080 ) > 0;
|
||||
temporary : bool = ( flags & 0x00000100 ) > 0;
|
||||
sparse_file : bool = ( flags & 0x00000200 ) > 0;
|
||||
reparse_point : bool = ( flags & 0x00000400 ) > 0;
|
||||
compressed : bool = ( flags & 0x00000800 ) > 0;
|
||||
offline : bool = ( flags & 0x00001000 ) > 0;
|
||||
not_content_indexed : bool = ( flags & 0x00002000 ) > 0;
|
||||
encrypted : bool = ( flags & 0x00004000 ) > 0;
|
||||
integrity_stream : bool = ( flags & 0x00008000 ) > 0;
|
||||
no_scrub_data : bool = ( flags & 0x00020000 ) > 0;
|
||||
};
|
||||
|
||||
type SMB2_Header(is_orig: bool) = record {
|
||||
head_length : uint16;
|
||||
credit_charge : uint16;
|
||||
status : uint32;
|
||||
command : uint16;
|
||||
credits : uint16;
|
||||
flags : uint32;
|
||||
next_command : uint32;
|
||||
message_id : uint64;
|
||||
process_id : uint32;
|
||||
tree_id : uint32;
|
||||
session_id : uint64;
|
||||
signature : bytestring &length = 16;
|
||||
} &let {
|
||||
response = (flags >> 24) & 1;
|
||||
async = (flags >> 25) & 1;
|
||||
related = (flags >> 26) & 1;
|
||||
msigned = (flags >> 27) & 1;
|
||||
dfs = (flags) & 1;
|
||||
proc : bool = $context.connection.proc_smb2_message(this, is_orig);
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type SMB2_security = record {
|
||||
buffer_offset : uint16;
|
||||
buffer_len : uint16;
|
||||
# TODO: handle previous session IDs
|
||||
sec_buffer : bytestring &length = buffer_len;
|
||||
} &byteorder = littleendian;
|
||||
|
||||
|
||||
# file ids and guids are the same thing and need unified somehow.
|
||||
type SMB2_guid = record {
|
||||
persistent : uint64;
|
||||
_volatile : uint64;
|
||||
};
|
||||
|
||||
type SMB2_lock = record {
|
||||
offset : uint64;
|
||||
len : uint64;
|
||||
flags : uint32;
|
||||
};
|
||||
|
||||
type SMB2_File_Notify_Information = record {
|
||||
next_entry_offset : uint32;
|
||||
action : uint32;
|
||||
filename_len : uint32;
|
||||
filename : SMB2_string(filename_len);
|
||||
};
|
||||
|
||||
type SMB2_symlink_error(byte_count: uint32) = record {
|
||||
sym_link_length : uint32;
|
||||
sym_link_err_tag : uint32;
|
||||
reparse_tag : uint32;
|
||||
reparse_data_len : uint16;
|
||||
unparsed_path_len : uint16;
|
||||
sub_name_offset : uint16;
|
||||
sub_name_length : uint16;
|
||||
print_name_offset : uint16;
|
||||
print_name_length : uint16;
|
||||
flags : uint32;
|
||||
path_buffer : bytestring &length = sub_name_length+print_name_length;
|
||||
} &let {
|
||||
absolute_target_path = (flags == 0x00000000);
|
||||
symlink_flag_relative = (flags == 0x00000001);
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type SMB2_error_data(byte_count: uint32) = case byte_count of {
|
||||
0 -> empty: empty;
|
||||
default -> error: SMB2_symlink_error(byte_count);
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type SMB2_error_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : padding[2];
|
||||
byte_count : uint32;
|
||||
error_data : SMB2_error_data(byte_count);
|
||||
} &byteorder = littleendian;
|
||||
|
||||
type SMB2_logoff_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
||||
|
||||
type SMB2_logoff_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
||||
|
||||
type SMB2_flush_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved1 : uint16;
|
||||
reserved2 : uint32;
|
||||
file_id : SMB2_guid;
|
||||
};
|
||||
|
||||
type SMB2_flush_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved1 : uint16;
|
||||
};
|
||||
|
||||
type SMB2_lock_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
lock_count : uint16;
|
||||
lock_seq : uint32;
|
||||
file_id : SMB2_guid;
|
||||
locks : SMB2_lock[lock_count];
|
||||
};
|
||||
|
||||
type SMB2_lock_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16; # ignore
|
||||
};
|
||||
|
||||
type SMB2_ioctl_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
ctl_code : uint32;
|
||||
file_id : SMB2_guid;
|
||||
input_offset : uint32;
|
||||
input_count : uint32;
|
||||
max_input_resp : uint32;
|
||||
output_offset : uint32;
|
||||
output_count : uint32;
|
||||
max_output_resp : uint32;
|
||||
flags : uint32;
|
||||
reserved2 : uint32;
|
||||
pad : padding to input_offset - header.head_length;
|
||||
input_buffer : bytestring &length = input_count;
|
||||
pad2 : padding to output_offset - header.head_length;
|
||||
output_buffer : bytestring &length=output_count;
|
||||
};
|
||||
|
||||
type SMB2_ioctl_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
ctl_code : uint32;
|
||||
file_id : SMB2_guid;
|
||||
input_offset : uint32;
|
||||
input_count : uint32;
|
||||
output_offset : uint32;
|
||||
output_count : uint32;
|
||||
flags : uint32;
|
||||
reserved2 : uint32;
|
||||
pad : padding to input_offset - header.head_length;
|
||||
input_buffer : bytestring &length=input_count;
|
||||
pad2 : padding to output_offset - header.head_length;
|
||||
output_buffer : bytestring &length=output_count;
|
||||
};
|
||||
|
||||
type SMB2_cancel_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
||||
|
||||
type SMB2_echo_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
||||
|
||||
type SMB2_echo_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
reserved : uint16;
|
||||
};
|
||||
|
||||
type SMB2_query_directory_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
_class : uint8;
|
||||
flags : uint8;
|
||||
file_index : uint32;
|
||||
file_id : SMB2_guid;
|
||||
file_name_offset : uint16;
|
||||
file_name_len : uint16;
|
||||
output_buffer_len : uint32;
|
||||
pad : padding to file_name_offset - header.head_length;
|
||||
file_name : bytestring &length = file_name_len;
|
||||
};
|
||||
|
||||
type SMB2_query_directory_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
buffer_offset : uint16;
|
||||
buffer_len : uint32;
|
||||
pad : padding to buffer_offset - header.head_length;
|
||||
buffer : bytestring &length = buffer_len;
|
||||
};
|
||||
|
||||
type SMB2_change_notify_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
flags : uint16;
|
||||
output_buffer_len : uint32;
|
||||
file_id : SMB2_guid;
|
||||
completion_filter : uint32;
|
||||
reserved : uint32;
|
||||
};
|
||||
|
||||
type SMB2_change_notify_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
output_buffer_offset : uint16;
|
||||
output_buffer_len : uint32;
|
||||
pad : padding to output_buffer_offset - header.head_length;
|
||||
buffer : SMB2_File_Notify_Information[] &length = output_buffer_len;
|
||||
};
|
||||
|
||||
type SMB2_query_info_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
info_type : uint8;
|
||||
file_info_class : uint8;
|
||||
output_buffer_len : uint32;
|
||||
input_buffer_offset : uint16;
|
||||
reserved : uint16;
|
||||
input_buffer_len : uint32;
|
||||
additional_info : uint32;
|
||||
flags : uint32;
|
||||
file_id : SMB2_guid;
|
||||
pad : padding to input_buffer_offset - header.head_length;
|
||||
buffer : bytestring &length = input_buffer_len;
|
||||
};
|
||||
|
||||
type SMB2_query_info_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
buffer_offset : uint16;
|
||||
buffer_len : uint32;
|
||||
pad : padding to buffer_offset - header.head_length;
|
||||
# TODO: a new structure needs to be created for this.
|
||||
buffer : bytestring &length = buffer_len;
|
||||
};
|
||||
|
||||
type SMB2_set_info_request(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
info_type : uint8;
|
||||
file_info_class : uint8;
|
||||
buffer_len : uint32;
|
||||
buffer_offset : uint16;
|
||||
reserved : uint16;
|
||||
additional_info : uint32;
|
||||
file_id : SMB2_guid;
|
||||
pad : padding to buffer_offset - header.head_length;
|
||||
# TODO: a new structure needs to be created for this.
|
||||
buffer : bytestring &length = buffer_len;
|
||||
};
|
||||
|
||||
type SMB2_set_info_response(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
};
|
||||
|
||||
type SMB2_oplock_break(header: SMB2_Header) = record {
|
||||
structure_size : uint16;
|
||||
oplock_level : uint8;
|
||||
reserved : uint8;
|
||||
reserved2 : uint32;
|
||||
file_id : SMB2_guid;
|
||||
};
|
4
src/analyzer/protocol/smb/smb2_com_close.bif
Normal file
4
src/analyzer/protocol/smb/smb2_com_close.bif
Normal file
|
@ -0,0 +1,4 @@
|
|||
event smb2_close_request%(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID%);
|
||||
event smb2_close_response%(c: connection, hdr: SMB2::Header, response: SMB2::CloseResponse%);
|
||||
|
||||
type SMB2::CloseResponse: record;
|
2
src/analyzer/protocol/smb/smb2_com_create.bif
Normal file
2
src/analyzer/protocol/smb/smb2_com_create.bif
Normal file
|
@ -0,0 +1,2 @@
|
|||
event smb2_create_request%(c: connection, hdr: SMB2::Header, file_name: string%);
|
||||
event smb2_create_response%(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, size: count, times: SMB::MACTimes, attrs: SMB2::FileAttrs%);
|
21
src/analyzer/protocol/smb/smb2_com_negotiate.bif
Normal file
21
src/analyzer/protocol/smb/smb2_com_negotiate.bif
Normal file
|
@ -0,0 +1,21 @@
|
|||
## Generated for SMB2 messages of type *negotiate*.
|
||||
##
|
||||
## c: The connection.
|
||||
##
|
||||
## hdr: The parsed header of the SMB2 message.
|
||||
##
|
||||
## dialects: A vector of the client's supported dialects.
|
||||
event smb2_negotiate_request%(c: connection, hdr: SMB2::Header, dialects: index_vec%);
|
||||
|
||||
## Generated for SMB2 messages of type *negotiate response*.
|
||||
##
|
||||
## c: The connection.
|
||||
##
|
||||
## hdr: The parsed header of the SMB2 message.
|
||||
##
|
||||
## response: The negotiate response data structure.
|
||||
event smb2_negotiate_response%(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse%);
|
||||
|
||||
#### Types
|
||||
|
||||
type SMB2::NegotiateResponse: record;
|
12
src/analyzer/protocol/smb/smb2_com_read.bif
Normal file
12
src/analyzer/protocol/smb/smb2_com_read.bif
Normal file
|
@ -0,0 +1,12 @@
|
|||
## Generated for SMB2 request messages of type *read*.
|
||||
##
|
||||
## c: The connection.
|
||||
##
|
||||
## hdr: The parsed header of the SMB2 message.
|
||||
##
|
||||
## file_id: The GUID being used for the file.
|
||||
##
|
||||
## offset: How far into the file this read should be taking place.
|
||||
##
|
||||
## length: The number of bytes of the file being read.
|
||||
event smb2_read_request%(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count%);
|
8
src/analyzer/protocol/smb/smb2_com_session_setup.bif
Normal file
8
src/analyzer/protocol/smb/smb2_com_session_setup.bif
Normal file
|
@ -0,0 +1,8 @@
|
|||
event smb2_session_setup_request%(c: connection, hdr: SMB2::Header, request: SMB2::SessionSetupRequest%);
|
||||
event smb2_session_setup_response%(c: connection, hdr: SMB2::Header, response: SMB2::SessionSetupResponse%);
|
||||
|
||||
#### Types
|
||||
|
||||
type SMB2::SessionSetupRequest: record;
|
||||
type SMB2::SessionSetupResponse: record;
|
||||
type SMB2::SessionSetupFlags: record;
|
4
src/analyzer/protocol/smb/smb2_com_tree_connect.bif
Normal file
4
src/analyzer/protocol/smb/smb2_com_tree_connect.bif
Normal file
|
@ -0,0 +1,4 @@
|
|||
event smb2_tree_connect_request%(c: connection, hdr: SMB2::Header, path: string%);
|
||||
event smb2_tree_connect_response%(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse%);
|
||||
|
||||
type SMB2::TreeConnectResponse: record;
|
1
src/analyzer/protocol/smb/smb2_com_tree_disconnect.bif
Normal file
1
src/analyzer/protocol/smb/smb2_com_tree_disconnect.bif
Normal file
|
@ -0,0 +1 @@
|
|||
|
12
src/analyzer/protocol/smb/smb2_com_write.bif
Normal file
12
src/analyzer/protocol/smb/smb2_com_write.bif
Normal file
|
@ -0,0 +1,12 @@
|
|||
## Generated for SMB2 request messages of type *write*.
|
||||
##
|
||||
## c: The connection.
|
||||
##
|
||||
## hdr: The parsed header of the SMB2 message.
|
||||
##
|
||||
## file_id: The GUID being used for the file.
|
||||
##
|
||||
## offset: How far into the file this write should be taking place.
|
||||
##
|
||||
## length: The number of bytes of the file being written.
|
||||
event smb2_write_request%(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count%);
|
5
src/analyzer/protocol/smb/smb2_events.bif
Normal file
5
src/analyzer/protocol/smb/smb2_events.bif
Normal file
|
@ -0,0 +1,5 @@
|
|||
event smb2_message%(c: connection, hdr: SMB2::Header, is_orig: bool%);
|
||||
|
||||
|
||||
|
||||
|
64
src/analyzer/protocol/smb/smb_ntlmssp.bif
Normal file
64
src/analyzer/protocol/smb/smb_ntlmssp.bif
Normal file
|
@ -0,0 +1,64 @@
|
|||
## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI NTLM message 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.
|
||||
##
|
||||
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||
##
|
||||
event smb_ntlm_negotiate%(c: connection, hdr: SMB1::Header, request: SMB::NTLMNegotiate%);
|
||||
|
||||
## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI NTLM message of type *challenge*.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||
##
|
||||
event smb_ntlm_challenge%(c: connection, hdr: SMB1::Header, request: SMB::NTLMChallenge%);
|
||||
|
||||
## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI NTLM message of type *authenticate*.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||
##
|
||||
event smb_ntlm_authenticate%(c: connection, hdr: SMB1::Header, request: SMB::NTLMAuthenticate%);
|
||||
|
||||
## Generated for SMB/CIFS requests that contain a security blob with a GSSAPI message of type *accept-completed*.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
event smb_ntlm_accepted%(c: connection, hdr: SMB1::Header%);
|
||||
|
||||
|
||||
#### Types
|
||||
|
||||
type SMB::NTLMNegotiate: record;
|
||||
type SMB::NTLMChallenge: record;
|
||||
type SMB::NTLMAuthenticate: record;
|
||||
|
||||
type SMB::NTLMNegotiateFlags: record;
|
||||
type SMB::NTLMVersion: record;
|
||||
type SMB::NTLMAVs: record;
|
6
src/analyzer/protocol/smb/smb_pipe.bif
Normal file
6
src/analyzer/protocol/smb/smb_pipe.bif
Normal file
|
@ -0,0 +1,6 @@
|
|||
## TODO
|
||||
event smb_atsvc_job_add%(c: connection, server: string, job: string%);
|
||||
|
||||
## TODO
|
||||
event smb_atsvc_job_id%(c: connection, id: count, status: count%);
|
||||
|
7
src/analyzer/protocol/smb/types.bif
Normal file
7
src/analyzer/protocol/smb/types.bif
Normal file
|
@ -0,0 +1,7 @@
|
|||
type SMB::MACTimes: record;
|
||||
|
||||
type SMB1::Header: record;
|
||||
|
||||
type SMB2::Header: record;
|
||||
type SMB2::GUID: record;
|
||||
type SMB2::FileAttrs: record;
|
Loading…
Add table
Add a link
Reference in a new issue