SMB & NTLM analyzers.

This commit is contained in:
Vlad Grigorescu 2014-07-24 16:28:31 -04:00
parent 3cea6ab1eb
commit 6a34de5dd8
84 changed files with 8133 additions and 1428 deletions

View file

@ -2235,12 +2235,154 @@ type ntp_msg: record {
}; };
## Maps SMB command numbers to descriptive names. module SMB;
global samba_cmds: table[count] of string &redef
&default = function(c: count): string
{ return fmt("samba-unknown-%d", c); };
## An SMB command header. 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 ## .. 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_negotiate smb_com_negotiate_response smb_com_nt_create_andx
@ -2248,70 +2390,321 @@ global samba_cmds: table[count] of string &redef
## smb_com_trans_pipe smb_com_trans_rap smb_com_transaction ## 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_transaction2 smb_com_tree_connect_andx smb_com_tree_disconnect
## smb_com_write_andx smb_error smb_get_dfs_referral smb_message ## smb_com_write_andx smb_error smb_get_dfs_referral smb_message
type smb_hdr : record { type SMB1::Header : record {
command: count; ##< The command number (see :bro:see:`samba_cmds`). command: count; ##< The command number
status: count; ##< The status code. status: count; ##< The status code.
flags: count; ##< Flag set 1. flags: count; ##< Flag set 1.
flags2: count; ##< Flag set 2. flags2: count; ##< Flag set 2.
tid: count; ##< TODO. tid: count; ##< Tree ID.
pid: count; ##< Process ID. pid: count; ##< Process ID.
uid: count; ##< User ID. uid: count; ##< User ID.
mid: count; ##< TODO. mid: count; ##< Multiplex ID.
}; };
## An SMB transaction. type SMB1::NegotiateRawMode: record {
## ## Read raw supported
## .. bro:see:: smb_com_trans_mailslot smb_com_trans_pipe smb_com_trans_rap read_raw : bool;
## smb_com_transaction smb_com_transaction2 ## Write raw supported
type smb_trans : record { write_raw : bool;
word_count: count; ##< TODO. };
total_param_count: count; ##< TODO.
total_data_count: count; ##< TODO. type SMB1::NegotiateCapabilities: record {
max_param_count: count; ##< TODO. ## The server supports SMB_COM_READ_RAW and SMB_COM_WRITE_RAW
max_data_count: count; ##< TODO. raw_mode : bool;
max_setup_count: count; ##< TODO. ## The server supports SMB_COM_READ_MPX and SMB_COM_WRITE_MPX
# flags: count; mpx_mode : bool;
# timeout: count; ## The server supports unicode strings
param_count: count; ##< TODO. unicode : bool;
param_offset: count; ##< TODO. ## The server supports large files with 64 bit offsets
data_count: count; ##< TODO. large_files : bool;
data_offset: count; ##< TODO. ## The server supports the SMBs particilar to the NT LM 0.12 dialect. Implies nt_find.
setup_count: count; ##< TODO. nt_smbs : bool;
setup0: count; ##< TODO.
setup1: count; ##< TODO. ## The server supports remote admin API requests via DCE-RPC
setup2: count; ##< TODO. rpc_remote_apis : bool;
setup3: count; ##< TODO. ## The server can respond with 32 bit status codes in Status.Status
byte_count: count; ##< TODO. status32 : bool;
parameters: string; ##< TODO. ## 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. module SMB2;
##
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere export {
## else. type SMB2::Header: record {
type smb_tree_connect : record { credit_charge: count;
status: count;
command: count;
credits: count;
flags: count; flags: count;
password: string; message_id: count;
path: string; process_id: count;
service: string; tree_id: count;
session_id: count;
signature: string;
}; };
## Deprecated. type SMB2::GUID: record {
## persistent: count;
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere volatile: count;
## else. };
type smb_negotiate : table[count] of string;
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. ## A list of router addresses offered by a DHCP server.
## ##

View file

@ -48,6 +48,7 @@
@load base/protocols/modbus @load base/protocols/modbus
@load base/protocols/pop3 @load base/protocols/pop3
@load base/protocols/radius @load base/protocols/radius
@load base/protocols/smb
@load base/protocols/snmp @load base/protocols/snmp
@load base/protocols/smtp @load base/protocols/smtp
@load base/protocols/socks @load base/protocols/socks

View 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

View 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."],
};

