diff --git a/scripts/base/protocols/dce-rpc/main.bro b/scripts/base/protocols/dce-rpc/main.bro index bd173a8b7d..795f575605 100644 --- a/scripts/base/protocols/dce-rpc/main.bro +++ b/scripts/base/protocols/dce-rpc/main.bro @@ -36,9 +36,15 @@ type State: record { named_pipe : string &optional; }; +type Stuff: record { + info: Info; + state: State; +}; + redef record connection += { dce_rpc: Info &optional; - dce_rpc_state: State &default=State(); + dce_rpc_state: State &optional; + dce_rpc_state_x: table[count] of Stuff &optional; }; const ports = { 135/tcp }; @@ -50,14 +56,10 @@ event bro_init() &priority=5 Analyzer::register_for_ports(Analyzer::ANALYZER_DCE_RPC, ports); } -function set_session(c: connection) +function set_state(c: connection, state_x: Stuff) { - if ( ! c?$dce_rpc ) - { - c$dce_rpc = [$ts=network_time(), - $id=c$id, - $uid=c$uid]; - } + c$dce_rpc = state_x$info; + c$dce_rpc_state = state_x$state; if ( c$dce_rpc_state?$uuid ) c$dce_rpc$endpoint = uuid_endpoint_map[c$dce_rpc_state$uuid]; @@ -65,9 +67,25 @@ function set_session(c: connection) c$dce_rpc$named_pipe = c$dce_rpc_state$named_pipe; } -event dce_rpc_bind(c: connection, uuid: string, ver_major: count, ver_minor: count) &priority=5 +function set_session(c: connection, fid: count) { - set_session(c); + if ( ! c?$dce_rpc_state_x ) + { + c$dce_rpc_state_x = table(); + } + if ( fid !in c$dce_rpc_state_x ) + { + local info = Info($ts=network_time(),$id=c$id,$uid=c$uid); + c$dce_rpc_state_x[fid] = Stuff($info=info, $state=State()); + } + + local state_x = c$dce_rpc_state_x[fid]; + set_state(c, state_x); + } + +event dce_rpc_bind(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count) &priority=5 + { + set_session(c, fid); local uuid_str = uuid_to_string(uuid); if ( uuid_str in ignored_uuids ) @@ -77,9 +95,9 @@ event dce_rpc_bind(c: connection, uuid: string, ver_major: count, ver_minor: cou c$dce_rpc$endpoint = uuid_endpoint_map[uuid_str]; } -event dce_rpc_bind_ack(c: connection, sec_addr: string) &priority=5 +event dce_rpc_bind_ack(c: connection, fid: count, sec_addr: string) &priority=5 { - set_session(c); + set_session(c, fid); if ( sec_addr != "" ) { @@ -88,19 +106,19 @@ event dce_rpc_bind_ack(c: connection, sec_addr: string) &priority=5 } } -event dce_rpc_request(c: connection, opnum: count, stub_len: count) &priority=5 +event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) &priority=5 { - set_session(c); + set_session(c, fid); - if ( c?$dce_rpc ) + if ( c?$dce_rpc ) { c$dce_rpc$ts = network_time(); } } -event dce_rpc_response(c: connection, opnum: count, stub_len: count) &priority=5 +event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=5 { - set_session(c); + set_session(c, fid); if ( c?$dce_rpc && c$dce_rpc?$endpoint ) { @@ -110,11 +128,11 @@ event dce_rpc_response(c: connection, opnum: count, stub_len: count) &priority=5 } } -event dce_rpc_response(c: connection, opnum: count, stub_len: count) &priority=-5 +event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=-5 { if ( c?$dce_rpc ) { - # If there is not endpoint, there isn't much reason to log. + # If there is not an endpoint, there isn't much reason to log. # This can happen if the request isn't seen. if ( c$dce_rpc?$endpoint ) Log::write(LOG, c$dce_rpc); @@ -128,4 +146,11 @@ event connection_state_remove(c: connection) return; # TODO: Go through any remaining dce_rpc requests that haven't been processed with replies. + for ( i in c$dce_rpc_state_x ) + { + local x = c$dce_rpc_state_x[i]; + set_state(c, x); + if ( c$dce_rpc?$endpoint ) + Log::write(LOG, c$dce_rpc); + } } \ No newline at end of file diff --git a/src/analyzer/protocol/dce-rpc/DCE_RPC.h b/src/analyzer/protocol/dce-rpc/DCE_RPC.h index 984ede8a3c..4f1da1612d 100644 --- a/src/analyzer/protocol/dce-rpc/DCE_RPC.h +++ b/src/analyzer/protocol/dce-rpc/DCE_RPC.h @@ -185,6 +185,9 @@ public: virtual void Undelivered(uint64 seq, int len, bool orig); virtual void EndpointEOF(bool is_orig); + bool SetFileID(uint64 fid_in) + { interp->set_file_id(fid_in); return true; } + static analyzer::Analyzer* Instantiate(Connection* conn) { return new DCE_RPC_Analyzer(conn); } diff --git a/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac b/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac index dce1340bb5..f2242ca2ac 100644 --- a/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac +++ b/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac @@ -3,8 +3,19 @@ refine connection DCE_RPC_Conn += { %member{ map cont_id_opnum_map; + uint64 fid; %} + %init{ + fid=0; + %} + + function set_file_id(fid_in: uint64): bool + %{ + fid = fid_in; + return true; + %} + function get_cont_id_opnum_map(cont_id: uint16): uint16 %{ return cont_id_opnum_map[cont_id]; @@ -30,6 +41,7 @@ refine connection DCE_RPC_Conn += { BifEvent::generate_dce_rpc_message(bro_analyzer(), bro_analyzer()->Conn(), ${header.is_orig}, + fid, ${header.PTYPE}, new EnumVal(${header.PTYPE}, BifType::Enum::DCE_RPC::PType)); } @@ -52,6 +64,7 @@ refine connection DCE_RPC_Conn += { // Queue the event BifEvent::generate_dce_rpc_bind(bro_analyzer(), bro_analyzer()->Conn(), + fid, bytestring_to_val(${uuid}), ${ver_major}, ${ver_minor}); @@ -67,13 +80,19 @@ refine connection DCE_RPC_Conn += { { StringVal *sec_addr; // Remove the null from the end of the string if it's there. - if ( *(${bind.sec_addr}.begin() + ${bind.sec_addr}.length()) == 0 ) + if ( ${bind.sec_addr}.length() > 0 && + *(${bind.sec_addr}.begin() + ${bind.sec_addr}.length()) == 0 ) + { sec_addr = new StringVal(${bind.sec_addr}.length()-1, (const char*) ${bind.sec_addr}.begin()); + } else + { sec_addr = new StringVal(${bind.sec_addr}.length(), (const char*) ${bind.sec_addr}.begin()); + } BifEvent::generate_dce_rpc_bind_ack(bro_analyzer(), bro_analyzer()->Conn(), + fid, sec_addr); } return true; @@ -85,6 +104,7 @@ refine connection DCE_RPC_Conn += { { BifEvent::generate_dce_rpc_request(bro_analyzer(), bro_analyzer()->Conn(), + fid, ${req.opnum}, ${req.stub}.length()); } @@ -100,6 +120,7 @@ refine connection DCE_RPC_Conn += { { BifEvent::generate_dce_rpc_response(bro_analyzer(), bro_analyzer()->Conn(), + fid, get_cont_id_opnum_map(${resp.context_id}), ${resp.stub}.length()); } diff --git a/src/analyzer/protocol/dce-rpc/events.bif b/src/analyzer/protocol/dce-rpc/events.bif index d89727ec70..44e0a64224 100644 --- a/src/analyzer/protocol/dce-rpc/events.bif +++ b/src/analyzer/protocol/dce-rpc/events.bif @@ -1,15 +1,15 @@ ## .. bro:see:: dce_rpc_bind dce_rpc_bind_ack dce_rpc_request dce_rpc_response -event dce_rpc_message%(c: connection, is_orig: bool, ptype_id: count, ptype: DCE_RPC::PType%); +event dce_rpc_message%(c: connection, is_orig: bool, fid: count, ptype_id: count, ptype: DCE_RPC::PType%); ## .. bro:see:: dce_rpc_message dce_rpc_bind_ack dce_rpc_request dce_rpc_response -event dce_rpc_bind%(c: connection, uuid: string, ver_major: count, ver_minor: count%); +event dce_rpc_bind%(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count%); ## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_request dce_rpc_response -event dce_rpc_bind_ack%(c: connection, sec_addr: string%); +event dce_rpc_bind_ack%(c: connection, fid: count, sec_addr: string%); ## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_response -event dce_rpc_request%(c: connection, opnum: count, stub_len: count%); +event dce_rpc_request%(c: connection, fid: count, opnum: count, stub_len: count%); ## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request -event dce_rpc_response%(c: connection, opnum: count, stub_len: count%); +event dce_rpc_response%(c: connection, fid: count, opnum: count, stub_len: count%); diff --git a/src/analyzer/protocol/smb/smb-gssapi.pac b/src/analyzer/protocol/smb/smb-gssapi.pac index 9372df7f47..741f5c5523 100644 --- a/src/analyzer/protocol/smb/smb-gssapi.pac +++ b/src/analyzer/protocol/smb/smb-gssapi.pac @@ -1,5 +1,17 @@ refine connection SMB_Conn += { + %member{ + analyzer::Analyzer *gssapi; + %} + + %init{ + gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer->Conn()); + %} + + %cleanup{ + if ( gssapi ) + delete gssapi; + %} function forward_gssapi(data: bytestring, is_orig: bool): bool %{ diff --git a/src/analyzer/protocol/smb/smb-pipe.pac b/src/analyzer/protocol/smb/smb-pipe.pac index 3ec7958ce8..6f55d66082 100644 --- a/src/analyzer/protocol/smb/smb-pipe.pac +++ b/src/analyzer/protocol/smb/smb-pipe.pac @@ -1,9 +1,23 @@ +%extern{ +#include "../dce-rpc/DCE_RPC.h" +%} refine connection SMB_Conn += { %member{ map tree_is_pipe_map; + map fid_to_analyzer_map; %} + %cleanup{ + // Iterate all of the analyzers and destroy them. + for ( auto kv : fid_to_analyzer_map ) + { + if ( kv.second ) + delete kv.second; + } + %} + + function get_tree_is_pipe(tree_id: uint16): bool %{ if ( tree_is_pipe_map.count(tree_id) > 0 ) @@ -18,10 +32,22 @@ refine connection SMB_Conn += { return true; %} - function forward_dce_rpc(pipe_data: bytestring, is_orig: bool): bool + function forward_dce_rpc(pipe_data: bytestring, fid: uint64, is_orig: bool): bool %{ - if ( dcerpc ) - dcerpc->DeliverStream(${pipe_data}.length(), ${pipe_data}.begin(), is_orig); + analyzer::dce_rpc::DCE_RPC_Analyzer *pipe_dcerpc; + if ( fid_to_analyzer_map.count(fid) == 0 ) + { + pipe_dcerpc = (analyzer::dce_rpc::DCE_RPC_Analyzer *)analyzer_mgr->InstantiateAnalyzer("DCE_RPC", bro_analyzer()->Conn()); + pipe_dcerpc->SetFileID(fid); + fid_to_analyzer_map[fid] = pipe_dcerpc; + } + else + { + pipe_dcerpc = fid_to_analyzer_map.at(fid); + } + + pipe_dcerpc->DeliverStream(${pipe_data}.length(), ${pipe_data}.begin(), is_orig); + return true; %} }; \ No newline at end of file diff --git a/src/analyzer/protocol/smb/smb.pac b/src/analyzer/protocol/smb/smb.pac index e6f63db25c..3ac9d40bd5 100644 --- a/src/analyzer/protocol/smb/smb.pac +++ b/src/analyzer/protocol/smb/smb.pac @@ -135,22 +135,3 @@ type SMB_Protocol_Identifier(is_orig: bool, msg_len: uint32) = record { flow SMB_Flow(is_orig: bool) { flowunit = SMB_TCP(is_orig) withcontext(connection, this); }; - -refine connection SMB_Conn += { - %member{ - analyzer::Analyzer *dcerpc; - analyzer::Analyzer *gssapi; - %} - - %init{ - dcerpc = analyzer_mgr->InstantiateAnalyzer("DCE_RPC", bro_analyzer->Conn()); - gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer->Conn()); - %} - - %cleanup{ - if ( dcerpc ) - delete dcerpc; - if ( gssapi ) - delete gssapi; - %} -}; diff --git a/src/analyzer/protocol/smb/smb1-com-read-andx.pac b/src/analyzer/protocol/smb/smb1-com-read-andx.pac index 2b83fed1dc..490fbe75fe 100644 --- a/src/analyzer/protocol/smb/smb1-com-read-andx.pac +++ b/src/analyzer/protocol/smb/smb1-com-read-andx.pac @@ -83,7 +83,7 @@ type SMB1_read_andx_response(header: SMB_Header) = record { data : bytestring &length=data_len; } &let { is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid); - pipe_proc : bool = $context.connection.forward_dce_rpc(data, false) &if(is_pipe); + pipe_proc : bool = $context.connection.forward_dce_rpc(data, 0, false) &if(is_pipe); padding_len : uint8 = (header.unicode == 1) ? 1 : 0; data_len : uint32 = (data_len_high << 16) + data_len_low; diff --git a/src/analyzer/protocol/smb/smb1-com-transaction.pac b/src/analyzer/protocol/smb/smb1-com-transaction.pac index 7319cf8954..40d9657378 100644 --- a/src/analyzer/protocol/smb/smb1-com-transaction.pac +++ b/src/analyzer/protocol/smb/smb1-com-transaction.pac @@ -70,7 +70,7 @@ type SMB1_transaction_data(header: SMB_Header, is_orig: bool, count: uint16, sub SMB_UNKNOWN -> unknown : bytestring &restofdata &transient; default -> data : bytestring &restofdata &transient; } &let { - pipe_proc : bool = $context.connection.forward_dce_rpc(pipe_data, is_orig) &if(trans_type == SMB_PIPE); + pipe_proc : bool = $context.connection.forward_dce_rpc(pipe_data, 0, is_orig) &if(trans_type == SMB_PIPE); }; type SMB1_transaction_setup(header: SMB_Header) = record { diff --git a/src/analyzer/protocol/smb/smb1-com-write-andx.pac b/src/analyzer/protocol/smb/smb1-com-write-andx.pac index 3d4e160968..3905b7293a 100644 --- a/src/analyzer/protocol/smb/smb1-com-write-andx.pac +++ b/src/analyzer/protocol/smb/smb1-com-write-andx.pac @@ -55,7 +55,7 @@ type SMB1_write_andx_request(header: SMB_Header) = record { data : bytestring &length=data_len; } &let { is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid); - pipe_proc : bool = $context.connection.forward_dce_rpc(data, true) &if(is_pipe); + pipe_proc : bool = $context.connection.forward_dce_rpc(data, 0, true) &if(is_pipe); data_len : uint32 = (data_len_high << 16) + data_len_low; offset_high : uint32 = (word_count == 0x0E) ? offset_high_tmp : 0; diff --git a/src/analyzer/protocol/smb/smb2-com-ioctl.pac b/src/analyzer/protocol/smb/smb2-com-ioctl.pac index 8a54959097..1d1e6ad8ea 100644 --- a/src/analyzer/protocol/smb/smb2-com-ioctl.pac +++ b/src/analyzer/protocol/smb/smb2-com-ioctl.pac @@ -1,4 +1,25 @@ refine connection SMB_Conn += { + %member{ + std::map smb2_ioctl_fids; + %} + + function get_ioctl_fid(message_id: uint64): uint64 + %{ + if ( smb2_ioctl_fids.count(message_id) == 0 ) + return 0; + else + { + uint64 fid = smb2_ioctl_fids[message_id]; + smb2_ioctl_fids.erase(message_id); + return fid; + } + %} + + function proc_smb2_ioctl_request(val: SMB2_ioctl_request) : bool + %{ + smb2_ioctl_fids[${val.header.message_id}] = ${val.file_id.persistent} + ${val.file_id._volatile}; + return true; + %} }; @@ -22,7 +43,9 @@ type SMB2_ioctl_request(header: SMB2_Header) = record { } &let { # We only handle FSCTL_PIPE_TRANSCEIVE messages right now. is_pipe: bool = (ctl_code == 0x0011C017); - pipe_proc : bool = $context.connection.forward_dce_rpc(input_buffer, true) &if(is_pipe); + fid: uint64 = file_id.persistent + file_id._volatile; + pipe_proc : bool = $context.connection.forward_dce_rpc(input_buffer, fid, true) &if(is_pipe); + proc : bool = $context.connection.proc_smb2_ioctl_request(this); }; type SMB2_ioctl_response(header: SMB2_Header) = record { @@ -42,6 +65,7 @@ type SMB2_ioctl_response(header: SMB2_Header) = record { output_buffer : bytestring &length=output_count; } &let { # We only handle FSCTL_PIPE_TRANSCEIVE messages right now. - is_pipe: bool = (ctl_code == 0x0011C017); - pipe_proc : bool = $context.connection.forward_dce_rpc(output_buffer, false) &if(is_pipe); + is_pipe : bool = (ctl_code == 0x0011C017); + fid : uint64 = $context.connection.get_ioctl_fid(header.message_id); + pipe_proc : bool = $context.connection.forward_dce_rpc(output_buffer, fid, false) &if(is_pipe); }; \ No newline at end of file diff --git a/src/analyzer/protocol/smb/smb2-com-read.pac b/src/analyzer/protocol/smb/smb2-com-read.pac index 10e3a98acf..b3601b3d67 100644 --- a/src/analyzer/protocol/smb/smb2-com-read.pac +++ b/src/analyzer/protocol/smb/smb2-com-read.pac @@ -4,8 +4,21 @@ refine connection SMB_Conn += { // Track read offsets to provide correct // offsets for file manager. std::map smb2_read_offsets; + std::map smb2_read_fids; %} + function get_file_id(message_id: uint64): uint64 + %{ + if ( smb2_read_fids.count(message_id) == 0 ) + return 0; + else + { + uint64 fid = smb2_read_fids[message_id]; + smb2_read_fids.erase(message_id); + return fid; + } + %} + function proc_smb2_read_request(h: SMB2_Header, val: SMB2_read_request) : bool %{ if ( smb2_read_request ) @@ -19,22 +32,28 @@ refine connection SMB_Conn += { } smb2_read_offsets[${h.message_id}] = ${val.offset}; + smb2_read_fids[${h.message_id}] = ${val.file_id.persistent} + ${val.file_id._volatile}; return true; %} function proc_smb2_read_response(h: SMB2_Header, val: SMB2_read_response) : bool %{ + uint64 offset = smb2_read_offsets[${h.message_id}]; + smb2_read_offsets.erase(${h.message_id}); + if ( ! ${val.is_pipe} && ${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()); } + + if ( ${val.is_pipe} ) + { + } + return true; %} @@ -69,8 +88,9 @@ type SMB2_read_response(header: SMB2_Header) = record { pad : padding to data_offset - header.head_length; data : bytestring &length=data_len; } &let { - is_pipe : bool = $context.connection.get_tree_is_pipe(header.tree_id); - pipe_proc : bool = $context.connection.forward_dce_rpc(data, false) &if(is_pipe); + is_pipe : bool = $context.connection.get_tree_is_pipe(header.tree_id); + fid : uint64 = $context.connection.get_file_id(header.message_id); + pipe_proc : bool = $context.connection.forward_dce_rpc(data, fid, false) &if(is_pipe); proc: bool = $context.connection.proc_smb2_read_response(header, this); }; diff --git a/src/analyzer/protocol/smb/smb2-com-write.pac b/src/analyzer/protocol/smb/smb2-com-write.pac index 06cfd1d1d6..13b0a0828b 100644 --- a/src/analyzer/protocol/smb/smb2-com-write.pac +++ b/src/analyzer/protocol/smb/smb2-com-write.pac @@ -46,7 +46,7 @@ type SMB2_write_request(header: SMB2_Header) = record { data : bytestring &length=data_len; } &let { is_pipe: bool = $context.connection.get_tree_is_pipe(header.tree_id); - pipe_proc : bool = $context.connection.forward_dce_rpc(data, true) &if(is_pipe); + pipe_proc : bool = $context.connection.forward_dce_rpc(data, file_id.persistent+file_id._volatile, true) &if(is_pipe); proc : bool = $context.connection.proc_smb2_write_request(header, this); };