From a6de23aaa33799ae176c06e928f8301575c24a7e Mon Sep 17 00:00:00 2001 From: Vlad Grigorescu Date: Tue, 7 Oct 2014 16:31:02 -0400 Subject: [PATCH] Refine transaction2 support, rewrite SMB scripts. --- scripts/base/init-bare.bro | 28 +++ scripts/base/protocols/smb/consts.bro | 37 ++++ scripts/base/protocols/smb/files.bro | 22 +- scripts/base/protocols/smb/main.bro | 171 ++++++++-------- scripts/base/protocols/smb/smb1-main.bro | 192 ++++++++++-------- scripts/base/protocols/smb/smb2-main.bro | 173 ++++++++-------- src/analyzer/protocol/smb/CMakeLists.txt | 1 + src/analyzer/protocol/smb/smb.pac | 1 + .../protocol/smb/smb1-com-transaction2.pac | 16 +- .../protocol/smb/smb1_com_transaction2.bif | 53 +++++ 10 files changed, 428 insertions(+), 266 deletions(-) create mode 100644 src/analyzer/protocol/smb/smb1_com_transaction2.bif diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index e4c69c07bb..7719e2959b 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2635,6 +2635,34 @@ export { security_blob : string &optional; }; + type SMB1::Find_First2_Request_Args: record { + ## File attributes to apply as a constraint to the search + search_attrs : string; + ## Max search results + search_count : count; + ## Misc. flags for how the server should manage the transaction + ## once results are returned + flags : count; + ## How detailed the information returned in the results should be + info_level : count; + ## Specify whether to search for directories or files + search_storage_type : count; + ## The string to serch for (note: may contain wildcards) + file_name : string; + }; + + type SMB1::Find_First2_Response_Args: record { + ## The server generated search identifier + sid : count; + ## Number of results returned by the search + search_count : count; + ## Whether or not the search can be continued using + ## the TRANS2_FIND_NEXT2 transaction + end_of_search : bool; + ## An extended attribute name that couldn't be retrieved + ext_attr_error : string &optional; + }; + } diff --git a/scripts/base/protocols/smb/consts.bro b/scripts/base/protocols/smb/consts.bro index 681fcb3c17..965541c640 100644 --- a/scripts/base/protocols/smb/consts.bro +++ b/scripts/base/protocols/smb/consts.bro @@ -9,6 +9,23 @@ export { const statuses: table[count] of StatusCode = { [0x00000000] = [$id="SUCCESS", $desc="The operation completed successfully."], } &redef &default=function(i: count):StatusCode { local unknown=fmt("unknown-%d", i); return [$id=unknown, $desc=unknown]; }; + + ## These are files names that are used for special + ## cases by the file system and would not be + ## considered "normal" files. + const pipe_names: set[string] = { + "\\netdfs", + "\\spoolss", + "\\NETLOGON", + "\\winreg", + "\\lsarpc", + "\\samr", + "\\srvsvc", + "srvsvc", + "MsFteWds", + "\\wkssvc", + }; + } module SMB1; @@ -88,6 +105,26 @@ export { [0xD9] = "WRITE_BULK", [0xDA] = "WRITE_BULK_DATA", } &default=function(i: count):string { return fmt("unknown-%d", i); }; + + const trans2_sub_commands: table[count] of string = { + [0x00] = "OPEN2", + [0x01] = "FIND_FIRST2", + [0x02] = "FIND_NEXT2", + [0x03] = "QUERY_FS_INFORMATION", + [0x04] = "SET_FS_INFORMATION", + [0x05] = "QUERY_PATH_INFORMATION", + [0x06] = "SET_PATH_INFORMATION", + [0x07] = "QUERY_FILE_INFORMATION", + [0x08] = "SET_FILE_INFORMATION", + [0x09] = "FSCTL", + [0x0A] = "IOCTL", + [0x0B] = "FIND_NOTIFY_FIRST", + [0x0C] = "FIND_NOTIFY_NEXT", + [0x0D] = "CREATE_DIRECTORY", + [0x0E] = "SESSION_SETUP", + [0x10] = "GET_DFS_REFERRAL", + [0x11] = "REPORT_DFS_INCONSISTENCY", + } &default=function(i: count):string { return fmt("unknown-trans2-sub-cmd-%d", i); }; } module SMB2; diff --git a/scripts/base/protocols/smb/files.bro b/scripts/base/protocols/smb/files.bro index dde3d179a7..2d2b82d0e0 100644 --- a/scripts/base/protocols/smb/files.bro +++ b/scripts/base/protocols/smb/files.bro @@ -12,15 +12,15 @@ export { 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)) ) + if ( ! (c$smb_state?$current_file && + ((c$smb_state$current_file?$name && c$smb_state$current_file$name !in pipe_names) || + c$smb_state$current_file?$path)) ) { - # TODO: figure out what are the cases where this happens. + # TODO - figure out what are the cases where this happens. return ""; } - local current_file = c$smb$current_file; + local current_file = c$smb_state$current_file; local path_name = current_file?$path ? current_file$path : ""; local file_name = current_file?$name ? current_file$name : ""; # Include last_mod time if available because if a file has been modified it @@ -38,8 +38,8 @@ function describe_file(f: fa_file): string 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; + if ( info?$smb_state && info$smb_state?$current_file && info$smb_state$current_file?$name ) + return info$smb_state$current_file$name; } return ""; } @@ -53,11 +53,11 @@ event bro_init() &priority=5 event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5 { - if ( c?$smb && c$smb?$current_file ) + if ( c?$smb_state && c$smb_state?$current_file ) { - c$smb$current_file$fuid = f$id; + c$smb_state$current_file$fuid = f$id; - if ( c$smb$current_file?$name ) - f$info$filename = c$smb$current_file$name; + if ( c$smb_state$current_file?$name ) + f$info$filename = c$smb_state$current_file$name; } } diff --git a/scripts/base/protocols/smb/main.bro b/scripts/base/protocols/smb/main.bro index 945a0ee01d..5204336eb9 100644 --- a/scripts/base/protocols/smb/main.bro +++ b/scripts/base/protocols/smb/main.bro @@ -1,3 +1,5 @@ +@load ./consts + module SMB; export { @@ -16,105 +18,100 @@ export { FILE_UNKNOWN, }; + ## The file actions which are logged. 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", - }; + } &redef; + ## The server response statuses which are *not* logged. + const ignored_command_statuses: set[string] = { + "MORE_PROCESSING_REQUIRED", + } &redef; + + ## This record is for the smb_files.log type FileInfo: record { ## Time when the file was first discovered. - ts : time &log; - uid : string &log; - id : conn_id &log; - fuid : string &log; - + ts : time &log; + ## Unique ID of the connection the file was sent over. + uid : string &log; + ## ID of the connection the file was sent over. + id : conn_id &log; + ## Unique ID of the file. + fuid : string &log &optional; + ## Action this log record represents. - action : FileAction &log &default=FILE_UNKNOWN; - + action : FileAction &log &default=FILE_UNKNOWN; ## Path pulled from the tree this file was transferred to or from. - path : string &log &optional; + path : string &log &optional; ## Filename if one was seen. - name : string &log &optional; - + name : string &log &optional; ## Total size of the file. - size : count &log &default=0; + size : count &log &default=0; ## Last time this file was modified. - times : SMB::MACTimes &log &optional; + times : SMB::MACTimes &log &optional; }; - + + ## This record is for the smb_mapping.log type TreeInfo: record { ## Time when the tree was mapped. - ts : time &log &optional; - - uid : string &log; - id : conn_id &log; + ts : time &log &optional; + ## Unique ID of the connection the tree was mapped over. + uid : string &log; + ## ID of the connection the tree was mapped over. + id : conn_id &log; ## Name of the tree path. - path : string &log &optional; - service : string &log &optional; - native_file_system : string &log &optional; - + path : string &log &optional; + ## The type of resource of the tree (disk share, printer share, named pipe, etc.) + service : string &log &optional; + ## File system of the tree. + native_file_system : string &log &optional; ## If this is SMB2, a share type will be included. - share_type : string &log &optional; + share_type : string &log &optional; }; - + + ## This record is for the smb_cmd.log 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; + ## Timestamp of the command request + ts : time &log; + ## Unique ID of the connection the request was sent over + uid : string &log; + ## ID of the connection the request was sent over + id : conn_id &log; - ## 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; - + ## The command sent by the client + command : string &log; + ## The subcommand sent by the client, if present + sub_command : string &log &optional; + ## Command argument sent by the client, if any + argument : string &log &optional; + + ## Server reply to the client's command + status : string &log &optional; ## Round trip time from the request to the response. - rtt: interval &log &optional; + rtt : interval &log &optional; + ## Version of SMB for the command + version : string &log; + ## If this is related to a tree, this is the tree + ## that was used for the current command. + tree : string &log &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; + }; + + ## This record stores the SMB state of in-flight commands, + ## the file and tree map of the connection. + type State: record { ## A reference to the current command. current_cmd : CmdInfo &optional; - ## A reference to the current file. current_file : FileInfo &optional; - ## A reference to the current tree. current_tree : TreeInfo &optional; @@ -127,20 +124,22 @@ export { }; redef record connection += { - smb : Info &optional; + smb_state : State &optional; }; + ## Internal use only + ## Some commands shouldn't be logged by the smb1_message event + const deferred_logging_cmds: set[string] = { + "NEGOTIATE", + }; + ## This is an internally used function. - const set_current_file: function(smb: Info, file_id: count) &redef; + const set_current_file: function(smb_state: State, 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; @@ -154,22 +153,22 @@ redef likely_server_ports += { ports }; event bro_init() &priority=5 { - Log::create_stream(CMD_LOG, [$columns=SMB::Info]); + Log::create_stream(CMD_LOG, [$columns=SMB::CmdInfo]); 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) +function set_current_file(smb_state: State, file_id: count) { - if ( file_id !in smb$fid_map ) + if ( file_id !in smb_state$fid_map ) { - smb$fid_map[file_id] = smb$current_cmd$referenced_file; - smb$fid_map[file_id]$fid = file_id; + smb_state$fid_map[file_id] = smb_state$current_cmd$referenced_file; + smb_state$fid_map[file_id]$fid = file_id; } - smb$current_file = smb$fid_map[file_id]; + smb_state$current_file = smb_state$fid_map[file_id]; } function write_file_log(f: FileInfo) @@ -190,9 +189,9 @@ event file_state_remove(f: fa_file) &priority=-5 for ( id in f$conns ) { local c = f$conns[id]; - if ( c?$smb && c$smb?$current_file) + if ( c?$smb_state && c$smb_state?$current_file) { - write_file_log(c$smb$current_file); + write_file_log(c$smb_state$current_file); } return; } diff --git a/scripts/base/protocols/smb/smb1-main.bro b/scripts/base/protocols/smb/smb1-main.bro index 5aeee80c30..ca25eabc2f 100644 --- a/scripts/base/protocols/smb/smb1-main.bro +++ b/scripts/base/protocols/smb/smb1-main.bro @@ -1,194 +1,216 @@ module SMB1; -redef record SMB::Info += { +redef record SMB::CmdInfo += { + ## Dialects offered by the client smb1_offered_dialects: string_vec &optional; }; event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=5 { - if ( ! c?$smb ) + if ( ! c?$smb_state ) { - 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 state: SMB::State; + state$fid_map = table(); + state$tid_map = table(); + state$pending_cmds = table(); + c$smb_state = state; } - - local smb = c$smb; + + local smb_state = c$smb_state; local tid = hdr$tid; local pid = hdr$pid; local uid = hdr$uid; local mid = hdr$mid; - if ( tid !in smb$tid_map ) + if ( tid !in smb_state$tid_map ) { local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id]; - smb$tid_map[tid] = tmp_tree; + smb_state$tid_map[tid] = tmp_tree; } - smb$current_tree = smb$tid_map[tid]; + smb_state$current_tree = smb_state$tid_map[tid]; - if ( mid !in smb$pending_cmds ) + if ( mid !in smb_state$pending_cmds ) { - local tmp_cmd: SMB::CmdInfo; - tmp_cmd$command = SMB1::commands[hdr$command]; + local tmp_cmd: SMB::CmdInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB1", $command = SMB1::commands[hdr$command]]; - local tmp_file: SMB::FileInfo; - tmp_file$ts = network_time(); - tmp_file$id = c$id; - tmp_file$uid = c$uid; + local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id]; tmp_cmd$referenced_file = tmp_file; - tmp_cmd$referenced_tree = smb$current_tree; + tmp_cmd$referenced_tree = smb_state$current_tree; - smb$pending_cmds[mid] = tmp_cmd; + smb_state$pending_cmds[mid] = tmp_cmd; } - smb$current_cmd = smb$pending_cmds[mid]; - smb$command = smb$current_cmd$command; + smb_state$current_cmd = smb_state$pending_cmds[mid]; - if ( is_orig ) + if ( !is_orig ) { - smb$ts = network_time(); - } - else - { - smb$rtt = network_time() - smb$ts; - smb$status = SMB::statuses[hdr$status]$id; + smb_state$current_cmd$rtt = network_time() - smb_state$current_cmd$ts; + smb_state$current_cmd$status = SMB::statuses[hdr$status]$id; } } event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=-5 { + # Is this a response? if ( !is_orig ) - # 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_state$current_cmd$status !in SMB::ignored_command_statuses ) && + ( c$smb_state$current_cmd$command !in SMB::deferred_logging_cmds ) ) + { + Log::write(SMB::CMD_LOG, c$smb_state$current_cmd); + } + delete c$smb_state$pending_cmds[hdr$mid]; + } + } - if ( c?$smb ) - Log::write(SMB::CMD_LOG, c$smb); + +event smb1_transaction2_request(c: connection, hdr: SMB1::Header, sub_cmd: count) + { + c$smb_state$current_cmd$sub_command = SMB1::trans2_sub_commands[sub_cmd]; } event smb1_negotiate_request(c: connection, hdr: SMB1::Header, dialects: string_vec) &priority=5 { - c$smb$smb1_offered_dialects = dialects; + c$smb_state$current_cmd$smb1_offered_dialects = dialects; } event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=5 { - if ( c$smb?$smb1_offered_dialects ) + if ( c$smb_state$current_cmd?$smb1_offered_dialects ) { if ( response?$ntlm ) - c$smb$dialect = c$smb$smb1_offered_dialects[response$ntlm$dialect_index]; - delete c$smb$smb1_offered_dialects; + { + c$smb_state$current_cmd$argument = c$smb_state$current_cmd$smb1_offered_dialects[response$ntlm$dialect_index]; + } + + delete c$smb_state$current_cmd$smb1_offered_dialects; } } - + +event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=-5 + { + if ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses ) + { + Log::write(SMB::CMD_LOG, c$smb_state$current_cmd); + } + } + event smb1_tree_connect_andx_request(c: connection, hdr: SMB1::Header, path: string, service: string) &priority=5 { - c$smb$current_cmd$referenced_tree$path = path; - c$smb$current_cmd$referenced_tree$service = service; - c$smb$current_tree$ts=network_time(); + local tmp_tree: SMB::TreeInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $path=path, $service=service]; + + c$smb_state$current_cmd$referenced_tree = tmp_tree; + c$smb_state$current_cmd$argument = path; } event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=5 { - c$smb$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; + c$smb_state$current_cmd$referenced_tree$native_file_system = native_file_system; + c$smb_state$current_tree = c$smb_state$current_cmd$referenced_tree; + c$smb_state$tid_map[hdr$tid] = c$smb_state$current_tree; } event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=-5 { - Log::write(SMB::MAPPING_LOG, c$smb$current_tree); + Log::write(SMB::MAPPING_LOG, c$smb_state$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; + local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id]; + c$smb_state$current_cmd$referenced_file = tmp_file; + c$smb_state$current_cmd$referenced_file$name = name; + c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN; + c$smb_state$current_file = c$smb_state$current_cmd$referenced_file; } 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; + c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN; + c$smb_state$current_cmd$referenced_file$fid = file_id; + c$smb_state$current_cmd$referenced_file$size = file_size; # I'm seeing negative data from IPC tree transfers if ( time_to_double(times$modified) > 0.0 ) - c$smb$current_file$times = times; + c$smb_state$current_cmd$referenced_file$times = times; # We can identify the file by its file id now so let's stick it # in the file map. - c$smb$fid_map[file_id] = c$smb$current_file; - - SMB::write_file_log(c$smb$current_file); + c$smb_state$fid_map[file_id] = c$smb_state$current_cmd$referenced_file; + + c$smb_state$current_file = c$smb_state$fid_map[file_id]; + + SMB::write_file_log(c$smb_state$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); + SMB::set_current_file(c$smb_state, file_id); + c$smb_state$current_file$action = SMB::FILE_READ; } -event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5 +event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=-5 { - #print "read andx response!"; + if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path ) + c$smb_state$current_file$path = c$smb_state$current_tree$path; + + # TODO - Why is this commented out? + #write_file_log(c$smb_state$current_file); } + +#event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5 +# { +# # TODO - determine what to do here +# } 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; + SMB::set_current_file(c$smb_state, file_id); + c$smb_state$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; + if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path ) + c$smb_state$current_file$path = c$smb_state$current_tree$path; - #write_file_log(c$smb$current_file); + # TODO - Why is this commented out? + #write_file_log(c$smb_state$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? +# # TODO - determine what to do here # } event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=5 { - SMB::set_current_file(c$smb, file_id); - c$smb$current_file$action = SMB::FILE_CLOSE; + SMB::set_current_file(c$smb_state, file_id); + c$smb_state$current_file$action = SMB::FILE_CLOSE; } event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=-5 { - if ( file_id in c$smb$fid_map ) + if ( file_id in c$smb_state$fid_map ) { - local fl = c$smb$fid_map[file_id]; - fl$uid = c$uid; - fl$id = c$id; + local fl = c$smb_state$fid_map[file_id]; # Need to check for existence of path in case tree connect message wasn't seen. - if ( c$smb$current_tree?$path ) - fl$path = c$smb$current_tree$path; - delete c$smb$fid_map[file_id]; + if ( c$smb_state$current_tree?$path ) + fl$path = c$smb_state$current_tree$path; + delete c$smb_state$fid_map[file_id]; SMB::write_file_log(fl); } else { + # TODO - Determine correct action # A reporter message is not right... #Reporter::warning("attempting to close an unknown file!"); } } + +event smb1_trans2_get_dfs_referral_request(c: connection, hdr: SMB1::Header, file_name: string, max_referral_level: count) + { + c$smb_state$current_cmd$argument = file_name; + } \ No newline at end of file diff --git a/scripts/base/protocols/smb/smb2-main.bro b/scripts/base/protocols/smb/smb2-main.bro index 7dc36c3717..295a8afe2d 100644 --- a/scripts/base/protocols/smb/smb2-main.bro +++ b/scripts/base/protocols/smb/smb2-main.bro @@ -1,182 +1,195 @@ module SMB2; -redef record SMB::Info += { +redef record SMB::CmdInfo += { + ## Dialects offered by the client smb2_offered_dialects: index_vec &optional; }; event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=5 { - if ( ! c?$smb ) + if ( ! c?$smb_state ) { - 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 state: SMB::State; + state$fid_map = table(); + state$tid_map = table(); + state$pending_cmds = table(); + c$smb_state = state; } - local smb = c$smb; + local smb_state = c$smb_state; local tid = hdr$tree_id; local pid = hdr$process_id; local mid = hdr$message_id; local sid = hdr$session_id; - if ( tid !in smb$tid_map ) + if ( tid !in smb_state$tid_map ) { local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id]; - smb$tid_map[tid] = tmp_tree; + smb_state$tid_map[tid] = tmp_tree; } - smb$current_tree = smb$tid_map[tid]; + smb_state$current_tree = smb_state$tid_map[tid]; - if ( mid !in smb$pending_cmds ) + if ( mid !in smb_state$pending_cmds ) { - local tmp_cmd: SMB::CmdInfo; - tmp_cmd$command = SMB2::commands[hdr$command]; + local tmp_cmd: SMB::CmdInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB2", $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; + local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id]; tmp_cmd$referenced_file = tmp_file; - tmp_cmd$referenced_tree = smb$current_tree; + tmp_cmd$referenced_tree = smb_state$current_tree; - smb$pending_cmds[mid] = tmp_cmd; + smb_state$pending_cmds[mid] = tmp_cmd; } - smb$current_cmd = smb$pending_cmds[mid]; - smb$command = smb$current_cmd$command; + smb_state$current_cmd = smb_state$pending_cmds[mid]; - if ( is_orig ) + if ( !is_orig ) { - smb$ts = network_time(); - } - else - { - smb$rtt = network_time() - smb$ts; - smb$status = SMB::statuses[hdr$status]$id; + smb_state$current_cmd$rtt = network_time() - smb_state$current_cmd$ts; + smb_state$current_cmd$status = SMB::statuses[hdr$status]$id; } } event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=-5 { + # Is this a response? if ( !is_orig ) - # 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); + { + if ( ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses ) && + ( c$smb_state$current_cmd$command !in SMB::deferred_logging_cmds ) ) + { + Log::write(SMB::CMD_LOG, c$smb_state$current_cmd); + } + delete c$smb_state$pending_cmds[hdr$message_id]; + } } event smb2_negotiate_request(c: connection, hdr: SMB2::Header, dialects: index_vec) &priority=5 { - c$smb$smb2_offered_dialects = dialects; + c$smb_state$current_cmd$smb2_offered_dialects = dialects; } -event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) +event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) &priority=5 { - if ( c$smb?$smb2_offered_dialects ) + if ( c$smb_state$current_cmd?$smb2_offered_dialects ) { - for ( i in c$smb$smb2_offered_dialects ) + for ( i in c$smb_state$current_cmd$smb2_offered_dialects ) { - if ( response$dialect_revision == c$smb$smb2_offered_dialects[i] ) + if ( response$dialect_revision == c$smb_state$current_cmd$smb2_offered_dialects[i] ) { - c$smb$dialect = SMB2::dialects[response$dialect_revision]; + c$smb_state$current_cmd$argument = SMB2::dialects[response$dialect_revision]; break; } } - delete c$smb$smb2_offered_dialects; + delete c$smb_state$current_cmd$smb2_offered_dialects; } } +event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) &priority=5 + { + if ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses ) + { + Log::write(SMB::CMD_LOG, c$smb_state$current_cmd); + } + } + event smb2_tree_connect_request(c: connection, hdr: SMB2::Header, path: string) &priority=5 { - c$smb$current_cmd$referenced_tree$path = path; - c$smb$current_tree$ts=network_time(); + local tmp_tree: SMB::TreeInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $path=path]; + + c$smb_state$current_cmd$referenced_tree = tmp_tree; } 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; + c$smb_state$current_cmd$referenced_tree$share_type = SMB2::share_types[response$share_type]; + c$smb_state$current_tree = c$smb_state$current_cmd$referenced_tree; + c$smb_state$tid_map[hdr$tree_id] = c$smb_state$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); + Log::write(SMB::MAPPING_LOG, c$smb_state$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; + local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id]; + c$smb_state$current_cmd$referenced_file = tmp_file; + c$smb_state$current_cmd$referenced_file$name = name; + c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN; + c$smb_state$current_file = c$smb_state$current_cmd$referenced_file; } 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; + c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN; + c$smb_state$current_cmd$referenced_file$fid = file_id$persistent+file_id$volatile; + c$smb_state$current_cmd$referenced_file$size = file_size; # I'm seeing negative data from IPC tree transfers if ( time_to_double(times$modified) > 0.0 ) - c$smb$current_file$times = times; + c$smb_state$current_cmd$referenced_file$times = times; # We can identify the file by its file id now so let's stick it # in the file map. - c$smb$fid_map[file_id$persistent+file_id$volatile] = c$smb$current_file; - - SMB::write_file_log(c$smb$current_file); + c$smb_state$fid_map[file_id$persistent+file_id$volatile] = c$smb_state$current_cmd$referenced_file; + + c$smb_state$current_file = c$smb_state$fid_map[file_id$persistent+file_id$volatile]; + + SMB::write_file_log(c$smb_state$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; + SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile); + c$smb_state$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; +event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5 + { + if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path ) + c$smb_state$current_file$path = c$smb_state$current_tree$path; - #write_file_log(c$smb$current_file); + # TODO - Why is this commented out? + #write_file_log(c$smb_state$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; + SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile); + c$smb_state$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_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5 + { + if ( c$smb_state$current_tree?$path && ! c$smb_state$current_file?$path ) + c$smb_state$current_file$path = c$smb_state$current_tree$path; + + # TODO - Why is this commented out? + #write_file_log(c$smb_state$current_file); } 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; + SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile); + c$smb_state$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 ) + if ( file_id$persistent+file_id$volatile in c$smb_state$fid_map ) { - local fl = c$smb$fid_map[file_id$persistent+file_id$volatile]; - fl$uid = c$uid; - fl$id = c$id; + local fl = c$smb_state$fid_map[file_id$persistent+file_id$volatile]; # Need to check for existence of path in case tree connect message wasn't seen. - if ( c$smb$current_tree?$path ) - fl$path = c$smb$current_tree$path; - delete c$smb$fid_map[file_id$persistent+file_id$volatile]; + if ( c$smb_state$current_tree?$path ) + fl$path = c$smb_state$current_tree$path; + delete c$smb_state$fid_map[file_id$persistent+file_id$volatile]; SMB::write_file_log(fl); } else { + # TODO - Determine correct action # A reporter message is not right... #Reporter::warning("attempting to close an unknown file!"); } diff --git a/src/analyzer/protocol/smb/CMakeLists.txt b/src/analyzer/protocol/smb/CMakeLists.txt index ef05ad353c..64cb6fe558 100644 --- a/src/analyzer/protocol/smb/CMakeLists.txt +++ b/src/analyzer/protocol/smb/CMakeLists.txt @@ -20,6 +20,7 @@ bro_plugin_bif( smb1_com_query_information.bif smb1_com_read_andx.bif smb1_com_session_setup_andx.bif + smb1_com_transaction2.bif smb1_com_tree_connect_andx.bif smb1_com_tree_disconnect.bif smb1_com_write_andx.bif diff --git a/src/analyzer/protocol/smb/smb.pac b/src/analyzer/protocol/smb/smb.pac index bbb70f4771..597e54a7c1 100644 --- a/src/analyzer/protocol/smb/smb.pac +++ b/src/analyzer/protocol/smb/smb.pac @@ -21,6 +21,7 @@ #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_transaction2.bif.h" #include "smb1_com_tree_connect_andx.bif.h" #include "smb1_com_tree_disconnect.bif.h" #include "smb1_com_write_andx.bif.h" diff --git a/src/analyzer/protocol/smb/smb1-com-transaction2.pac b/src/analyzer/protocol/smb/smb1-com-transaction2.pac index cff496c054..b8ea3f8975 100644 --- a/src/analyzer/protocol/smb/smb1-com-transaction2.pac +++ b/src/analyzer/protocol/smb/smb1-com-transaction2.pac @@ -22,13 +22,16 @@ 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}); + if ( smb1_transaction2_request ) + BifEvent::generate_smb1_transaction2_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), ${val.sub_cmd}); + return true; %} function proc_smb1_transaction2_response(header: SMB_Header, val: SMB1_transaction2_response): bool %{ - //printf("transaction2_response sub command: %d\n", ${val.sub_cmd}); +// if ( smb1_transaction2_response ) +// BifEvent::generate_smb1_transaction2_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), new Val(${val.sub_cmd}, TYPE_COUNT)); return true; %} @@ -278,8 +281,13 @@ 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"); + if ( smb1_trans2_get_dfs_referral_request ) + { + BifEvent::generate_smb1_trans2_get_dfs_referral_request(bro_analyzer(), bro_analyzer()->Conn(), \ + BuildHeaderVal(header), \ + smb_string2stringval(${val.file_name}),\ + ${val.max_referral_level}); + } return true; %} diff --git a/src/analyzer/protocol/smb/smb1_com_transaction2.bif b/src/analyzer/protocol/smb/smb1_com_transaction2.bif new file mode 100644 index 0000000000..1430098f00 --- /dev/null +++ b/src/analyzer/protocol/smb/smb1_com_transaction2.bif @@ -0,0 +1,53 @@ +### Requests + + +# TODO - Description +event smb1_transaction2_request%(c: connection, hdr: SMB1::Header, sub_cmd: count%); + +# TODO - Description +event smb1_trans2_find_first2_request%(c: connection, hdr: SMB1::Header, args: SMB1::Find_First2_Request_Args%); + +# TODO - Implementation +# event smb1_trans2_fs_info_request%(c: connection, hdr: SMB1::Header, ??? %); + +# TODO - Description +event smb1_trans2_query_path_info_request%(c: connection, hdr: SMB1::Header, file_name: string, level_of_interest: count%); + +# TODO - Description +event smb1_trans2_query_file_info_request%(c: connection, hdr: SMB1::Header, file_id: count, level_of_interest: count%); + +# TODO - Implementation +# event smb1_trans2_set_file_info_request(c: connection, hdr: SMB1::Header, ??? %); + +# TODO - Description +event smb1_trans2_get_dfs_referral_request%(c: connection, hdr: SMB1::Header, file_name: string, max_referral_level: count%); + +### Responses + + +# TODO - Description +event smb1_transaction2_response%(c: connection, hdr: SMB1::Header, sub_cmd: count%); + +# TODO - Description +event smb1_trans2_find_first2_response%(c: connection, hdr: SMB1::Header, args: SMB1::Find_First2_Response_Args%); + +# TODO - Implementation +# event smb1_trans2_fs_info_response%(c: connection, hdr: SMB1::Header, ??? %); + +# TODO - Implementation +# event smb1_trans2_query_path_info_response%(c: connection, hdr: SMB1::Header, ??? %); + +# TODO - Implementation +# event smb1_trans2_query_file_info_response%(c: connection, hdr: SMB1::Header, ??? %); + +# TODO - Implementation +# event smb1_trans2_set_file_info_response%(c: connection, hdr: SMB1::Header, ??? %); + +# TODO - Implementation +# event smb1_trans2_get_dfs_referral_response%(c: connection, hdr: SMB1::Header, ??? %); + + +### Types + +type SMB1::Find_First2_Request_Args: record; +type SMB1::Find_First2_Response_Args: record; \ No newline at end of file