File diff suppressed because it is too large Load diff

View 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); };
}

View 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;
}
}

View 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;
}
}

View 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;
}

View 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!");
}
}

View 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!");
}
}

View file

@ -1,4 +1,3 @@
include(BroPlugin) include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
@ -6,6 +5,75 @@ include_directories(AFTER ${CMAKE_CURRENT_BINARY_DIR}/../dce-rpc)
bro_plugin_begin(Bro SMB) bro_plugin_begin(Bro SMB)
bro_plugin_cc(SMB.cc Plugin.cc) bro_plugin_cc(SMB.cc Plugin.cc)
bro_plugin_bif(events.bif) bro_plugin_bif(
bro_plugin_pac(smb.pac smb-protocol.pac smb-pipe.pac smb-mailslot.pac) 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() bro_plugin_end()

View file

@ -1,4 +1,3 @@
#include "plugin/Plugin.h" #include "plugin/Plugin.h"
#include "SMB.h" #include "SMB.h"
@ -7,5 +6,36 @@ BRO_PLUGIN_BEGIN(Bro, SMB)
BRO_PLUGIN_DESCRIPTION("SMB analyzer"); BRO_PLUGIN_DESCRIPTION("SMB analyzer");
BRO_PLUGIN_ANALYZER("SMB", smb::SMB_Analyzer); BRO_PLUGIN_ANALYZER("SMB", smb::SMB_Analyzer);
BRO_PLUGIN_SUPPORT_ANALYZER("Contents_SMB"); 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 BRO_PLUGIN_END

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,3 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PROTOCOL_SMB_SMB_H #ifndef ANALYZER_PROTOCOL_SMB_SMB_H
#define ANALYZER_PROTOCOL_SMB_SMB_H #define ANALYZER_PROTOCOL_SMB_SMB_H
@ -7,7 +5,7 @@
// Reference: http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf // Reference: http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf
#include "analyzer/protocol/tcp/TCP.h" #include "analyzer/protocol/tcp/TCP.h"
#include "analyzer/protocol/dce-rpc/DCE_RPC.h" #include "analyzer/protocol/rpc/RPC.h"
#include "smb_pac.h" #include "smb_pac.h"
namespace analyzer { namespace smb { namespace analyzer { namespace smb {
@ -19,182 +17,68 @@ enum IPC_named_pipe {
IPC_SAMR, // Security Account Manager 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 { class Contents_SMB : public tcp::TCP_SupportAnalyzer {
public: public:
Contents_SMB(Connection* conn, bool orig, SMB_Session* smb_session); Contents_SMB(Connection* conn, bool orig);
~Contents_SMB(); ~Contents_SMB();
virtual void DeliverStream(int len, const u_char* data, bool orig); virtual void DeliverStream(int len, const u_char* data, bool orig);
protected: 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); void DeliverSMB(int len, const u_char* data);
SMB_Session* smb_session; binpac::SMB::SMB_Conn* smb_session;
u_char dshdr[4];
u_char* msg_buf; rpc::RPC_Reasm_Buffer hdr_buf; // Reassembles the NetBIOS length and glue.
rpc::RPC_Reasm_Buffer msg_buf; // Reassembles the SMB message.
int msg_len; int msg_len;
int buf_n; // number of bytes in msg_buf int msg_type;
int buf_len; // size off msg_buf 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 { class SMB_Analyzer : public tcp::TCP_ApplicationAnalyzer {
public: public:
SMB_Analyzer(Connection* conn); 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) static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new SMB_Analyzer(conn); } { return new SMB_Analyzer(conn); }
protected: protected:
SMB_Session* smb_session; binpac::SMB::SMB_Conn* interp;
Contents_SMB* o_smb; Contents_SMB* o_smb;
Contents_SMB* r_smb; Contents_SMB* r_smb;
// Count the number of chunks received by the analyzer
// but only used to count the first few.
uint8 chunks;
}; };
} } // namespace analyzer::* } } // namespace analyzer::*

