Fixes for DCE_RPC analyzer

- DCE_RPC fragmentation handling returns!
  - Fixed some general parsing issues
  - Fixed an issue with the DCE_RPC signature not working for IPv6 connections.
This commit is contained in:
Seth Hall 2016-10-08 10:00:26 -04:00
parent 14c119c7f9
commit 029d92183e
7 changed files with 79 additions and 78 deletions

View file

@ -1,6 +1,5 @@
signature dpd_dce_rpc { signature dpd_dce_rpc {
ip-proto == tcp payload /\x05[\x00\x01][\x00-\x13]/
payload /^\x05[\x00\x01][\x00-\x13]\x03/
enable "DCE_RPC" enable "DCE_RPC"
} }

View file

@ -118,36 +118,6 @@ refine connection DCE_RPC_Conn += {
}; };
refine flow DCE_RPC_Flow += {
#%member{
#FlowBuffer frag_reassembler_;
#%}
# Fragment reassembly.
#function reassemble_fragment(frag: bytestring, lastfrag: bool): bool
# %{
# int orig_data_length = frag_reassembler_.data_length();
#
# frag_reassembler_.NewData(frag.begin(), frag.end());
#
# int new_frame_length = orig_data_length + frag.length();
# if ( orig_data_length == 0 )
# frag_reassembler_.NewFrame(new_frame_length, false);
# else
# frag_reassembler_.GrowFrame(new_frame_length);
#
# return lastfrag;
# %}
#function reassembled_body(): const_bytestring
# %{
# return const_bytestring(
# frag_reassembler_.begin(),
# frag_reassembler_.end());
# %}
};
refine typeattr DCE_RPC_PDU += &let { refine typeattr DCE_RPC_PDU += &let {
proc = $context.connection.proc_dce_rpc_pdu(this); proc = $context.connection.proc_dce_rpc_pdu(this);
} }

View file

