Skip to content

Commit

Permalink
dcerpc/tcp: add frames support
Browse files Browse the repository at this point in the history
Frames of the following types have been added for toserver direction:
1. Pdu: The entire Protocol Data Unit
2. Hdr: Header of the request
3. Data: PDU data

Feature 4904
  • Loading branch information
inashivb committed Jan 28, 2025
1 parent ee72456 commit 3f3aaf4
Showing 1 changed file with 41 additions and 23 deletions.
64 changes: 41 additions & 23 deletions rust/src/dcerpc/dcerpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::core::{self, *};
use crate::dcerpc::parser;
use crate::direction::{Direction, DIR_BOTH};
use crate::flow::Flow;
use crate::frames::*;
use nom7::error::{Error, ErrorKind};
use nom7::number::Endianness;
use nom7::{Err, IResult, Needed};
Expand Down Expand Up @@ -117,6 +118,13 @@ pub(super) static mut DCERPC_MAX_TX: usize = 1024;

pub static mut ALPROTO_DCERPC: AppProto = ALPROTO_UNKNOWN;

#[derive(AppLayerFrameType)]
pub enum DCERPCFrameType {
Pdu,
Hdr,
Data,
}

pub fn dcerpc_type_string(t: u8) -> String {
match t {
DCERPC_TYPE_REQUEST => "REQUEST",
Expand Down Expand Up @@ -873,10 +881,10 @@ impl DCERPCState {
}
}

pub fn handle_input_data(&mut self, input: &[u8], direction: Direction) -> AppLayerResult {
pub fn handle_input_data(&mut self, stream_slice: StreamSlice, direction: Direction) -> AppLayerResult {
let mut parsed = 0;
let retval;
let mut cur_i = input;
let mut cur_i = stream_slice.as_slice();

// 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 @@ -910,6 +918,10 @@ impl DCERPCState {
}

let mut frag_bytes_consumed: u16 = 0;
let mut flow = std::ptr::null();
if let Some(f) = self.flow {
flow = f;
}
// Check if header data was complete. In case of EoF or incomplete data, wait for more
// data else return error
if self.header.is_none() && !cur_i.is_empty() {
Expand All @@ -931,6 +943,11 @@ impl DCERPCState {
return AppLayerResult::incomplete(parsed as u32, fraglen as u32 - parsed as u32);
}

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 current_call_id = self.get_hdr_call_id().unwrap_or(0);

match self.get_hdr_type() {
Expand Down Expand Up @@ -1063,7 +1080,7 @@ pub unsafe extern "C" fn rs_dcerpc_parse_request(
}
if !stream_slice.is_gap() {
state.flow = Some(flow);
return state.handle_input_data(stream_slice.as_slice(), Direction::ToServer);
return state.handle_input_data(stream_slice, Direction::ToServer);
}
AppLayerResult::err()
}
Expand All @@ -1086,7 +1103,7 @@ pub unsafe extern "C" fn rs_dcerpc_parse_response(
}
if !stream_slice.is_gap() {
state.flow = Some(flow);
return state.handle_input_data(stream_slice.as_slice(), Direction::ToClient);
return state.handle_input_data(stream_slice, Direction::ToClient);
}
AppLayerResult::err()
}
Expand Down Expand Up @@ -1263,8 +1280,8 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() {
get_state_data: rs_dcerpc_get_state_data,
apply_tx_config: None,
flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS,
get_frame_id_by_name: None,
get_frame_name_by_id: None,
get_frame_id_by_name: Some(DCERPCFrameType::ffi_id_from_name),
get_frame_name_by_id: Some(DCERPCFrameType::ffi_name_from_id),
};

let ip_proto_str = CString::new("tcp").unwrap();
Expand Down Expand Up @@ -1301,7 +1318,8 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() {

#[cfg(test)]
mod tests {
use crate::applayer::AppLayerResult;
use crate::applayer::{AppLayerResult, StreamSlice};
use crate::core::*;
use crate::dcerpc::dcerpc::DCERPCState;
use crate::direction::Direction;
use std::cmp;
Expand Down Expand Up @@ -1729,7 +1747,7 @@ mod tests {
let mut dcerpc_state = DCERPCState::new();
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(request, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(request, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(hdr) = dcerpc_state.header {
assert_eq!(0, hdr.hdrtype);
Expand Down Expand Up @@ -1765,11 +1783,11 @@ mod tests {
let mut dcerpc_state = DCERPCState::new();
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind1, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind1, STREAM_TOSERVER, 0), Direction::ToServer)
);
assert_eq!(
AppLayerResult::ok(), // TODO ASK if this is correct?
dcerpc_state.handle_input_data(bind2, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind2, STREAM_TOSERVER, 0), Direction::ToServer)
);
}

Expand All @@ -1792,7 +1810,7 @@ mod tests {
];
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bindbuf, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bindbuf, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(ref bind) = dcerpc_state.bind {
let bind_uuid = &bind.uuid_list[0].uuid;
Expand Down Expand Up @@ -1826,7 +1844,7 @@ mod tests {
let mut dcerpc_state = DCERPCState::new();
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bindbuf, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bindbuf, STREAM_TOSERVER, 0), Direction::ToServer)
);
}

Expand All @@ -1845,7 +1863,7 @@ mod tests {
let mut dcerpc_state = DCERPCState::new();
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind_ack, Direction::ToClient)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack, STREAM_TOSERVER, 0), Direction::ToServer)
);
}

Expand Down Expand Up @@ -2096,11 +2114,11 @@ mod tests {
];
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind1, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind1, STREAM_TOSERVER, 0), Direction::ToServer)
);
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind_ack1, Direction::ToClient)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack1, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(ref back) = dcerpc_state.bindack {
assert_eq!(1, back.accepted_uuid_list.len());
Expand All @@ -2109,11 +2127,11 @@ mod tests {
}
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind2, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind2, STREAM_TOSERVER, 0), Direction::ToServer)
);
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind_ack2, Direction::ToClient)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack2, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(ref back) = dcerpc_state.bindack {
assert_eq!(1, back.accepted_uuid_list.len());
Expand All @@ -2122,11 +2140,11 @@ mod tests {
}
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind3, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind3, STREAM_TOSERVER, 0), Direction::ToServer)
);
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind_ack3, Direction::ToClient)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack3, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(ref back) = dcerpc_state.bindack {
assert_eq!(1, back.accepted_uuid_list.len());
Expand Down Expand Up @@ -2178,11 +2196,11 @@ mod tests {
];
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bind, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bind, STREAM_TOSERVER, 0), Direction::ToServer)
);
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(bindack, Direction::ToClient)
dcerpc_state.handle_input_data(StreamSlice::from_slice(bindack, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(ref back) = dcerpc_state.bindack {
assert_eq!(1, back.accepted_uuid_list.len());
Expand All @@ -2191,11 +2209,11 @@ mod tests {
}
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(alter_context, Direction::ToServer)
dcerpc_state.handle_input_data(StreamSlice::from_slice(alter_context, STREAM_TOSERVER, 0), Direction::ToServer)
);
assert_eq!(
AppLayerResult::ok(),
dcerpc_state.handle_input_data(alter_context_resp, Direction::ToClient)
dcerpc_state.handle_input_data(StreamSlice::from_slice(alter_context_resp, STREAM_TOSERVER, 0), Direction::ToServer)
);
if let Some(ref back) = dcerpc_state.bindack {
assert_eq!(1, back.accepted_uuid_list.len());
Expand Down

0 comments on commit 3f3aaf4

Please sign in to comment.