View file

@ -73,3 +73,5 @@ SMB_COMMAND(SMB_COM_GET_PRINT_QUEUE, 0xC3)
SMB_COMMAND(SMB_COM_READ_BULK, 0xD8) SMB_COMMAND(SMB_COM_READ_BULK, 0xD8)
SMB_COMMAND(SMB_COM_WRITE_BULK, 0xD9) SMB_COMMAND(SMB_COM_WRITE_BULK, 0xD9)
SMB_COMMAND(SMB_COM_WRITE_BULK_DATA, 0xDA) SMB_COMMAND(SMB_COM_WRITE_BULK_DATA, 0xDA)
SMB_COMMAND(SMB_COM_INVALID, 0xFE)
SMB_COMMAND(SMB_COM_NO_ANDX_COMMAND, 0xFF)

View 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];

View 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 {
};

View 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;
%}

View file

@ -1,4 +1,3 @@
enum SMB_MailSlot_opcode { enum SMB_MailSlot_opcode {
HOST_ANNOUNCEMENT = 1, HOST_ANNOUNCEMENT = 1,
ANNOUCEMENT_REQUEST = 2, ANNOUCEMENT_REQUEST = 2,

View 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;
};

View file

@ -1,12 +1,46 @@
# this won't work correctly yet, since sometimes the parameters # this won't work correctly yet, since sometimes the parameters
# field in the transaction takes up all of the data field # 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 { type SMB_Pipe_message( unicode: bool, byte_count: uint16, sub_cmd: uint16 ) = record {
rpc : DCE_RPC_Header;
# there's a problem with byte_count here, not sure why ... its todo : padding[6]; # These fields are currently missing from DCE/RPC for some reason.
# not the real length of the rest of the packet opnum : uint8;
data : bytestring &restofdata; 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; } &byteorder = littleendian;
type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record { 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; data : bytestring &restofdata;
} &byteorder = littleendian; } &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);
};

View file

@ -336,7 +336,7 @@ type SMB_read_andx_response = record {
byte_count : uint16; byte_count : uint16;
pad : padding[padding_length]; pad : padding[padding_length];
data : bytestring &length = data_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 # issues with the packet format or is the data_length just not
# right. The problem is that the padding isn't always filled right, # right. The problem is that the padding isn't always filled right,
# espeically when its not the first command in the packet. # espeically when its not the first command in the packet.

View 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];
};

View 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;
#

View file

@ -2,11 +2,130 @@
%include bro.pac %include bro.pac
%extern{ %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-mailslot.pac
%include smb-pipe.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);
};

View 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);
};

View 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);
};

View 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);
};

View 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);
};

View 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);
};

View 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);
};

View 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;
};

View 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);
};

View 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);
};

View 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);
};

View 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;

View 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);
};

View 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;

View 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;
};

View 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);
};

View 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);
};

View 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);
};
###########################################

View 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);
};

View 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);
};

View 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);
};

View 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;
%}
};

View 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%);

View 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%);

View 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%);

View file

@ -0,0 +1,5 @@
## TODO
event smb1_echo_request%(c: connection, data: string%);
## TODO
event smb1_echo_response%(c: connection, data: string%);

View 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%);

View 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;

View file

@ -0,0 +1,2 @@
## TODO
event smb1_nt_cancel_request%(c: connection, hdr: SMB1::Header%);

View 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%);

View 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%);

View file

@ -0,0 +1,3 @@
# TODO
event smb1_query_information_request%(c: connection, hdr: SMB1::Header, filename: string%);

View 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%);

View 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;

View 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%);

View 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%);

View 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%);

View 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%);

View 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);
};

View 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);
};

View 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);
};

View 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);
};

View 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);
};

View 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);
};

View 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;
};

View 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);
};

View 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;
};

View 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;

View 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%);

View 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;

View 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%);

View 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;

View 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;

View file

@ -0,0 +1 @@

View 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%);

View file

@ -0,0 +1,5 @@
event smb2_message%(c: connection, hdr: SMB2::Header, is_orig: bool%);

View 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;

View 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%);

View 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;