diff --git a/rust/src/dcerpc/dcerpc.rs b/rust/src/dcerpc/dcerpc.rs index 5d71f7d254..b61b83ec42 100644 --- a/rust/src/dcerpc/dcerpc.rs +++ b/rust/src/dcerpc/dcerpc.rs @@ -263,6 +263,8 @@ pub struct DCERPCUuidEntry { pub version: u16, pub versionminor: u16, pub flags: u16, + pub call_id: u32, + pub acked: bool, } impl DCERPCUuidEntry { @@ -325,8 +327,7 @@ pub struct DCERPCBindAck { #[derive(Default, Debug)] pub struct DCERPCState { - pub bind: Option, - pub bindack: Option, + pub interface_uuids: Vec, pub transactions: VecDeque, tx_index_completed: usize, pub pad: u8, @@ -539,6 +540,7 @@ impl DCERPCState { let mut uuidentry = DCERPCUuidEntry::new(); uuidentry.uuid = ctxitem.uuid; uuidentry.internal_id = uuid_internal_id; + uuidentry.call_id = hdr.call_id; uuidentry.ctxid = ctxitem.ctxid; uuidentry.version = ctxitem.version; uuidentry.versionminor = ctxitem.versionminor; @@ -548,9 +550,15 @@ impl DCERPCState { if pfcflags & PFC_FIRST_FRAG > 0 { uuidentry.flags |= DCERPC_UUID_ENTRY_FLAG_FF; } - if let Some(ref mut bind) = self.bind { - SCLogDebug!("DCERPC BIND CtxItem: Pushing uuid: {:?}", uuidentry); - bind.uuid_list.push(uuidentry); + for uuid in self.interface_uuids.iter_mut() { + if uuid.ctxid == uuidentry.ctxid { + *uuid = uuidentry; + return (input.len() - leftover_bytes.len()) as i32; + } + } + // arbitrary bound + if self.interface_uuids.len() < 64 { + self.interface_uuids.push(uuidentry); } (input.len() - leftover_bytes.len()) as i32 } @@ -573,7 +581,6 @@ impl DCERPCState { match parser::parse_dcerpc_bind(input) { Ok((leftover_bytes, header)) => { let numctxitems = header.numctxitems; - self.bind = Some(header); for i in 0..numctxitems { retval = self.handle_bindctxitem(&input[idx as usize..], i as u16, hdr); if retval == -1 { @@ -610,23 +617,19 @@ impl DCERPCState { } } - pub fn process_bindack_pdu(&mut self, input: &[u8]) -> i32 { + pub fn process_bindack_pdu(&mut self, input: &[u8], call_id: u32) -> i32 { match parser::parse_dcerpc_bindack(input) { - Ok((leftover_bytes, mut back)) => { - if let Some(ref mut bind) = self.bind { - for (uuid_internal_id, r) in back.ctxitems.iter().enumerate() { - for uuid in bind.uuid_list.iter_mut() { - if uuid.internal_id == uuid_internal_id as u16 { - uuid.result = r.ack_result; - if uuid.result != 0 { - break; - } - back.accepted_uuid_list.push(uuid.clone()); + Ok((leftover_bytes, back)) => { + for (uuid_internal_id, r) in back.ctxitems.iter().enumerate() { + for uuid in self.interface_uuids.iter_mut().rev() { + if uuid.internal_id == uuid_internal_id as u16 && uuid.call_id == call_id{ + uuid.result = r.ack_result; + uuid.acked = true; + if uuid.result == 0 { SCLogDebug!("DCERPC BINDACK accepted UUID: {:?}", uuid); } } } - self.bindack = Some(back); } (input.len() - leftover_bytes.len()) as i32 } @@ -942,7 +945,7 @@ impl DCERPCState { } DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => { let retval = - self.process_bindack_pdu(&cur_i[parsed as usize..fraglen as usize]); + self.process_bindack_pdu(&cur_i[parsed as usize..fraglen as usize], hdr.call_id); if retval == -1 { return AppLayerResult::err(); } @@ -1566,14 +1569,20 @@ mod tests { let mut dcerpc_state = DCERPCState::new(); let hdr = parser::parse_dcerpc_header(bind).unwrap().1; assert_eq!(1068, dcerpc_state.process_bind_pdu(&bind[16..], &hdr)); - assert_eq!(604, dcerpc_state.process_bindack_pdu(bindack)); - if let Some(back) = dcerpc_state.bindack { - assert_eq!(1, back.accepted_uuid_list.len()); - assert_eq!( - vec!(57, 25, 40, 106, 177, 12, 17, 208, 155, 168, 0, 192, 79, 217, 46, 245), - back.accepted_uuid_list[0].uuid - ); - assert_eq!(11, back.accepted_uuid_list[0].internal_id); + assert_eq!(604, dcerpc_state.process_bindack_pdu(bindack, hdr.call_id)); + assert_eq!(24, dcerpc_state.interface_uuids.len()); + for i in 0..24 { + assert!(dcerpc_state.interface_uuids[i].acked); + if i == 11 { + assert_eq!( + vec!(57, 25, 40, 106, 177, 12, 17, 208, 155, 168, 0, 192, 79, 217, 46, 245), + dcerpc_state.interface_uuids[11].uuid + ); + assert_eq!(11, dcerpc_state.interface_uuids[11].internal_id); + assert_eq!(0, dcerpc_state.interface_uuids[11].result); + } else { + assert_ne!(0, dcerpc_state.interface_uuids[i].result); + } } } @@ -1813,19 +1822,17 @@ mod tests { Direction::ToServer ) ); - if let Some(ref bind) = dcerpc_state.bind { - let bind_uuid = &bind.uuid_list[0].uuid; - assert_eq!(1, bind.uuid_list.len()); - assert_eq!( - cmp::Ordering::Equal, - bind_uuid - .iter() - .zip(expected_uuid) - .map(|(x, y)| x.cmp(y)) - .find(|&ord| ord != cmp::Ordering::Equal) - .unwrap_or_else(|| bind_uuid.len().cmp(&expected_uuid.len())) - ); - } + assert_eq!(1, dcerpc_state.interface_uuids.len()); + let bind_uuid = &dcerpc_state.interface_uuids[0].uuid; + assert_eq!( + cmp::Ordering::Equal, + bind_uuid + .iter() + .zip(expected_uuid) + .map(|(x, y)| x.cmp(y)) + .find(|&ord| ord != cmp::Ordering::Equal) + .unwrap_or_else(|| bind_uuid.len().cmp(&expected_uuid.len())) + ); } #[test] @@ -2087,11 +2094,9 @@ mod tests { Direction::ToServer ) ); - if let Some(ref back) = dcerpc_state.bindack { - assert_eq!(1, back.accepted_uuid_list.len()); - assert_eq!(12, back.accepted_uuid_list[0].ctxid); - assert_eq!(expected_uuid1, back.accepted_uuid_list[0].uuid); - } + assert_eq!(13, dcerpc_state.interface_uuids.len()); + assert_eq!(12, dcerpc_state.interface_uuids[12].ctxid); + assert_eq!(expected_uuid1, dcerpc_state.interface_uuids[12].uuid); assert_eq!( AppLayerResult::ok(), dcerpc_state.handle_input_data( @@ -2106,11 +2111,9 @@ mod tests { Direction::ToServer ) ); - if let Some(ref back) = dcerpc_state.bindack { - assert_eq!(1, back.accepted_uuid_list.len()); - assert_eq!(15, back.accepted_uuid_list[0].ctxid); - assert_eq!(expected_uuid2, back.accepted_uuid_list[0].uuid); - } + assert_eq!(16, dcerpc_state.interface_uuids.len()); + assert_eq!(15, dcerpc_state.interface_uuids[15].ctxid); + assert_eq!(expected_uuid2, dcerpc_state.interface_uuids[15].uuid); assert_eq!( AppLayerResult::ok(), dcerpc_state.handle_input_data( @@ -2125,11 +2128,9 @@ mod tests { Direction::ToServer ) ); - if let Some(ref back) = dcerpc_state.bindack { - assert_eq!(1, back.accepted_uuid_list.len()); - assert_eq!(11, back.accepted_uuid_list[0].ctxid); - assert_eq!(expected_uuid3, back.accepted_uuid_list[0].uuid); - } + assert_eq!(16, dcerpc_state.interface_uuids.len()); + assert_eq!(11, dcerpc_state.interface_uuids[11].ctxid); + assert_eq!(expected_uuid3, dcerpc_state.interface_uuids[11].uuid); } #[test] @@ -2187,11 +2188,9 @@ mod tests { Direction::ToServer ) ); - if let Some(ref back) = dcerpc_state.bindack { - assert_eq!(1, back.accepted_uuid_list.len()); - assert_eq!(0, back.accepted_uuid_list[0].ctxid); - assert_eq!(expected_uuid1, back.accepted_uuid_list[0].uuid); - } + assert_eq!(1, dcerpc_state.interface_uuids.len()); + assert_eq!(0, dcerpc_state.interface_uuids[0].ctxid); + assert_eq!(expected_uuid1, dcerpc_state.interface_uuids[0].uuid); assert_eq!( AppLayerResult::ok(), dcerpc_state.handle_input_data( @@ -2206,10 +2205,8 @@ mod tests { Direction::ToServer ) ); - if let Some(ref back) = dcerpc_state.bindack { - assert_eq!(1, back.accepted_uuid_list.len()); - assert_eq!(1, back.accepted_uuid_list[0].ctxid); - assert_eq!(expected_uuid2, back.accepted_uuid_list[0].uuid); - } + assert_eq!(2, dcerpc_state.interface_uuids.len()); + assert_eq!(1, dcerpc_state.interface_uuids[1].ctxid); + assert_eq!(expected_uuid2, dcerpc_state.interface_uuids[1].uuid); } } diff --git a/rust/src/dcerpc/detect.rs b/rust/src/dcerpc/detect.rs index 29fe4b9255..7599adc89b 100644 --- a/rust/src/dcerpc/detect.rs +++ b/rust/src/dcerpc/detect.rs @@ -63,8 +63,8 @@ fn match_backuuid( tx: &DCERPCTransaction, state: &mut DCERPCState, if_data: &mut DCEIfaceData, ) -> u8 { let mut ret = 0; - if let Some(ref bindack) = state.bindack { - for uuidentry in bindack.accepted_uuid_list.iter() { + if !state.interface_uuids.is_empty() { + for uuidentry in &state.interface_uuids { ret = 1; // if any_frag is not enabled, we need to match only against the first fragment if if_data.any_frag == 0 && (uuidentry.flags & DCERPC_UUID_ENTRY_FLAG_FF == 0) { @@ -72,7 +72,8 @@ fn match_backuuid( continue; } // if the uuid has been rejected(uuidentry->result == 1), we skip to the next uuid - if uuidentry.result != 0 { + if !uuidentry.acked || uuidentry.result != 0 { + ret = 0; SCLogDebug!("Skipping to next UUID"); continue; } diff --git a/rust/src/dcerpc/log.rs b/rust/src/dcerpc/log.rs index 9c94944d12..5a00bdf8df 100644 --- a/rust/src/dcerpc/log.rs +++ b/rust/src/dcerpc/log.rs @@ -21,16 +21,19 @@ use crate::dcerpc::dcerpc_udp::*; use crate::jsonbuilder::{JsonBuilder, JsonError}; fn log_bind_interfaces(jsb: &mut JsonBuilder, state: &DCERPCState) -> Result<(), JsonError> { - if let Some(bind) = &state.bind { + if !state.interface_uuids.is_empty() { jsb.open_array("interfaces")?; - for uuid in &bind.uuid_list { + for uuid in &state.interface_uuids { jsb.start_object()?; let ifstr = Uuid::from_slice(uuid.uuid.as_slice()); let ifstr = ifstr.map(|uuid| uuid.to_hyphenated().to_string()).unwrap(); jsb.set_string("uuid", &ifstr)?; let vstr = format!("{}.{}", uuid.version, uuid.versionminor); jsb.set_string("version", &vstr)?; - jsb.set_uint("ack_result", uuid.result as u64)?; + // TODO? log only the interface for the right ctxid jsb.set_uint("ctxid", uuid.ctxid as u64)?; + if uuid.acked { + jsb.set_uint("ack_result", uuid.result as u64)?; + } jsb.close()?; } jsb.close()?;