From 8dc3431d86ff098621873b46edd2125dd76e328b Mon Sep 17 00:00:00 2001 From: Pierre Chifflier Date: Wed, 19 Jan 2022 11:41:52 +0100 Subject: [PATCH] rust/dcerpc: convert parser to nom7 functions --- rust/src/dcerpc/dcerpc.rs | 22 +- rust/src/dcerpc/dcerpc_udp.rs | 3 +- rust/src/dcerpc/parser.rs | 390 ++++++++++++++++------------------ 3 files changed, 198 insertions(+), 217 deletions(-) diff --git a/rust/src/dcerpc/dcerpc.rs b/rust/src/dcerpc/dcerpc.rs index f0e1fdfe7a..a4758366ab 100644 --- a/rust/src/dcerpc/dcerpc.rs +++ b/rust/src/dcerpc/dcerpc.rs @@ -18,9 +18,9 @@ use crate::applayer::*; use crate::core::{self, *}; use crate::dcerpc::parser; -use nom::error::ErrorKind; -use nom::number::Endianness; -use nom; +use nom7::error::{Error, ErrorKind}; +use nom7::number::Endianness; +use nom7::{Err, IResult, Needed}; use std; use std::cmp; use std::ffi::CString; @@ -575,7 +575,7 @@ impl DCERPCState { } } - pub fn search_dcerpc_record<'a>(&mut self, i: &'a[u8]) -> nom::IResult<&'a[u8], &'a[u8]> { + pub fn search_dcerpc_record<'a>(&mut self, i: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> { let mut d = i; while d.len() >= 2 { if d[0] == 0x05 && d[1] == 0x00 { @@ -583,7 +583,7 @@ impl DCERPCState { } d = &d[1..]; } - Err(nom::Err::Incomplete(nom::Needed::Size(2 as usize - d.len()))) + Err(Err::Incomplete(Needed::new(2 as usize - d.len()))) } /// Makes a call to the nom parser for parsing DCERPC Header. @@ -613,12 +613,12 @@ impl DCERPCState { self.header = Some(header); (input.len() - leftover_bytes.len()) as i32 } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // Insufficient data. SCLogDebug!("Insufficient data while parsing DCERPC header"); -1 } - Err(nom::Err::Error(([], ErrorKind::Eof))) => { + Err(Err::Error(Error{code:ErrorKind::Eof, ..})) => { SCLogDebug!("EoF reached while parsing DCERPC header"); -1 } @@ -652,7 +652,7 @@ impl DCERPCState { } (input.len() - leftover_bytes.len()) as i32 } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // Insufficient data. SCLogDebug!("Insufficient data while parsing DCERPC BIND CTXItem"); -1 @@ -692,7 +692,7 @@ impl DCERPCState { // of bindctxitems) (input.len() - leftover_bytes.len()) as i32 + retval * numctxitems as i32 } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // Insufficient data. SCLogDebug!("Insufficient data while parsing DCERPC BIND header"); -1 @@ -727,7 +727,7 @@ impl DCERPCState { } (input.len() - leftover_bytes.len()) as i32 } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // Insufficient data. SCLogDebug!("Insufficient data while parsing DCERPC BINDACK"); -1 @@ -877,7 +877,7 @@ impl DCERPCState { ); parsed } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // Insufficient data. SCLogDebug!("Insufficient data while parsing DCERPC REQUEST"); -1 diff --git a/rust/src/dcerpc/dcerpc_udp.rs b/rust/src/dcerpc/dcerpc_udp.rs index b98ee827bb..51e9a583d8 100644 --- a/rust/src/dcerpc/dcerpc_udp.rs +++ b/rust/src/dcerpc/dcerpc_udp.rs @@ -21,6 +21,7 @@ use crate::dcerpc::dcerpc::{ DCERPCTransaction, DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, PFCL1_FRAG, PFCL1_LASTFRAG, rs_dcerpc_get_alstate_progress, ALPROTO_DCERPC, PARSER_NAME, }; +use nom7::Err; use std; use std::ffi::CString; use crate::dcerpc::parser; @@ -189,7 +190,7 @@ impl DCERPCUDPState { return AppLayerResult::err(); } } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // Insufficient data. SCLogDebug!("Insufficient data while parsing DCERPC request"); return AppLayerResult::err(); diff --git a/rust/src/dcerpc/parser.rs b/rust/src/dcerpc/parser.rs index 9771a28be0..2ff4288692 100644 --- a/rust/src/dcerpc/parser.rs +++ b/rust/src/dcerpc/parser.rs @@ -18,8 +18,12 @@ use crate::dcerpc::dcerpc::{ BindCtxItem, DCERPCBind, DCERPCBindAck, DCERPCBindAckResult, DCERPCHdr, DCERPCRequest, Uuid, }; use crate::dcerpc::dcerpc_udp::DCERPCHdrUdp; -use nom::number::complete::{le_u16, le_u32, le_u8}; -use nom::number::Endianness; +use nom7::bytes::streaming::take; +use nom7::combinator::cond; +use nom7::number::complete::{le_u16, le_u32, le_u8, u16, u32}; +use nom7::number::Endianness; +use nom7::multi::count; +use nom7::IResult; fn uuid_to_vec(uuid: Uuid) -> Vec { let mut uuidtmp = uuid; @@ -49,216 +53,192 @@ fn assemble_uuid(uuid: Uuid) -> Vec { vect } -named!(pub parse_uuid, - do_parse!( - time_low: take!(4) - >> time_mid: take!(2) - >> time_hi_and_version: take!(2) - >> clock_seq_hi_and_reserved: le_u8 - >> clock_seq_low: le_u8 - >> node: take!(6) - >> ( - Uuid { - time_low: time_low.to_vec(), - time_mid: time_mid.to_vec(), - time_hi_and_version: time_hi_and_version.to_vec(), - clock_seq_hi_and_reserved: clock_seq_hi_and_reserved, - clock_seq_low: clock_seq_low, - node: node.to_vec(), - } - ) - ) -); +pub fn parse_uuid(i: &[u8]) -> IResult<&[u8], Uuid> { + let (i, time_low) = take(4_usize)(i)?; + let (i, time_mid) = take(2_usize)(i)?; + let (i, time_hi_and_version) = take(2_usize)(i)?; + let (i, clock_seq_hi_and_reserved) = le_u8(i)?; + let (i, clock_seq_low) = le_u8(i)?; + let (i, node) = take(6_usize)(i)?; + let uuid = Uuid { + time_low: time_low.to_vec(), + time_mid: time_mid.to_vec(), + time_hi_and_version: time_hi_and_version.to_vec(), + clock_seq_hi_and_reserved, + clock_seq_low, + node: node.to_vec(), + }; + Ok((i, uuid)) +} -named!(pub parse_dcerpc_udp_header, - do_parse!( - rpc_vers: le_u8 - >> pkt_type: le_u8 - >> flags1: le_u8 - >> flags2: le_u8 - >> drep: take!(3) - >> endianness: value!(if drep[0] == 0 { Endianness::Big } else { Endianness::Little }) - >> serial_hi: le_u8 - >> objectuuid: take!(16) - >> interfaceuuid: take!(16) - >> activityuuid: take!(16) - >> server_boot: u32!(endianness) - >> if_vers: u32!(endianness) - >> seqnum: u32!(endianness) - >> opnum: u16!(endianness) - >> ihint: u16!(endianness) - >> ahint: u16!(endianness) - >> fraglen: u16!(endianness) - >> fragnum: u16!(endianness) - >> auth_proto: le_u8 - >> serial_lo: le_u8 - >> ( - DCERPCHdrUdp { - rpc_vers: rpc_vers, - pkt_type: pkt_type, - flags1: flags1, - flags2: flags2, - drep: drep.to_vec(), - serial_hi: serial_hi, - objectuuid: match parse_uuid(objectuuid) { - Ok((_, vect)) => assemble_uuid(vect), - Err(_e) => { - SCLogDebug!("{}", _e); - vec![0] - }, - }, - interfaceuuid: match parse_uuid(interfaceuuid) { - Ok((_, vect)) => assemble_uuid(vect), - Err(_e) => { - SCLogDebug!("{}", _e); - vec![0] - }, - }, - activityuuid: match parse_uuid(activityuuid){ - Ok((_, vect)) => assemble_uuid(vect), - Err(_e) => { - SCLogDebug!("{}", _e); - vec![0] - }, - }, - server_boot: server_boot, - if_vers: if_vers, - seqnum: seqnum, - opnum: opnum, - ihint: ihint, - ahint: ahint, - fraglen: fraglen, - fragnum: fragnum, - auth_proto: auth_proto, - serial_lo: serial_lo, - } - ) - ) -); +pub fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp> { + let (i, rpc_vers) = le_u8(i)?; + let (i, pkt_type) = le_u8(i)?; + let (i, flags1) = le_u8(i)?; + let (i, flags2) = le_u8(i)?; + let (i, drep) = take(3_usize)(i)?; + let endianness = if drep[0] == 0 { Endianness::Big } else { Endianness::Little }; + let (i, serial_hi) = le_u8(i)?; + let (i, objectuuid) = take(16_usize)(i)?; + let (i, interfaceuuid) = take(16_usize)(i)?; + let (i, activityuuid) = take(16_usize)(i)?; + let (i, server_boot) = u32(endianness)(i)?; + let (i, if_vers) = u32(endianness)(i)?; + let (i, seqnum) = u32(endianness)(i)?; + let (i, opnum) = u16(endianness)(i)?; + let (i, ihint) = u16(endianness)(i)?; + let (i, ahint) = u16(endianness)(i)?; + let (i, fraglen) = u16(endianness)(i)?; + let (i, fragnum) = u16(endianness)(i)?; + let (i, auth_proto) = le_u8(i)?; + let (i, serial_lo) = le_u8(i)?; + let header = DCERPCHdrUdp { + rpc_vers, + pkt_type, + flags1, + flags2, + drep: drep.to_vec(), + serial_hi, + objectuuid: match parse_uuid(objectuuid) { + Ok((_, vect)) => assemble_uuid(vect), + Err(_e) => { + SCLogDebug!("{}", _e); + vec![0] + }, + }, + interfaceuuid: match parse_uuid(interfaceuuid) { + Ok((_, vect)) => assemble_uuid(vect), + Err(_e) => { + SCLogDebug!("{}", _e); + vec![0] + }, + }, + activityuuid: match parse_uuid(activityuuid){ + Ok((_, vect)) => assemble_uuid(vect), + Err(_e) => { + SCLogDebug!("{}", _e); + vec![0] + }, + }, + server_boot, + if_vers, + seqnum, + opnum, + ihint, + ahint, + fraglen, + fragnum, + auth_proto, + serial_lo, + }; + Ok((i, header)) +} -named!(pub parse_dcerpc_bindack_result, - do_parse!( - ack_result: le_u16 - >> ack_reason: le_u16 - >> transfer_syntax: take!(16) - >> syntax_version: le_u32 - >> ( - DCERPCBindAckResult { - ack_result:ack_result, - ack_reason:ack_reason, - transfer_syntax:transfer_syntax.to_vec(), - syntax_version:syntax_version, - } - ) - ) -); +pub fn parse_dcerpc_bindack_result(i: &[u8]) -> IResult<&[u8], DCERPCBindAckResult> { + let (i, ack_result) = le_u16(i)?; + let (i, ack_reason) = le_u16(i)?; + let (i, transfer_syntax) = take(16_usize)(i)?; + let (i, syntax_version) = le_u32(i)?; + let result = DCERPCBindAckResult { + ack_result, + ack_reason, + transfer_syntax: transfer_syntax.to_vec(), + syntax_version, + }; + Ok((i, result)) +} -named!(pub parse_dcerpc_bindack, - do_parse!( - _max_xmit_frag: le_u16 - >> _max_recv_frag: le_u16 - >> _assoc_group: take!(4) - >> sec_addr_len: le_u16 - >> take!(sec_addr_len) - >> cond!((sec_addr_len + 2) % 4 != 0, take!(4 - (sec_addr_len + 2) % 4)) - >> numctxitems: le_u8 - >> take!(3) // Padding - >> ctxitems: count!(parse_dcerpc_bindack_result, numctxitems as usize) - >> ( - DCERPCBindAck { - accepted_uuid_list: Vec::new(), - sec_addr_len: sec_addr_len, - numctxitems: numctxitems, - ctxitems: ctxitems, - } - ) - ) -); +pub fn parse_dcerpc_bindack(i: &[u8]) -> IResult<&[u8], DCERPCBindAck> { + let (i, _max_xmit_frag) = le_u16(i)?; + let (i, _max_recv_frag) = le_u16(i)?; + let (i, _assoc_group) = take(4_usize)(i)?; + let (i, sec_addr_len) = le_u16(i)?; + let (i, _) = take(sec_addr_len)(i)?; + let (i, _) = cond((sec_addr_len + 2) % 4 != 0, |b| take(4 - (sec_addr_len + 2) % 4)(b))(i)?; + let (i, numctxitems) = le_u8(i)?; + let (i, _) = take(3_usize)(i)?; // Padding + let (i, ctxitems) = count(parse_dcerpc_bindack_result, numctxitems as usize)(i)?; + let result = DCERPCBindAck { + accepted_uuid_list: Vec::new(), + sec_addr_len, + numctxitems, + ctxitems, + }; + Ok((i, result)) +} -named_args!(pub parse_bindctx_item(endianness: Endianness) , - do_parse!( - ctxid: u16!(endianness) - >> _num_trans_items: le_u8 - >> take!(1) // Reservid bit - >> uuid: take!(16) - >> version: u16!(endianness) - >> versionminor: u16!(endianness) - >> take!(20) - >> ( - BindCtxItem { - ctxid: ctxid, - // UUID parsing for TCP seems to change as per endianness - uuid: match parse_uuid(uuid) { - Ok((_, vect)) => match endianness { - Endianness::Little => assemble_uuid(vect), - _ => uuid_to_vec(vect), - }, - // Shouldn't happen - Err(_e) => {vec![0]}, - }, - version: version, - versionminor: versionminor, - } - ) - ) -); +pub fn parse_bindctx_item(i: &[u8], endianness: Endianness) -> IResult<&[u8], BindCtxItem> { + let (i, ctxid) = u16(endianness)(i)?; + let (i, _num_trans_items) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // Reservid bit + let (i, uuid) = take(16_usize)(i)?; + let (i, version) = u16(endianness)(i)?; + let (i, versionminor) = u16(endianness)(i)?; + let (i, _) = take(20_usize)(i)?; + let result = BindCtxItem { + ctxid, + // UUID parsing for TCP seems to change as per endianness + uuid: match parse_uuid(uuid) { + Ok((_, vect)) => match endianness { + Endianness::Little => assemble_uuid(vect), + _ => uuid_to_vec(vect), + }, + // Shouldn't happen + Err(_e) => {vec![0]}, + }, + version, + versionminor, + }; + Ok((i, result)) +} -named!(pub parse_dcerpc_bind, - do_parse!( - _max_xmit_frag: le_u16 - >> _max_recv_frag: le_u16 - >> _assoc_group_id: le_u32 - >> numctxitems: le_u8 - >> take!(3) - >> ( - DCERPCBind { - numctxitems: numctxitems, - uuid_list: Vec::new(), - } - ) - ) -); +pub fn parse_dcerpc_bind(i: &[u8]) -> IResult<&[u8], DCERPCBind> { + let (i, _max_xmit_frag) = le_u16(i)?; + let (i, _max_recv_frag) = le_u16(i)?; + let (i, _assoc_group_id) = le_u32(i)?; + let (i, numctxitems) = le_u8(i)?; + let (i, _) = take(3_usize)(i)?; + let result = DCERPCBind { + numctxitems, + uuid_list: Vec::new(), + }; + Ok((i, result)) +} -named!(pub parse_dcerpc_header, - do_parse!( - rpc_vers: le_u8 - >> rpc_vers_minor: le_u8 - >> hdrtype: le_u8 - >> pfc_flags: le_u8 - >> packed_drep: take!(4) - >> endianness: value!(if packed_drep[0] & 0x10 == 0 { Endianness::Big } else { Endianness::Little }) - >> frag_length: u16!(endianness) - >> auth_length: u16!(endianness) - >> call_id: u32!(endianness) - >> ( - DCERPCHdr { - rpc_vers: rpc_vers, - rpc_vers_minor: rpc_vers_minor, - hdrtype: hdrtype, - pfc_flags: pfc_flags, - packed_drep: packed_drep.to_vec(), - frag_length: frag_length, - auth_length: auth_length, - call_id: call_id, - } - ) - ) -); +pub fn parse_dcerpc_header(i: &[u8]) -> IResult<&[u8], DCERPCHdr> { + let (i, rpc_vers) = le_u8(i)?; + let (i, rpc_vers_minor) = le_u8(i)?; + let (i, hdrtype) = le_u8(i)?; + let (i, pfc_flags) = le_u8(i)?; + let (i, packed_drep) = take(4_usize)(i)?; + let endianness = if packed_drep[0] & 0x10 == 0 { Endianness::Big } else { Endianness::Little }; + let (i, frag_length) = u16(endianness)(i)?; + let (i, auth_length) = u16(endianness)(i)?; + let (i, call_id) = u32(endianness)(i)?; + let header = DCERPCHdr { + rpc_vers, + rpc_vers_minor, + hdrtype, + pfc_flags, + packed_drep: packed_drep.to_vec(), + frag_length, + auth_length, + call_id, + }; + Ok((i, header)) +} -named_args!(pub parse_dcerpc_request(endianness: Endianness) , - do_parse!( - _pad: take!(4) - >> ctxid: u16!(endianness) - >> opnum: u16!(endianness) - >> ( - DCERPCRequest { - ctxid: ctxid, - opnum: opnum, - first_request_seen: 1, - } - ) - ) -); +pub fn parse_dcerpc_request(i: &[u8], endianness: Endianness) -> IResult<&[u8], DCERPCRequest> { + let (i, _pad) = take(4_usize)(i)?; + let (i, ctxid) = u16(endianness)(i)?; + let (i, opnum) = u16(endianness)(i)?; + let req = DCERPCRequest { + ctxid, + opnum, + first_request_seen: 1, + }; + Ok((i, req)) +} #[cfg(test)] mod tests {