From d453dc149cccc67bfb6f531dbebde8d5ecca29dd Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 3 Mar 2016 14:27:15 -0500 Subject: [PATCH] A lot of changes to SMB analyzer. - Add beginning of infrastructure for pipe support in SMB2. - Improve identification of non-file tree mappings. - Stop passing pipe data to the file analysis framework. - Reduce log volume in smb_files.log by watching for repeated files being seen so that you don't end up with nearly the exact same log line over and over and over. - Lots of little whitespace and indentation changes. --- scripts/base/protocols/smb/main.bro | 93 ++++++++++++++----- scripts/base/protocols/smb/pipe.bro | 63 ++++++------- scripts/base/protocols/smb/smb1-main.bro | 4 +- scripts/base/protocols/smb/smb2-main.bro | 86 ++++++++++++++--- src/analyzer/protocol/smb/SMB.cc | 9 +- src/analyzer/protocol/smb/smb-pipe.pac | 53 +++++------ .../protocol/smb/smb1-com-transaction.pac | 27 +++--- .../smb/smb1-com-tree-connect-andx.pac | 2 +- .../protocol/smb/smb1-com-write-andx.pac | 2 +- .../protocol/smb/smb2-com-negotiate.pac | 2 +- src/analyzer/protocol/smb/smb2-com-read.pac | 10 +- .../protocol/smb/smb2-com-tree-connect.pac | 3 +- src/analyzer/protocol/smb/smb2-com-write.pac | 30 +++--- src/analyzer/protocol/smb/smb2-protocol.pac | 6 ++ 14 files changed, 252 insertions(+), 138 deletions(-) diff --git a/scripts/base/protocols/smb/main.bro b/scripts/base/protocols/smb/main.bro index e054ad15fe..246f578022 100644 --- a/scripts/base/protocols/smb/main.bro +++ b/scripts/base/protocols/smb/main.bro @@ -10,19 +10,42 @@ export { }; ## Abstracted actions for SMB file actions. - type FileAction: enum { + type Action: enum { FILE_READ, FILE_WRITE, FILE_OPEN, FILE_CLOSE, FILE_UNKNOWN, + + PIPE_READ, + PIPE_WRITE, + PIPE_OPEN, + PIPE_CLOSE, + + PRINT_READ, + PRINT_WRITE, + PRINT_OPEN, + PRINT_CLOSE, + + UNKNOWN_READ, + UNKNOWN_WRITE, + UNKNOWN_OPEN, + UNKNOWN_CLOSE, }; ## The file actions which are logged. - const logged_file_actions: set[FileAction] = { + const logged_file_actions: set[Action] = { FILE_OPEN, FILE_READ, FILE_WRITE, + + PIPE_OPEN, + PIPE_CLOSE, + + PRINT_OPEN, + PRINT_CLOSE, + + UNKNOWN_OPEN, } &redef; ## The server response statuses which are *not* logged. @@ -42,7 +65,7 @@ export { fuid : string &log &optional; ## Action this log record represents. - action : FileAction &log &default=FILE_UNKNOWN; + action : Action &log &optional; ## Path pulled from the tree this file was transferred to or from. path : string &log &optional; ## Filename if one was seen. @@ -50,26 +73,26 @@ export { ## Total size of the file. 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; + ts : time &log &optional; ## Unique ID of the connection the tree was mapped over. - uid : string &log; + uid : string &log; ## ID of the connection the tree was mapped over. - id : conn_id &log; + id : conn_id &log; ## Name of the tree path. - path : 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; + service : string &log &optional; ## File system of the tree. - native_file_system : string &log &optional; + 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 &default="UNKNOWN"; }; ## This record is for the smb_cmd.log @@ -121,15 +144,20 @@ export { current_tree : TreeInfo &optional; ## Indexed on MID to map responses to requests. - pending_cmds: table[count] of CmdInfo &optional; + 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; + 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; + tid_map : table[count] of TreeInfo &optional; ## User map to retrieve user name based on the user ID. - uid_map : table[count] of string &optional; + uid_map : table[count] of string &optional; ## Pipe map to retrieve UUID based on the file ID of a pipe. - pipe_map : table[count] of string &optional; + pipe_map : table[count] of string &optional; + + ## A set of recent files to avoid logging the same + ## files over and over in the smb files log. + ## This only applies to files seen in a single connection. + recent_files : set[string] &default=string_set() &read_expire=3min; }; redef record connection += { @@ -154,18 +182,18 @@ export { 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; + const write_file_log: function(state: State) &redef; } redef record FileInfo += { ## ID referencing this file. - fid : count &optional; + fid : count &optional; ## Maintain a reference to the file record. - f : fa_file &optional; + f : fa_file &optional; ## UUID referencing this file if DCE/RPC - uuid: string &optional; + uuid : string &optional; }; const ports = { 139/tcp, 445/tcp }; @@ -191,12 +219,33 @@ function set_current_file(smb_state: State, file_id: count) smb_state$current_file = smb_state$fid_map[file_id]; } -function write_file_log(f: FileInfo) +function write_file_log(state: State) { + local f = state$current_file; if ( f?$name && f$name !in pipe_names && f$action in logged_file_actions ) { + # Everything in this if statement is to avoid overlogging + # of the same data from a single connection based on recently + # seen files in the SMB::State $recent_files field. + if ( f?$times ) + { + local file_ident = cat(f$action, + f?$fuid ? f$fuid : "", + f?$name ? f$name : "", + f?$path ? f$path : "", + f$size, + f$times); + if ( file_ident in state$recent_files ) + { + # We've already seen this file and don't want to log it again. + return; + } + else + add state$recent_files[file_ident]; + } + Log::write(FILES_LOG, f); } } @@ -211,7 +260,7 @@ event file_state_remove(f: fa_file) &priority=-5 local c = f$conns[id]; if ( c?$smb_state && c$smb_state?$current_file) { - write_file_log(c$smb_state$current_file); + write_file_log(c$smb_state); } return; } diff --git a/scripts/base/protocols/smb/pipe.bro b/scripts/base/protocols/smb/pipe.bro index d9f201d455..6057c73700 100644 --- a/scripts/base/protocols/smb/pipe.bro +++ b/scripts/base/protocols/smb/pipe.bro @@ -6,25 +6,18 @@ export { }; 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; + ts : time &log; ##< Time of the request + uid : string &log; ##< UID of the connection + id : conn_id &log; ##< Connection info + command : string &log; ##< Command (add, enum, delete, etc.) + arg : string &log; ##< Argument + server : string &log; ##< Server the command was issued to + result : string &log &optional; ##< Result of the command }; } -redef record connection += { - smb_atsvc: ATSvcInfo &optional; +redef record SMB::State += { + pipe_atsvc: ATSvcInfo &optional; }; event bro_init() &priority=5 @@ -32,28 +25,28 @@ event bro_init() &priority=5 Log::create_stream(ATSVC_LOG, [$columns=ATSvcInfo]); } -event smb_atsvc_job_add(c: connection, server: string, job: string) +event smb_atsvc_job_add(c: connection, server: string, job: string) &priority=5 { - 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; + local info = ATSvcInfo($ts=network_time(), + $uid = c$uid, + $id = c$id, + $command = "Add job", + $arg = job, + $server = server); + c$smb_state$pipe_atsvc = info; } -event smb_atsvc_job_id(c: connection, id: count, status: count) +event smb_atsvc_job_id(c: connection, id: count, status: count) &priority=5 { - if ( !c?$smb_atsvc ) - return; - if ( status == 0 ) - c$smb_atsvc$result = "success"; - else - c$smb_atsvc$result = "failed"; + if ( c$smb_state?$pipe_atsvc ) + c$smb_state$pipe_atsvc$result = (status==0) ? "success" : "failed"; + } - Log::write(ATSVC_LOG, c$smb_atsvc); - delete c$smb_atsvc; +event smb_atsvc_job_id(c: connection, id: count, status: count) &priority=-5 + { + if ( c$smb_state?$pipe_atsvc ) + { + Log::write(ATSVC_LOG, c$smb_state$pipe_atsvc); + delete c$smb_state$pipe_atsvc; + } } \ No newline at end of file diff --git a/scripts/base/protocols/smb/smb1-main.bro b/scripts/base/protocols/smb/smb1-main.bro index 4756554ce0..d0f9bb3c1e 100644 --- a/scripts/base/protocols/smb/smb1-main.bro +++ b/scripts/base/protocols/smb/smb1-main.bro @@ -168,7 +168,7 @@ event smb1_nt_create_andx_response(c: connection, hdr: SMB1::Header, file_id: co c$smb_state$current_file = c$smb_state$fid_map[file_id]; - SMB::write_file_log(c$smb_state$current_file); + SMB::write_file_log(c$smb_state); } event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=5 @@ -237,7 +237,7 @@ event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &prio delete c$smb_state$fid_map[file_id]; - SMB::write_file_log(fl); + SMB::write_file_log(c$smb_state); } else { diff --git a/scripts/base/protocols/smb/smb2-main.bro b/scripts/base/protocols/smb/smb2-main.bro index e668d9b2fd..60c3edf425 100644 --- a/scripts/base/protocols/smb/smb2-main.bro +++ b/scripts/base/protocols/smb/smb2-main.bro @@ -28,7 +28,7 @@ event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=5 smb_state$tid_map[tid] = tmp_tree; } smb_state$current_tree = smb_state$tid_map[tid]; - + if ( mid !in smb_state$pending_cmds ) { local tmp_cmd: SMB::CmdInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB2", $command = SMB2::commands[hdr$command]]; @@ -114,30 +114,43 @@ event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB event smb2_create_request(c: connection, hdr: SMB2::Header, name: string) &priority=5 { - local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id]; + local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $name=name]; + + switch ( c$smb_state$current_cmd$referenced_tree$share_type ) + { + case "DISK": + tmp_file$action = SMB::FILE_OPEN; + break; + case "PIPE": + tmp_file$action = SMB::PIPE_OPEN; + break; + case "PRINT": + tmp_file$action = SMB::PRINT_OPEN; + break; + default: + tmp_file$action = SMB::UNKNOWN_OPEN; + break; + } 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 { - 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_state$current_cmd$referenced_file$times = times; - + # We can identify the file by its file id now so let's stick it # in the file map. c$smb_state$fid_map[file_id$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); + + SMB::write_file_log(c$smb_state); } event smb2_set_info_request(c: connection, hdr: SMB2::Header, request: SMB2::SetInfoRequest) &priority=5 @@ -148,7 +161,22 @@ event smb2_set_info_request(c: connection, hdr: SMB2::Header, request: SMB2::Set event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5 { SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile); - c$smb_state$current_file$action = SMB::FILE_READ; + + switch ( c$smb_state$current_cmd$referenced_tree$share_type ) + { + case "DISK": + c$smb_state$current_file$action = SMB::FILE_READ; + break; + case "PIPE": + c$smb_state$current_file$action = SMB::PIPE_READ; + break; + case "PRINT": + c$smb_state$current_file$action = SMB::PRINT_READ; + break; + default: + c$smb_state$current_file$action = SMB::UNKNOWN_OPEN; + break; + } } event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5 @@ -157,13 +185,28 @@ event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, o 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); + #write_file_log(c$smb_state); } event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5 { SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile); - c$smb_state$current_file$action = SMB::FILE_WRITE; + + switch ( c$smb_state$current_cmd$referenced_tree$share_type ) + { + case "DISK": + c$smb_state$current_file$action = SMB::FILE_WRITE; + break; + case "PIPE": + c$smb_state$current_file$action = SMB::PIPE_WRITE; + break; + case "PRINT": + c$smb_state$current_file$action = SMB::PRINT_WRITE; + break; + default: + c$smb_state$current_file$action = SMB::UNKNOWN_WRITE; + break; + } } event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5 @@ -172,13 +215,28 @@ event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, 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); + #write_file_log(c$smb_state); } event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=5 { SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile); - c$smb_state$current_file$action = SMB::FILE_CLOSE; + + switch ( c$smb_state$current_cmd$referenced_tree$share_type ) + { + case "DISK": + c$smb_state$current_file$action = SMB::FILE_CLOSE; + break; + case "PIPE": + c$smb_state$current_file$action = SMB::PIPE_CLOSE; + break; + case "PRINT": + c$smb_state$current_file$action = SMB::PRINT_CLOSE; + break; + default: + c$smb_state$current_file$action = SMB::UNKNOWN_CLOSE; + break; + } } event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=-5 @@ -191,7 +249,7 @@ event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) 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); + SMB::write_file_log(c$smb_state); } else { diff --git a/src/analyzer/protocol/smb/SMB.cc b/src/analyzer/protocol/smb/SMB.cc index 643c8a4ae6..19e7dec13f 100644 --- a/src/analyzer/protocol/smb/SMB.cc +++ b/src/analyzer/protocol/smb/SMB.cc @@ -58,8 +58,8 @@ void SMB_Analyzer::DeliverStream(int len, const u_char* data, bool orig) } catch ( const binpac::Exception& e ) { - ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); - //printf(fmt("Binpac exception: %s", e.c_msg())); + ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); + //printf(fmt("Binpac exception: %s", e.c_msg())); } } @@ -161,11 +161,6 @@ void Contents_SMB::DeliverStream(int len, const u_char* data, bool orig) case WAIT_FOR_HDR: { // We have the 4 bytes header now - - // This does not abide the spec, but we've seen it - // in real traffic. - if (data[1] > 2) - Conn()->Weird(fmt("NetBIOS session flags > 2: %d", data[1])); msg_len = 0; msg_type = data[0]; for ( int i = 1; i < 4; i++) diff --git a/src/analyzer/protocol/smb/smb-pipe.pac b/src/analyzer/protocol/smb/smb-pipe.pac index f09cb6d53c..78de7d048b 100644 --- a/src/analyzer/protocol/smb/smb-pipe.pac +++ b/src/analyzer/protocol/smb/smb-pipe.pac @@ -8,6 +8,9 @@ %} refine connection SMB_Conn += { + %member{ + map tree_is_pipe_map; + %} function get_tree_is_pipe(tree_id: uint16): bool %{ @@ -19,13 +22,9 @@ refine connection SMB_Conn += { function set_tree_is_pipe(tree_id: uint16, is_pipe: bool): bool %{ tree_is_pipe_map[tree_id] = is_pipe; - return true; + return true; %} - %member{ - map tree_is_pipe_map; - %} - function proc_smb_pipe_message(val: SMB_Pipe_message, header: SMB_Header): bool %{ switch ( ${val.rpc_header.PTYPE} ) { @@ -83,45 +82,43 @@ type SMB_Pipe_message(header: SMB_Header, byte_count: uint16) = record { proc: bool = $context.connection.proc_smb_pipe_message(this, header); } &byteorder = littleendian; -type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record { - - rap_code : uint16; - param_desc : SMB_string(unicode, offsetof(param_desc) ); - data_desc : SMB_string(unicode, offsetof(data_desc) ); - data : bytestring &restofdata; - +type SMB_RAP_message(unicode: bool, byte_count: uint16) = record { + rap_code : uint16; + param_desc : SMB_string(unicode, offsetof(param_desc)); + data_desc : SMB_string(unicode, offsetof(data_desc)); + data : bytestring &restofdata; } &byteorder = littleendian; type AT_SVC_Request(unicode: bool, opnum: uint8) = record { empty: padding[1]; op: case opnum of { - 0 -> add: AT_SVC_NetrJobAdd(unicode); - default -> unknown: bytestring &restofdata; + 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)); + 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); + 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); }; type AT_SVC_Reply(unicode: bool, opnum: uint16) = record { op: case opnum of { - 0 -> add: AT_SVC_JobID(unicode); + 0 -> add: AT_SVC_JobID(unicode); default -> unknown: bytestring &restofdata; }; }; diff --git a/src/analyzer/protocol/smb/smb1-com-transaction.pac b/src/analyzer/protocol/smb/smb1-com-transaction.pac index b5c19a332a..4db7a4a209 100644 --- a/src/analyzer/protocol/smb/smb1-com-transaction.pac +++ b/src/analyzer/protocol/smb/smb1-com-transaction.pac @@ -10,8 +10,11 @@ refine connection SMB_Conn += { function proc_smb1_transaction_request(header: SMB_Header, val: SMB1_transaction_request): bool %{ if ( smb1_transaction_request ) - BifEvent::generate_smb1_transaction_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), \ - smb_string2stringval(${val.name}), ${val.sub_cmd}); + BifEvent::generate_smb1_transaction_request(bro_analyzer(), + bro_analyzer()->Conn(), + BuildHeaderVal(header), + smb_string2stringval(${val.name}), + ${val.sub_cmd}); return true; %} @@ -24,8 +27,11 @@ refine connection SMB_Conn += { function proc_smb1_transaction_setup(header: SMB_Header, val: SMB1_transaction_setup): bool %{ if ( smb1_transaction_setup ) - BifEvent::generate_smb1_transaction_setup(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), \ - ${val.op_code}, ${val.file_id}); + BifEvent::generate_smb1_transaction_setup(bro_analyzer(), + bro_analyzer()->Conn(), + BuildHeaderVal(header), + ${val.op_code}, + ${val.file_id}); return true; %} @@ -33,13 +39,13 @@ refine connection SMB_Conn += { type SMB1_transaction_data(header: SMB_Header, count: uint16, sub_cmd: uint16, - trans_type: TransactionType ) = case trans_type of { + 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); SMB_PIPE -> pipe : SMB_Pipe_message(header, count); - SMB_UNKNOWN -> unknown : bytestring &restofdata; -# default -> data : bytestring &restofdata; + SMB_UNKNOWN -> unknown : bytestring &restofdata &transient; + default -> data : bytestring &restofdata &transient; }; type SMB1_transaction_setup(header: SMB_Header) = record { @@ -79,7 +85,6 @@ type SMB1_transaction_request(header: SMB_Header) = record { 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; @@ -99,10 +104,8 @@ type SMB1_transaction_response(header: SMB_Header) = record { 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.get_tree_is_pipe(header.tid) 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); - }; + data : SMB1_transaction_data(header, data_count, 0, is_tree_a_pipe ? SMB_PIPE : SMB_UNKNOWN)[data_count>0 ? 1 : 0]; } &let { proc : bool = $context.connection.proc_smb1_transaction_response(header, this); + is_tree_a_pipe: bool = $context.connection.get_tree_is_pipe(header.tid); }; diff --git a/src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac b/src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac index cb7f63d548..030c213902 100644 --- a/src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac +++ b/src/analyzer/protocol/smb/smb1-com-tree-connect-andx.pac @@ -13,7 +13,7 @@ refine connection SMB_Conn += { function proc_smb1_tree_connect_andx_response(header: SMB_Header, val: SMB1_tree_connect_andx_response): bool %{ - set_tree_is_pipe(${header.tid}, strcmp((const char*) smb_string2stringval(${val.service})->Bytes(), "IPC") == 0); + set_tree_is_pipe(${header.tid}, strncmp((const char*) smb_string2stringval(${val.service})->Bytes(), "IPC", 3) == 0); if ( smb1_tree_connect_andx_response ) BifEvent::generate_smb1_tree_connect_andx_response(bro_analyzer(), bro_analyzer()->Conn(), diff --git a/src/analyzer/protocol/smb/smb1-com-write-andx.pac b/src/analyzer/protocol/smb/smb1-com-write-andx.pac index f508a62e68..cf56f6db9c 100644 --- a/src/analyzer/protocol/smb/smb1-com-write-andx.pac +++ b/src/analyzer/protocol/smb/smb1-com-write-andx.pac @@ -52,7 +52,7 @@ type SMB1_write_andx_request(header: SMB_Header) = record { byte_count : uint16; pad : padding to data_offset - SMB_Header_length; - is_pipe : case $context.connection.get_tree_is_pipe(header.tid) of { + is_pipe : case $context.connection.get_tree_is_pipe(header.tid) of { true -> pipe_data : SMB_Pipe_message(header, byte_count) &length=data_len; default -> data : bytestring &length=data_len; } &requires(data_len); diff --git a/src/analyzer/protocol/smb/smb2-com-negotiate.pac b/src/analyzer/protocol/smb/smb2-com-negotiate.pac index 956d7b0bdf..c95eec49dc 100644 --- a/src/analyzer/protocol/smb/smb2-com-negotiate.pac +++ b/src/analyzer/protocol/smb/smb2-com-negotiate.pac @@ -43,7 +43,7 @@ type SMB2_negotiate_request(header: SMB2_Header) = record { 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_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 { diff --git a/src/analyzer/protocol/smb/smb2-com-read.pac b/src/analyzer/protocol/smb/smb2-com-read.pac index 9fb4d9ce08..612fa01cf2 100644 --- a/src/analyzer/protocol/smb/smb2-com-read.pac +++ b/src/analyzer/protocol/smb/smb2-com-read.pac @@ -25,7 +25,7 @@ refine connection SMB_Conn += { function proc_smb2_read_response(h: SMB2_Header, val: SMB2_read_response) : bool %{ - if ( ${val.data_len} > 0 ) + if ( ! ${val.is_pipe} && ${val.data_len} > 0 ) { uint64 offset = smb2_read_offsets[${h.message_id}]; smb2_read_offsets.erase(${h.message_id}); @@ -67,7 +67,13 @@ type SMB2_read_response(header: SMB2_Header) = record { data_remaining : uint32; reserved : uint32; pad : padding to data_offset - header.head_length; - data : bytestring &length=data_len; + pipe_file_switch : case is_pipe of { + # The SMB_Pipe_message type doesn't support smb2 pipes yet. + #true -> pipe_data : SMB_Pipe_message(header, data_len) &length=data_len; + false -> data : bytestring &length=data_len; + }; } &let { + is_pipe: bool = $context.connection.get_tree_is_pipe(header.tree_id); + proc: bool = $context.connection.proc_smb2_read_response(header, this); }; diff --git a/src/analyzer/protocol/smb/smb2-com-tree-connect.pac b/src/analyzer/protocol/smb/smb2-com-tree-connect.pac index 5c6ae8020d..f2860172b1 100644 --- a/src/analyzer/protocol/smb/smb2-com-tree-connect.pac +++ b/src/analyzer/protocol/smb/smb2-com-tree-connect.pac @@ -13,10 +13,11 @@ refine connection SMB_Conn += { function proc_smb2_tree_connect_response(header: SMB2_Header, val: SMB2_tree_connect_response): bool %{ + set_tree_is_pipe(${header.tree_id}, ${val.share_type} == SMB2_SHARE_TYPE_PIPE); + 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(), diff --git a/src/analyzer/protocol/smb/smb2-com-write.pac b/src/analyzer/protocol/smb/smb2-com-write.pac index 64a9d72254..64a5eaa106 100644 --- a/src/analyzer/protocol/smb/smb2-com-write.pac +++ b/src/analyzer/protocol/smb/smb2-com-write.pac @@ -12,7 +12,7 @@ refine connection SMB_Conn += { ${val.data_len}); } - if ( ${val.data}.length() > 0 ) + if ( ! ${val.is_pipe} && ${val.data}.length() > 0 ) { file_mgr->DataIn(${val.data}.begin(), ${val.data_len}, ${val.offset}, bro_analyzer()->GetAnalyzerTag(), @@ -32,19 +32,25 @@ refine connection SMB_Conn += { 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; + 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; + channel_info_len : uint16; # ignore + flags : uint32; + pad : padding to data_offset - header.head_length; + pipe_file_switch : case is_pipe of { + # The SMB_Pipe_message type doesn't support smb2 pipes yet. + #true -> pipe_data : SMB_Pipe_message(header, data_len) &length=data_len; + default -> data : bytestring &length=data_len; + }; } &let { + is_pipe: bool = $context.connection.get_tree_is_pipe(header.tree_id); + proc : bool = $context.connection.proc_smb2_write_request(header, this); }; diff --git a/src/analyzer/protocol/smb/smb2-protocol.pac b/src/analyzer/protocol/smb/smb2-protocol.pac index 7831a5ba0e..5acdabd8bd 100644 --- a/src/analyzer/protocol/smb/smb2-protocol.pac +++ b/src/analyzer/protocol/smb/smb2-protocol.pac @@ -23,6 +23,12 @@ enum smb2_commands { SMB2_OPLOCK_BREAK = 18, }; +enum smb2_share_types { + SMB2_SHARE_TYPE_DISK = 0x01, + SMB2_SHARE_TYPE_PIPE = 0x02, + SMB2_SHARE_TYPE_PRINT = 0x03, +}; + type SMB2_PDU(is_orig: bool) = record { header : SMB2_Header(is_orig); message : case header.status of {