diff --git a/NEWS b/NEWS index 77e1c7007f..7c6312aedb 100644 --- a/NEWS +++ b/NEWS @@ -434,6 +434,19 @@ Changed Functionality and the original weird.log may not differ much either, except in the cases where a particular weird type exceeds the sampling threshold. +- Improved DCE-RPC analysis via tracking of context identifier mappings + + - These DCE-RPC events now contain an additional context-id argument: + + - dce_rpc_bind + - dce_rpc_request + - dce_rpc_response + + - Added new events: + + - dce_rpc_alter_context + - dce_rpc_alter_context_resp + Removed Functionality --------------------- diff --git a/scripts/base/protocols/dce-rpc/main.bro b/scripts/base/protocols/dce-rpc/main.bro index 3b028131f3..13bab9b638 100644 --- a/scripts/base/protocols/dce-rpc/main.bro +++ b/scripts/base/protocols/dce-rpc/main.bro @@ -37,6 +37,7 @@ export { type State: record { uuid : string &optional; named_pipe : string &optional; + ctx_to_uuid: table[count] of string &optional; }; # This is to store the log and state information @@ -100,11 +101,30 @@ function set_session(c: connection, fid: count) set_state(c, state_x); } -event dce_rpc_bind(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count) &priority=5 +event dce_rpc_bind(c: connection, fid: count, ctx_id: count, uuid: string, ver_major: count, ver_minor: count) &priority=5 { set_session(c, fid); local uuid_str = uuid_to_string(uuid); + + if ( ! c$dce_rpc_state?$ctx_to_uuid ) + c$dce_rpc_state$ctx_to_uuid = table(); + + c$dce_rpc_state$ctx_to_uuid[ctx_id] = uuid_str; + c$dce_rpc_state$uuid = uuid_str; + c$dce_rpc$endpoint = uuid_endpoint_map[uuid_str]; + } + +event dce_rpc_alter_context(c: connection, fid: count, ctx_id: count, uuid: string, ver_major: count, ver_minor: count) &priority=5 + { + set_session(c, fid); + + local uuid_str = uuid_to_string(uuid); + + if ( ! c$dce_rpc_state?$ctx_to_uuid ) + c$dce_rpc_state$ctx_to_uuid = table(); + + c$dce_rpc_state$ctx_to_uuid[ctx_id] = uuid_str; c$dce_rpc_state$uuid = uuid_str; c$dce_rpc$endpoint = uuid_endpoint_map[uuid_str]; } @@ -120,7 +140,12 @@ event dce_rpc_bind_ack(c: connection, fid: count, sec_addr: string) &priority=5 } } -event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) &priority=5 +event dce_rpc_alter_context_resp(c: connection, fid: count) &priority=5 + { + set_session(c, fid); + } + +event dce_rpc_request(c: connection, fid: count, ctx_id: count, opnum: count, stub_len: count) &priority=5 { set_session(c, fid); @@ -130,7 +155,7 @@ event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) } } -event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=5 +event dce_rpc_response(c: connection, fid: count, ctx_id: count, opnum: count, stub_len: count) &priority=5 { set_session(c, fid); @@ -146,15 +171,26 @@ event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) } } - if ( c?$dce_rpc && c$dce_rpc?$endpoint ) + if ( c?$dce_rpc ) { - c$dce_rpc$operation = operations[c$dce_rpc_state$uuid, opnum]; - if ( c$dce_rpc$ts != network_time() ) - c$dce_rpc$rtt = network_time() - c$dce_rpc$ts; + if ( c$dce_rpc?$endpoint ) + { + c$dce_rpc$operation = operations[c$dce_rpc_state$uuid, opnum]; + if ( c$dce_rpc$ts != network_time() ) + c$dce_rpc$rtt = network_time() - c$dce_rpc$ts; + } + + if ( c$dce_rpc_state?$ctx_to_uuid && + ctx_id in c$dce_rpc_state$ctx_to_uuid ) + { + local u = c$dce_rpc_state$ctx_to_uuid[ctx_id]; + c$dce_rpc$endpoint = uuid_endpoint_map[u]; + c$dce_rpc$operation = operations[u, opnum]; + } } } -event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=-5 +event dce_rpc_response(c: connection, fid: count, ctx_id: count, opnum: count, stub_len: count) &priority=-5 { if ( c?$dce_rpc ) { diff --git a/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac b/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac index 53402fd9a0..2bf8550ce5 100644 --- a/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac +++ b/src/analyzer/protocol/dce-rpc/dce_rpc-analyzer.pac @@ -54,6 +54,7 @@ refine connection DCE_RPC_Conn += { BifEvent::generate_dce_rpc_bind(bro_analyzer(), bro_analyzer()->Conn(), fid, + ${req.id}, bytestring_to_val(${req.abstract_syntax.uuid}), ${req.abstract_syntax.ver_major}, ${req.abstract_syntax.ver_minor}); @@ -62,6 +63,22 @@ refine connection DCE_RPC_Conn += { return true; %} + function process_dce_rpc_alter_context(req: ContextRequest): bool + %{ + if ( dce_rpc_alter_context ) + { + BifEvent::generate_dce_rpc_alter_context(bro_analyzer(), + bro_analyzer()->Conn(), + fid, + ${req.id}, + bytestring_to_val(${req.abstract_syntax.uuid}), + ${req.abstract_syntax.ver_major}, + ${req.abstract_syntax.ver_minor}); + } + + return true; + %} + function process_dce_rpc_bind_ack(bind: DCE_RPC_Bind_Ack): bool %{ if ( dce_rpc_bind_ack ) @@ -86,6 +103,17 @@ refine connection DCE_RPC_Conn += { return true; %} + function process_dce_rpc_alter_context_resp(bind: DCE_RPC_AlterContext_Resp): bool + %{ + if ( dce_rpc_alter_context_resp ) + { + BifEvent::generate_dce_rpc_alter_context_resp(bro_analyzer(), + bro_analyzer()->Conn(), + fid); + } + return true; + %} + function process_dce_rpc_request(req: DCE_RPC_Request): bool %{ if ( dce_rpc_request ) @@ -93,6 +121,7 @@ refine connection DCE_RPC_Conn += { BifEvent::generate_dce_rpc_request(bro_analyzer(), bro_analyzer()->Conn(), fid, + ${req.context_id}, ${req.opnum}, ${req.stub}.length()); } @@ -109,6 +138,7 @@ refine connection DCE_RPC_Conn += { BifEvent::generate_dce_rpc_response(bro_analyzer(), bro_analyzer()->Conn(), fid, + ${resp.context_id}, get_cont_id_opnum_map(${resp.context_id}), ${resp.stub}.length()); } @@ -127,13 +157,20 @@ refine typeattr DCE_RPC_Header += &let { }; refine typeattr ContextRequest += &let { - proc = $context.connection.process_dce_rpc_bind(this); + proc = case ptype of { + DCE_RPC_BIND -> $context.connection.process_dce_rpc_bind(this); + DCE_RPC_ALTER_CONTEXT -> $context.connection.process_dce_rpc_alter_context(this); + }; }; refine typeattr DCE_RPC_Bind_Ack += &let { proc = $context.connection.process_dce_rpc_bind_ack(this); }; +refine typeattr DCE_RPC_AlterContext_Resp += &let { + proc = $context.connection.process_dce_rpc_alter_context_resp(this); +}; + refine typeattr DCE_RPC_Request += &let { proc = $context.connection.process_dce_rpc_request(this); }; diff --git a/src/analyzer/protocol/dce-rpc/dce_rpc-protocol.pac b/src/analyzer/protocol/dce-rpc/dce_rpc-protocol.pac index e610efcadc..ad71373423 100644 --- a/src/analyzer/protocol/dce-rpc/dce_rpc-protocol.pac +++ b/src/analyzer/protocol/dce-rpc/dce_rpc-protocol.pac @@ -71,7 +71,7 @@ type Syntax = record { ver_minor : uint16; }; -type ContextRequest = record { +type ContextRequest(ptype: uint8) = record { id : uint16; num_syntaxes : uint8; reserved : padding[1]; @@ -85,11 +85,11 @@ type ContextReply = record { syntax : Syntax; }; -type ContextList(is_request: bool) = record { +type ContextList(is_request: bool, ptype: uint8) = record { num_contexts : uint8; reserved : padding[3]; req_reply : case is_request of { - true -> request_contexts : ContextRequest[num_contexts]; + true -> request_contexts : ContextRequest(ptype)[num_contexts]; false -> reply_contexts : ContextReply[num_contexts]; }; }; @@ -98,7 +98,7 @@ type DCE_RPC_Bind = record { max_xmit_frag : uint16; max_recv_frag : uint16; assoc_group_id : uint32; - context_list : ContextList(1); + context_list : ContextList(1, DCE_RPC_BIND); }; type DCE_RPC_Bind_Ack = record { @@ -108,7 +108,7 @@ type DCE_RPC_Bind_Ack = record { sec_addr_length : uint16; sec_addr : bytestring &length=sec_addr_length; pad : padding align 4; - contexts : ContextList(0); + contexts : ContextList(0, DCE_RPC_BIND_ACK); }; type DCE_RPC_Request(h: DCE_RPC_Header) = record { @@ -136,15 +136,17 @@ type DCE_RPC_AlterContext = record { max_xmit_frag : uint16; max_recv_frag : uint16; assoc_group_id : uint32; - contexts : ContextList(0); + context_list : ContextList(1, DCE_RPC_ALTER_CONTEXT); }; type DCE_RPC_AlterContext_Resp = record { - max_xmit_frag : uint16; - max_recv_frag : uint16; - assoc_group_id : uint32; - sec_addr_len : uint16; - contexts : ContextList(0); + max_xmit_frag : uint16; + max_recv_frag : uint16; + assoc_group_id : uint32; + sec_addr_length : uint16; + sec_addr : bytestring &length=sec_addr_length; + pad : padding align 4; + contexts : ContextList(0, DCE_RPC_ALTER_CONTEXT_RESP); }; type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of { @@ -152,9 +154,8 @@ type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of { DCE_RPC_BIND_ACK -> bind_ack : DCE_RPC_Bind_Ack; DCE_RPC_REQUEST -> request : DCE_RPC_Request(header); DCE_RPC_RESPONSE -> response : DCE_RPC_Response; - # TODO: Something about the two following structures isn't being handled correctly. - #DCE_RPC_ALTER_CONTEXT -> alter_context : DCE_RPC_AlterContext; - #DCE_RPC_ALTER_CONTEXT_RESP -> alter_resp : DCE_RPC_AlterContext_Resp; + DCE_RPC_ALTER_CONTEXT -> alter_context : DCE_RPC_AlterContext; + DCE_RPC_ALTER_CONTEXT_RESP -> alter_resp : DCE_RPC_AlterContext_Resp; default -> other : bytestring &restofdata; }; diff --git a/src/analyzer/protocol/dce-rpc/events.bif b/src/analyzer/protocol/dce-rpc/events.bif index b2a5ef1c4d..1e4a4e0d51 100644 --- a/src/analyzer/protocol/dce-rpc/events.bif +++ b/src/analyzer/protocol/dce-rpc/events.bif @@ -16,7 +16,7 @@ event dce_rpc_message%(c: connection, is_orig: bool, fid: count, ptype_id: count, ptype: DCE_RPC::PType%); ## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` bind request message. -## Since RPC offers the ability for a client to request connections to multiple endpoints, this event can occur +## Since RPC offers the ability for a client to request connections to multiple endpoints, this event can occur ## multiple times for a single RPC message. ## ## c: The connection. @@ -25,6 +25,8 @@ event dce_rpc_message%(c: connection, is_orig: bool, fid: count, ptype_id: count ## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was ## not transported over a pipe. ## +## ctx_id: The context identifier of the data representation. +## ## uuid: The string interpretted uuid of the endpoint being requested. ## ## ver_major: The major version of the endpoint being requested. @@ -32,7 +34,28 @@ event dce_rpc_message%(c: connection, is_orig: bool, fid: count, ptype_id: count ## ver_minor: The minor version of the endpoint being requested. ## ## .. bro:see:: dce_rpc_message dce_rpc_bind_ack dce_rpc_request dce_rpc_response -event dce_rpc_bind%(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count%); +event dce_rpc_bind%(c: connection, fid: count, ctx_id: count, uuid: string, ver_major: count, ver_minor: count%); + +## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` alter context request message. +## Since RPC offers the ability for a client to request connections to multiple endpoints, this event can occur +## multiple times for a single RPC message. +## +## c: The connection. +## +## fid: File ID of the PIPE that carried the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` +## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was +## not transported over a pipe. +## +## ctx_id: The context identifier of the data representation. +## +## uuid: The string interpretted uuid of the endpoint being requested. +## +## ver_major: The major version of the endpoint being requested. +## +## ver_minor: The minor version of the endpoint being requested. +## +## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request dce_rpc_response dce_rpc_alter_context_resp +event dce_rpc_alter_context%(c: connection, fid: count, ctx_id: count, uuid: string, ver_major: count, ver_minor: count%); ## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` bind request ack message. ## @@ -47,6 +70,17 @@ event dce_rpc_bind%(c: connection, fid: count, uuid: string, ver_major: count, v ## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_request dce_rpc_response event dce_rpc_bind_ack%(c: connection, fid: count, sec_addr: string%); +## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` alter context response message. +## +## c: The connection. +## +## fid: File ID of the PIPE that carried the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` +## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was +## not transported over a pipe. +## +## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request dce_rpc_response dce_rpc_alter_context +event dce_rpc_alter_context_resp%(c: connection, fid: count%); + ## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` request message. ## ## c: The connection. @@ -55,12 +89,14 @@ event dce_rpc_bind_ack%(c: connection, fid: count, sec_addr: string%); ## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was ## not transported over a pipe. ## +## ctx_id: The context identifier of the data representation. +## ## opnum: Number of the RPC operation. ## ## stub_len: Length of the data for the request. ## ## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_response -event dce_rpc_request%(c: connection, fid: count, opnum: count, stub_len: count%); +event dce_rpc_request%(c: connection, fid: count, ctx_id: count, opnum: count, stub_len: count%); ## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` response message. ## @@ -70,9 +106,11 @@ event dce_rpc_request%(c: connection, fid: count, opnum: count, stub_len: count% ## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was ## not transported over a pipe. ## +## ctx_id: The context identifier of the data representation. +### ## opnum: Number of the RPC operation. ## ## stub_len: Length of the data for the response. ## ## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request -event dce_rpc_response%(c: connection, fid: count, opnum: count, stub_len: count%); +event dce_rpc_response%(c: connection, fid: count, ctx_id: count, opnum: count, stub_len: count%); diff --git a/testing/btest/Baseline/scripts.base.protocols.dce-rpc.context/dce_rpc.log b/testing/btest/Baseline/scripts.base.protocols.dce-rpc.context/dce_rpc.log new file mode 100644 index 0000000000..383f8be565 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.dce-rpc.context/dce_rpc.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path dce_rpc +#open 2018-08-23-19-54-19 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p rtt named_pipe endpoint operation +#types time string addr port addr port interval string string string +1347446180.330312 CHhAvVGS1DHFjwGM9 192.168.122.145 55614 192.168.122.3 1024 0.005544 \\PIPE\\drsuapi drsuapi DRSBind +1347446180.336310 CHhAvVGS1DHFjwGM9 192.168.122.145 55614 192.168.122.3 1024 0.000788 \\PIPE\\drsuapi drsuapi DRSCrackNames +1347446180.369165 CHhAvVGS1DHFjwGM9 192.168.122.145 55614 192.168.122.3 1024 0.000580 \\PIPE\\drsuapi drsuapi DRSUnbind +#close 2018-08-23-19-54-19 diff --git a/testing/btest/Baseline/scripts.base.protocols.dce-rpc.context/out b/testing/btest/Baseline/scripts.base.protocols.dce-rpc.context/out new file mode 100644 index 0000000000..b54910b5e6 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.dce-rpc.context/out @@ -0,0 +1,15 @@ +dce_rpc_bind :: fid == 0 +dce_rpc_bind :: ctx_id == 0 +dce_rpc_bind :: uuid == e3514235-4b06-11d1-ab04-00c04fc2dcd2 +dce_rpc_bind :: fid == 0 +dce_rpc_bind :: ctx_id == 1 +dce_rpc_bind :: uuid == e3514235-4b06-11d1-ab04-00c04fc2dcd2 +dce_rpc_bind :: fid == 0 +dce_rpc_bind :: ctx_id == 2 +dce_rpc_bind :: uuid == e3514235-4b06-11d1-ab04-00c04fc2dcd2 +dce_rpc_bind_ack :: fid == 0 +dce_rpc_bind_ack :: sec_addr == \PIPE\drsuapi +dce_rpc_alter_context :: fid == 0 +dce_rpc_alter_context :: ctx_id == 0 +dce_rpc_alter_context :: uuid == e3514235-4b06-11d1-ab04-00c04fc2dcd2 +dce_rpc_alter_context_resp :: fid == 0 diff --git a/testing/btest/Traces/dce-rpc/cs_window7-join_stream092.pcap b/testing/btest/Traces/dce-rpc/cs_window7-join_stream092.pcap new file mode 100644 index 0000000000..c867e07e74 Binary files /dev/null and b/testing/btest/Traces/dce-rpc/cs_window7-join_stream092.pcap differ diff --git a/testing/btest/scripts/base/protocols/dce-rpc/context.bro b/testing/btest/scripts/base/protocols/dce-rpc/context.bro new file mode 100644 index 0000000000..cb0d93383b --- /dev/null +++ b/testing/btest/scripts/base/protocols/dce-rpc/context.bro @@ -0,0 +1,31 @@ +# @TEST-EXEC: bro -b -C -r $TRACES/dce-rpc/cs_window7-join_stream092.pcap %INPUT >out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff dce_rpc.log + +@load base/protocols/dce-rpc + +event dce_rpc_bind(c: connection, fid: count, ctx_id: count, uuid: string, ver_major: count, ver_minor: count) &priority=5 + { + print fmt("dce_rpc_bind :: fid == %s", fid); + print fmt("dce_rpc_bind :: ctx_id == %s", ctx_id); + print fmt("dce_rpc_bind :: uuid == %s", uuid_to_string(uuid)); + } + +event dce_rpc_alter_context(c: connection, fid: count, ctx_id: count, uuid: string, ver_major: count, ver_minor: count) &priority=5 + { + print fmt("dce_rpc_alter_context :: fid == %s", fid); + print fmt("dce_rpc_alter_context :: ctx_id == %s", ctx_id); + print fmt("dce_rpc_alter_context :: uuid == %s", uuid_to_string(uuid)); + } + + +event dce_rpc_bind_ack(c: connection, fid: count, sec_addr: string) &priority=5 + { + print fmt("dce_rpc_bind_ack :: fid == %s", fid); + print fmt("dce_rpc_bind_ack :: sec_addr == %s", sec_addr); + } + +event dce_rpc_alter_context_resp(c: connection, fid: count) &priority=5 + { + print fmt("dce_rpc_alter_context_resp :: fid == %s", fid); + }