Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 75 additions & 98 deletions rust/src/dcerpc/dcerpc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2020-2024 Open Information Security Foundation
/* Copyright (C) 2020-2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
Expand Down Expand Up @@ -558,6 +558,7 @@ impl DCERPCState {
for i in 0..numctxitems {
retval = self.handle_bindctxitem(&input[idx as usize..], i as u16, hdr);
if retval == -1 {
SCLogDebug!("Error handling BindCtxItem");
return -1;
}
idx += retval;
Expand Down Expand Up @@ -765,6 +766,7 @@ impl DCERPCState {
let retval;
let mut cur_i = stream_slice.as_slice();
let mut consumed = 0u32;
let mut rem = cur_i.len() as u32;

// Skip the record since this means that its in the middle of a known length record
if (self.ts_gap && direction == Direction::ToServer) || (self.tc_gap && direction == Direction::ToClient) {
Expand Down Expand Up @@ -797,6 +799,7 @@ impl DCERPCState {
},
}
}
rem -= consumed;

let mut flow = std::ptr::null_mut();
if let Some(f) = self.flow {
Expand Down Expand Up @@ -835,82 +838,96 @@ impl DCERPCState {
};
let parsed = DCERPC_HDR_LEN;
let fraglen = hdr.frag_length;
match fraglen.cmp(&parsed) {
cmp::Ordering::Less => {
// fragment length should at least be header length
SCLogDebug!("Erroneous fragment length");
return AppLayerResult::err();
},
cmp::Ordering::Equal => {
// input only consists of the header and that was consumed, so, return early
return AppLayerResult::ok();
}
cmp::Ordering::Greater => {}
}

if cur_i.len() < fraglen as usize {
// rem == bytes consumed to move past gap; so those were not a part of the fragment
if rem < fraglen as u32 {
SCLogDebug!("Possibly fragmented data, waiting for more..");
return AppLayerResult::incomplete(consumed, fraglen.into());
}

let hdrtype = hdr.hdrtype;

let _hdr = Frame::new(flow, &stream_slice, cur_i, parsed as i64, DCERPCFrameType::Hdr as u8, None);
let _pdu = Frame::new(flow, &stream_slice, cur_i, fraglen as i64, DCERPCFrameType::Pdu as u8, None);
if fraglen >= DCERPC_HDR_LEN && cur_i.len() > DCERPC_HDR_LEN as usize {
let _data = Frame::new(flow, &stream_slice, &cur_i[DCERPC_HDR_LEN as usize..], (fraglen - DCERPC_HDR_LEN) as i64, DCERPCFrameType::Data as u8, None);
let _hdr = Frame::new(flow, &stream_slice, &cur_i[consumed as usize..], DCERPC_HDR_LEN as i64, DCERPCFrameType::Hdr as u8, None);
let _pdu = Frame::new(flow, &stream_slice, &cur_i[consumed as usize..], fraglen as i64, DCERPCFrameType::Pdu as u8, None);
if fraglen >= DCERPC_HDR_LEN && rem > DCERPC_HDR_LEN as u32 {
let _data = Frame::new(flow, &stream_slice, &cur_i[(consumed + DCERPC_HDR_LEN as u32) as usize..], (fraglen - DCERPC_HDR_LEN) as i64, DCERPCFrameType::Data as u8, None);
}
let current_call_id = hdr.call_id;

debug_validate_bug_on!(parsed > fraglen);
match hdrtype {
DCERPC_TYPE_BIND | DCERPC_TYPE_ALTER_CONTEXT => {
retval = self.process_bind_pdu(&cur_i[parsed as usize..], &hdr);
if retval == -1 {
return AppLayerResult::err();
}
DCERPC_TYPE_BIND | DCERPC_TYPE_ALTER_CONTEXT => {
retval = self.process_bind_pdu(&cur_i[parsed as usize..fraglen as usize], &hdr);
if retval == -1 {
return AppLayerResult::err();
}
DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => {
retval = self.process_bindack_pdu(&cur_i[parsed as usize..]);
if retval == -1 {
return AppLayerResult::err();
}
let tx = if let Some(tx) = self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype) {
}
DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => {
retval = self.process_bindack_pdu(&cur_i[parsed as usize..fraglen as usize]);
if retval == -1 {
return AppLayerResult::err();
}
let tx = if let Some(tx) = self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype) {
tx.resp_cmd = hdrtype;
tx
} else {
let mut tx = self.create_tx(&hdr);
tx.resp_cmd = hdrtype;
self.transactions.push_back(tx);
self.transactions.back_mut().unwrap()
};
tx.resp_done = true;
tx.frag_cnt_tc = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_inspection(flow, Direction::ToClient as i32);
}
}
DCERPC_TYPE_REQUEST => {
retval = self.process_request_pdu(&cur_i[parsed as usize..fraglen as usize], &hdr);
if retval < 0 {
return AppLayerResult::err();
}
// In case the response came first, the transaction would complete later when
// the corresponding request also comes through
}
DCERPC_TYPE_RESPONSE => {
let transaction = self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype);
match transaction {
Some(tx) => {
tx.resp_cmd = hdrtype;
tx
} else {
}
None => {
let mut tx = self.create_tx(&hdr);
tx.resp_cmd = hdrtype;
self.transactions.push_back(tx);
self.transactions.back_mut().unwrap()
};
tx.resp_done = true;
tx.frag_cnt_tc = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_inspection(flow, Direction::ToClient as i32);
}
}
DCERPC_TYPE_REQUEST => {
retval = self.process_request_pdu(&cur_i[parsed as usize..], &hdr);
if retval < 0 {
return AppLayerResult::err();
}
// In case the response came first, the transaction would complete later when
// the corresponding request also comes through
}
DCERPC_TYPE_RESPONSE => {
let transaction = self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype);
match transaction {
Some(tx) => {
tx.resp_cmd = hdrtype;
}
None => {
let mut tx = self.create_tx(&hdr);
tx.resp_cmd = hdrtype;
self.transactions.push_back(tx);
}
};
retval = self.handle_common_stub(
&cur_i[parsed as usize..],
0,
Direction::ToClient,
&hdr,
);
if retval < 0 {
return AppLayerResult::err();
}
}
_ => {
SCLogDebug!("Unrecognized packet type: {:?}", hdrtype);
};
retval = self.handle_common_stub(
&cur_i[parsed as usize..fraglen as usize],
0,
Direction::ToClient,
&hdr,
);
if retval < 0 {
return AppLayerResult::err();
}
}
_ => {
SCLogDebug!("Unrecognized packet type: {:?}", hdrtype);
return AppLayerResult::err();
}
}

self.post_gap_housekeeping(direction);
Expand Down Expand Up @@ -1705,46 +1722,6 @@ mod tests {
}
}

#[test]
// Check for endless loop with bind PDUs (Imported from C code)
pub fn test_parse_bind_pdu_infinite_loop() {
let bindbuf: &[u8] = &[
0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x7f, 0x00,
0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00,
0x00, 0x00, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02,
0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0xFF, /* ka boom - endless loop */
];
let mut dcerpc_state = DCERPCState::new();
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(StreamSlice::from_slice(bindbuf, STREAM_TOSERVER, 0), Direction::ToServer)
);
}

#[test]
// Check for endless loop with bind_ack PDUs (Imported from C code)
pub fn test_parse_bindack_pdu_infinite_loop() {
let bind_ack: &[u8] = &[
0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00,
0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0xfd, 0x04, 0x01, 0x00, 0x04, 0x00, 0x31, 0x33,
0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d,
0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c,
0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x01, 0x02, 0x03, 0x04,
0xFF,
];
let mut dcerpc_state = DCERPCState::new();
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack, STREAM_TOSERVER, 0), Direction::ToServer)
);
}

#[test]
// Check for correct internal ids for bind_acks
pub fn test_parse_bindack_internal_ids() {
Expand Down
Loading