Fix tracking of DCE-RPC context identifier mappings

This adds previously-missing support for "Alter Context"
request/response PDUs (initial patch contributed by Mark Fernandez).

Also, context ID arguments were added to dce_rpc_bind, dce_rpc_request,
and dce_rpc_response in order to properly track what endpoint/operation
a given opnum maps to.
This commit is contained in:
Jon Siwek 2018-08-23 15:11:38 -05:00
parent 45338b1942
commit 620cd671ba
9 changed files with 210 additions and 27 deletions

13
NEWS
View file

@ -434,6 +434,19 @@ Changed Functionality
and the original weird.log may not differ much either, except in and the original weird.log may not differ much either, except in
the cases where a particular weird type exceeds the sampling threshold. 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 Removed Functionality
--------------------- ---------------------

View file

@ -37,6 +37,7 @@ export {
type State: record { type State: record {
uuid : string &optional; uuid : string &optional;
named_pipe : string &optional; named_pipe : string &optional;
ctx_to_uuid: table[count] of string &optional;
}; };
# This is to store the log and state information # 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); 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); set_session(c, fid);
local uuid_str = uuid_to_string(uuid); 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_state$uuid = uuid_str;
c$dce_rpc$endpoint = uuid_endpoint_map[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); 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); 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 )
{
if ( c$dce_rpc?$endpoint )
{ {
c$dce_rpc$operation = operations[c$dce_rpc_state$uuid, opnum]; c$dce_rpc$operation = operations[c$dce_rpc_state$uuid, opnum];
if ( c$dce_rpc$ts != network_time() ) if ( c$dce_rpc$ts != network_time() )
c$dce_rpc$rtt = network_time() - c$dce_rpc$ts; 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 ) if ( c?$dce_rpc )
{ {

View file

@ -54,6 +54,23 @@ refine connection DCE_RPC_Conn += {
BifEvent::generate_dce_rpc_bind(bro_analyzer(), BifEvent::generate_dce_rpc_bind(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
fid, 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_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}), bytestring_to_val(${req.abstract_syntax.uuid}),
${req.abstract_syntax.ver_major}, ${req.abstract_syntax.ver_major},
${req.abstract_syntax.ver_minor}); ${req.abstract_syntax.ver_minor});
@ -86,6 +103,17 @@ refine connection DCE_RPC_Conn += {
return true; 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 function process_dce_rpc_request(req: DCE_RPC_Request): bool
%{ %{
if ( dce_rpc_request ) if ( dce_rpc_request )
@ -93,6 +121,7 @@ refine connection DCE_RPC_Conn += {
BifEvent::generate_dce_rpc_request(bro_analyzer(), BifEvent::generate_dce_rpc_request(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
fid, fid,
${req.context_id},
${req.opnum}, ${req.opnum},
${req.stub}.length()); ${req.stub}.length());
} }
@ -109,6 +138,7 @@ refine connection DCE_RPC_Conn += {
BifEvent::generate_dce_rpc_response(bro_analyzer(), BifEvent::generate_dce_rpc_response(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),
fid, fid,
${resp.context_id},
get_cont_id_opnum_map(${resp.context_id}), get_cont_id_opnum_map(${resp.context_id}),
${resp.stub}.length()); ${resp.stub}.length());
} }
@ -127,13 +157,20 @@ refine typeattr DCE_RPC_Header += &let {
}; };
refine typeattr ContextRequest += &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 { refine typeattr DCE_RPC_Bind_Ack += &let {
proc = $context.connection.process_dce_rpc_bind_ack(this); 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 { refine typeattr DCE_RPC_Request += &let {
proc = $context.connection.process_dce_rpc_request(this); proc = $context.connection.process_dce_rpc_request(this);
}; };

View file

@ -71,7 +71,7 @@ type Syntax = record {
ver_minor : uint16; ver_minor : uint16;
}; };
type ContextRequest = record { type ContextRequest(ptype: uint8) = record {
id : uint16; id : uint16;
num_syntaxes : uint8; num_syntaxes : uint8;
reserved : padding[1]; reserved : padding[1];
@ -85,11 +85,11 @@ type ContextReply = record {
syntax : Syntax; syntax : Syntax;
}; };
type ContextList(is_request: bool) = record { type ContextList(is_request: bool, ptype: uint8) = record {
num_contexts : uint8; num_contexts : uint8;
reserved : padding[3]; reserved : padding[3];
req_reply : case is_request of { 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]; false -> reply_contexts : ContextReply[num_contexts];
}; };
}; };
@ -98,7 +98,7 @@ type DCE_RPC_Bind = record {
max_xmit_frag : uint16; max_xmit_frag : uint16;
max_recv_frag : uint16; max_recv_frag : uint16;
assoc_group_id : uint32; assoc_group_id : uint32;
context_list : ContextList(1); context_list : ContextList(1, DCE_RPC_BIND);
}; };
type DCE_RPC_Bind_Ack = record { type DCE_RPC_Bind_Ack = record {
@ -108,7 +108,7 @@ type DCE_RPC_Bind_Ack = record {
sec_addr_length : uint16; sec_addr_length : uint16;
sec_addr : bytestring &length=sec_addr_length; sec_addr : bytestring &length=sec_addr_length;
pad : padding align 4; pad : padding align 4;
contexts : ContextList(0); contexts : ContextList(0, DCE_RPC_BIND_ACK);
}; };
type DCE_RPC_Request(h: DCE_RPC_Header) = record { type DCE_RPC_Request(h: DCE_RPC_Header) = record {
@ -136,15 +136,17 @@ type DCE_RPC_AlterContext = record {
max_xmit_frag : uint16; max_xmit_frag : uint16;
max_recv_frag : uint16; max_recv_frag : uint16;
assoc_group_id : uint32; assoc_group_id : uint32;
contexts : ContextList(0); context_list : ContextList(1, DCE_RPC_ALTER_CONTEXT);
}; };
type DCE_RPC_AlterContext_Resp = record { type DCE_RPC_AlterContext_Resp = record {
max_xmit_frag : uint16; max_xmit_frag : uint16;
max_recv_frag : uint16; max_recv_frag : uint16;
assoc_group_id : uint32; assoc_group_id : uint32;
sec_addr_len : uint16; sec_addr_length : uint16;
contexts : ContextList(0); 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 { 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_BIND_ACK -> bind_ack : DCE_RPC_Bind_Ack;
DCE_RPC_REQUEST -> request : DCE_RPC_Request(header); DCE_RPC_REQUEST -> request : DCE_RPC_Request(header);
DCE_RPC_RESPONSE -> response : DCE_RPC_Response; 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 -> alter_context : DCE_RPC_AlterContext; DCE_RPC_ALTER_CONTEXT_RESP -> alter_resp : DCE_RPC_AlterContext_Resp;
#DCE_RPC_ALTER_CONTEXT_RESP -> alter_resp : DCE_RPC_AlterContext_Resp;
default -> other : bytestring &restofdata; default -> other : bytestring &restofdata;
}; };

View file

@ -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 ## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was
## not transported over a pipe. ## not transported over a pipe.
## ##
## ctx_id: The context identifier of the data representation.
##
## uuid: The string interpretted uuid of the endpoint being requested. ## uuid: The string interpretted uuid of the endpoint being requested.
## ##
## ver_major: The major version 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. ## 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 ## .. 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. ## 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 ## .. 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%); 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. ## Generated for every :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` request message.
## ##
## c: The connection. ## 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 ## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was
## not transported over a pipe. ## not transported over a pipe.
## ##
## ctx_id: The context identifier of the data representation.
##
## opnum: Number of the RPC operation. ## opnum: Number of the RPC operation.
## ##
## stub_len: Length of the data for the request. ## stub_len: Length of the data for the request.
## ##
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_response ## .. 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. ## 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 ## message. Zero will be used if the :abbr:`DCE-RPC (Distributed Computing Environment/Remote Procedure Calls)` was
## not transported over a pipe. ## not transported over a pipe.
## ##
## ctx_id: The context identifier of the data representation.
###
## opnum: Number of the RPC operation. ## opnum: Number of the RPC operation.
## ##
## stub_len: Length of the data for the response. ## stub_len: Length of the data for the response.
## ##
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request ## .. 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%);

View file

@ -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

View file

@ -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

View file

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