The bug:
The dcerpc dce_iface keyword just match the packet following the bind. Only the
next request after the rpc is sent will match. However the expected behaviour it
that all the rpc requests/responses sent under the context of the given
interface would match.
In the Open Group c706 the following is indicated:
In 2.2.1 Binding-related Operations, indicates that one category of binding
operations are those that "operations that establish internal call routing
information for the server." (The other are to establish the protocol which is
not relevant here). And the following statement can be found:
Operations in the second category establish a set of mappings that the server
can use to route calls internally to the appropriate manager routine. This
routing is based on the interface and version, operation and any object
requested by the call.
It indicates that server routes (to call methods) are based on the operation,
interface and object.
- Operation: To indicate the method to call, and operation number is
specified as indicated in the second step of 2.3.3.2 (Client
Binding Steps).
- Interface: An interface is a set of remotely callable operations offered by a
server and invokable by clients. (2.1.1.1)
- Object: Is the manager that implements the interface, as stated in section
Interface and Manager Selection of 2.3.3.3. It is not mandatory, can
be nil.
To call a method, a client must send a request message as defined in 2.6.4.9,
that contains these identifiers:
- opnum: The opnum field identifies the operation being invoked within the
interface.
- p_cont_id (Context ID in Wireshark): The p_cont_id field holds a presentation
context identifier that identifies the
data representation and interface, as
defined in 12.6.3.4 (Context Identifiers).
- object: The object field is contained if the PFC_OBJECT_UUID is set. (Could be
interesting to create a keyword dce_object for matching this UUID)
Therefore, to get the correct method to invoke, the server must map the context
to the correct interface. This is negotiated by the bind request
Interfaces are first negotiated using the bind message (12.6.4.3), contained in
the p_context_elem array. Then they are accepted or rejected using the bind_ack
message (12.6.4.4).
Once these contexts are established, both client and server can use the context
id, which is the index of the p_context_elem array, to refer the interface they
are using.
Moreover, in the middle of the connection, the context can be changed with the
alter_context message.
This is way suricata shouldn't delete the bindack attribute, that contains
the contexts, used by match_backuuid. This is the only way to know the interface
a request message is referring to.
ticket: 4769
https://redmine.openinfosecfoundation.org/issues/4769
(cherry picked from commit
1aca2676a6965056582c3da85e4bb2058aca43b0)
None
}
- pub fn handle_bind_cache(&mut self, call_id: u32, is_response: bool) {
- if self.clear_bind_cache == true {
- self.bind = None;
- self.bindack = None;
- }
- if self.prev_tx_call_id == call_id && is_response == true {
- self.clear_bind_cache = true;
- } else {
- self.clear_bind_cache = false;
- }
- self.prev_tx_call_id = call_id;
- }
-
pub fn parse_data_gap(&mut self, direction: u8) -> AppLayerResult {
match direction {
core::STREAM_TOSERVER => {
if retval == -1 {
return AppLayerResult::err();
}
- self.handle_bind_cache(current_call_id, false);
}
DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => {
retval = self.process_bindack_pdu(&buffer[parsed as usize..]);
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOCLIENT.into());
}
- self.handle_bind_cache(current_call_id, false);
}
DCERPC_TYPE_REQUEST => {
retval = self.process_request_pdu(&buffer[parsed as usize..]);
}
// In case the response came first, the transaction would complete later when
// the corresponding request also comes through
- self.handle_bind_cache(current_call_id, false);
}
DCERPC_TYPE_RESPONSE => {
let transaction = self.get_tx_by_call_id(current_call_id, core::STREAM_TOCLIENT);
if retval < 0 {
return AppLayerResult::err();
}
- self.handle_bind_cache(current_call_id, true);
}
_ => {
SCLogDebug!("Unrecognized packet type: {:?}", x);