@ -1,5 +1,7 @@
# Definitions for DCE RPC. # Definitions for DCE RPC.
enum dce_rpc_ptype { enum dce_rpc_ptype {
DCE_RPC_REQUEST, DCE_RPC_REQUEST,
DCE_RPC_PING, DCE_RPC_PING,
@ -30,19 +32,14 @@ type context_handle = record {
}; };
type DCE_RPC_PDU(is_orig: bool) = record { type DCE_RPC_PDU(is_orig: bool) = record {
# Set header's byteorder to little-endian (or big-endian) to
# avoid cyclic dependency.
header : DCE_RPC_Header(is_orig); header : DCE_RPC_Header(is_orig);
# TODO: bring back reassembly. It was having trouble. frag : bytestring &length=body_length;
#frag : bytestring &length = body_length;
body : DCE_RPC_Body(header);
auth : DCE_RPC_Auth_wrapper(header); auth : DCE_RPC_Auth_wrapper(header);
} &let { } &let {
#body_length : int = header.frag_length - sizeof(header) - header.auth_length; # Subtract an extra 8 when there is an auth section because we have some "auth header" fields in that structure.
#frag_reassembled : bool = $context.flow.reassemble_fragment(frag, header.lastfrag); body_length : int = header.frag_length - sizeof(header) - header.auth_length - (header.auth_length > 0 ? 8 : 0);
#body : DCE_RPC_Body(header) frag_reassembled : bool = $context.flow.reassemble_fragment(header, frag);
# withinput $context.flow.reassembled_body() body : DCE_RPC_Body(header) withinput $context.flow.reassembled_body(header, frag) &if(header.lastfrag);
# &if frag_reassembled;
} &byteorder = header.byteorder, &length = header.frag_length; } &byteorder = header.byteorder, &length = header.frag_length;
type NDR_Format = record { type NDR_Format = record {
@ -53,9 +50,6 @@ type NDR_Format = record {
byteorder = (intchar >> 4) ? littleendian : bigendian; byteorder = (intchar >> 4) ? littleendian : bigendian;
}; };
# There might be a endianness problem here: the frag_length
# causes problems despite the NDR_Format having a byteorder set.
type DCE_RPC_Header(is_orig: bool) = record { type DCE_RPC_Header(is_orig: bool) = record {
rpc_vers : uint8 &check(rpc_vers == 5); rpc_vers : uint8 &check(rpc_vers == 5);
rpc_vers_minor : uint8; rpc_vers_minor : uint8;
@ -66,8 +60,9 @@ type DCE_RPC_Header(is_orig: bool) = record {
auth_length : uint16; auth_length : uint16;
call_id : uint32; call_id : uint32;
} &let { } &let {
frag = pfc_flags & 4; firstfrag = pfc_flags & 1;
lastfrag = (! frag) || (pfc_flags & 2); lastfrag = (pfc_flags >> 1) & 1;
object = (pfc_flags >> 7) & 1;
} &byteorder = packed_drep.byteorder; } &byteorder = packed_drep.byteorder;
type Syntax = record { type Syntax = record {
@ -116,12 +111,15 @@ type DCE_RPC_Bind_Ack = record {
contexts : ContextList(0); contexts : ContextList(0);
}; };
type DCE_RPC_Request = record { type DCE_RPC_Request(h: DCE_RPC_Header) = record {
alloc_hint : uint32; alloc_hint : uint32;
context_id : uint16; context_id : uint16;
opnum : uint16; opnum : uint16;
# object : uuid; has_object : case h.object of {
# stub_pad_0 : padding align 8; true -> uuid : uuid;
false -> no_uuid : empty;
};
stub_pad : padding align 8;
stub : bytestring &restofdata; stub : bytestring &restofdata;
}; };
@ -130,7 +128,7 @@ type DCE_RPC_Response = record {
context_id : uint16; context_id : uint16;
cancel_count : uint8; cancel_count : uint8;
reserved : uint8; reserved : uint8;
# stub_pad_0 : padding align 8; stub_pad : padding align 8;
stub : bytestring &restofdata; stub : bytestring &restofdata;
}; };
@ -152,13 +150,13 @@ type DCE_RPC_AlterContext_Resp = record {
type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of { type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of {
DCE_RPC_BIND -> bind : DCE_RPC_Bind; DCE_RPC_BIND -> bind : DCE_RPC_Bind;
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; 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. # 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;
} &length=header.frag_length - 16 - header.auth_length - (header.auth_length==0 ? 0 : 8); };
type DCE_RPC_Auth_wrapper(header: DCE_RPC_Header) = case header.auth_length of { type DCE_RPC_Auth_wrapper(header: DCE_RPC_Header) = case header.auth_length of {
0 -> none : empty; 0 -> none : empty;
@ -173,3 +171,41 @@ type DCE_RPC_Auth(header: DCE_RPC_Header) = record {
context_id : uint32; context_id : uint32;
blob : bytestring &length=header.auth_length; blob : bytestring &length=header.auth_length;
}; };
flow DCE_RPC_Flow(is_orig: bool) {
flowunit = DCE_RPC_PDU(is_orig) withcontext(connection, this);
%member{
std::map<uint32, FlowBuffer*> fb;
%}
# Fragment reassembly.
function reassemble_fragment(header: DCE_RPC_Header, frag: bytestring): bool
%{
if ( ${header.firstfrag} && !${header.lastfrag} &&
fb.count(${header.call_id}) == 0 )
fb[${header.call_id}] = new FlowBuffer();
if ( fb.count(${header.call_id}) == 0 )
return false;
auto frag_reassembler_ = fb[${header.call_id}];
frag_reassembler_->BufferData(frag.begin(), frag.end());
return (!${header.firstfrag} && ${header.lastfrag});
%}
function reassembled_body(h: DCE_RPC_Header, body: bytestring): const_bytestring
%{
const_bytestring bd = body;
if ( fb.count(${h.call_id}) > 0 )
{
bd = const_bytestring(fb[${h.call_id}]->begin(), fb[${h.call_id}]->end());
delete fb[${h.call_id}];
fb.erase(${h.call_id});
}
return bd;
%}
};

View file

@ -15,12 +15,8 @@ connection DCE_RPC_Conn(bro_analyzer: BroAnalyzer) {
upflow = DCE_RPC_Flow(true); upflow = DCE_RPC_Flow(true);
downflow = DCE_RPC_Flow(false); downflow = DCE_RPC_Flow(false);
}; };
%include dce_rpc-protocol.pac
# Now we define the flow: %include dce_rpc-protocol.pac
flow DCE_RPC_Flow(is_orig: bool) {
flowunit = DCE_RPC_PDU(is_orig) withcontext(connection, this);
};
%include endpoint-atsvc.pac %include endpoint-atsvc.pac
%include endpoint-epmapper.pac %include endpoint-epmapper.pac

View file

@ -3,19 +3,19 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path dce_rpc #path dce_rpc
#open 2016-08-08-20-13-23 #open 2016-10-08-03-48-34
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p rtt named_pipe endpoint operation #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 #types time string addr port addr port interval string string string
1056991898.891148 C4J4Th3PJpwUYZZ6gc 192.168.0.173 1066 192.168.0.2 135 0.000375 135 epmapper ept_map 1056991898.891148 CmES5u32sYpV7JYN 192.168.0.173 1066 192.168.0.2 135 0.000375 135 epmapper ept_map
1056991898.895146 CtPZjS20MLrsMUOJi2 192.168.0.173 1067 192.168.0.2 4997 0.000749 4997 nspi NspiBind 1056991898.895146 CP5puj4I8PtEU4qzYg 192.168.0.173 1067 192.168.0.2 4997 0.000749 4997 nspi NspiBind
1056991898.902393 CUM0KZ3MLUfNB0cl11 192.168.0.173 1068 192.168.0.2 4997 0.026606 4997 nspi NspiBind 1056991898.902393 C37jN32gN3y3AZzyf6 192.168.0.173 1068 192.168.0.2 4997 0.026606 4997 nspi NspiBind
1056991898.931248 CmES5u32sYpV7JYN 192.168.0.173 1069 192.168.0.2 135 0.000500 135 epmapper ept_lookup 1056991898.931248 C3eiCBGOLw3VtHfOj 192.168.0.173 1069 192.168.0.2 135 0.000500 135 epmapper ept_lookup
1056991899.586840 CP5puj4I8PtEU4qzYg 192.168.0.173 1072 192.168.0.2 135 0.000374 135 epmapper ept_map 1056991899.586840 C0LAHyvtKSQHyJxIl 192.168.0.173 1072 192.168.0.2 135 0.000374 135 epmapper ept_map
1056991899.594336 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.031980 1032 exchange_mapi EcDoConnect 1056991899.594336 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.031980 1032 exchange_mapi EcDoConnect
1056991899.626566 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.024359 1032 exchange_mapi EcDoRpc 1056991899.626566 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.024359 1032 exchange_mapi EcDoRpc
1056991899.652798 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.001374 1032 exchange_mapi EcDoRpc 1056991899.652798 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.001374 1032 exchange_mapi EcDoRpc
1056991899.655922 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.000999 1032 exchange_mapi EcDoRpc 1056991899.655922 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.000999 1032 exchange_mapi EcDoRpc
1056991899.658670 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.001624 1032 exchange_mapi EcDoRpc 1056991899.658670 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.001624 1032 exchange_mapi EcDoRpc
1056991899.660794 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.003998 1032 exchange_mapi EcRRegisterPushNotification 1056991899.660794 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.003998 1032 exchange_mapi EcRRegisterPushNotification
1056991899.707516 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 0.003998 1032 exchange_mapi EcRRegisterPushNotification 1056991899.707516 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 0.003998 1032 exchange_mapi EcRRegisterPushNotification
#close 2016-08-08-20-13-23 #close 2016-10-08-03-48-34

View file

@ -3,9 +3,9 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path ntlm #path ntlm
#open 2016-08-08-20-13-23 #open 2016-10-08-03-48-34
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p username hostname domainname success status #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p username hostname domainname success status
#types time string addr port addr port string string string bool string #types time string addr port addr port string string string bool string
1056991898.902392 CUM0KZ3MLUfNB0cl11 192.168.0.173 1068 192.168.0.2 4997 ALeonard ALEONARD-XP CNAMIS - - 1056991898.902392 C37jN32gN3y3AZzyf6 192.168.0.173 1068 192.168.0.2 4997 ALeonard ALEONARD-XP CNAMIS - -
1056991899.594334 C37jN32gN3y3AZzyf6 192.168.0.173 1073 192.168.0.2 1032 ALeonard ALEONARD-XP CNAMIS - - 1056991899.594334 CFLRIC3zaTU1loLGxh 192.168.0.173 1073 192.168.0.2 1032 ALeonard ALEONARD-XP CNAMIS - -
#close 2016-08-08-20-13-23 #close 2016-10-08-03-48-34