diff --git a/rust/src/smb/ntlmssp_records.rs b/rust/src/smb/ntlmssp_records.rs index 6026f7f217..a548b7c512 100644 --- a/rust/src/smb/ntlmssp_records.rs +++ b/rust/src/smb/ntlmssp_records.rs @@ -23,6 +23,8 @@ use nom7::combinator::{cond, rest, verify}; use nom7::number::streaming::{le_u8, le_u16, le_u32}; use nom7::sequence::tuple; use nom7::IResult; +use nom7::Err; +use nom7::error::{ErrorKind, make_error}; #[derive(Debug,PartialEq, Eq)] pub struct NTLMSSPVersion { @@ -71,8 +73,23 @@ fn parse_ntlm_auth_nego_flags(i:&[u8]) -> IResult<&[u8],(u8,u8,u32)> { )))(i) } +const NTLMSSP_IDTYPE_LEN: usize = 12; + +fn extract_ntlm_substring(i: &[u8], offset: u32, length: u16) -> IResult<&[u8], &[u8]> { + if offset < NTLMSSP_IDTYPE_LEN as u32 { + return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); + } + let start = offset as usize - NTLMSSP_IDTYPE_LEN; + let end = offset as usize + length as usize - NTLMSSP_IDTYPE_LEN; + if i.len() < end { + return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); + } + return Ok((i, &i[start..end])); +} + pub fn parse_ntlm_auth_record(i: &[u8]) -> IResult<&[u8], NTLMSSPAuthRecord> { - let record_len = i.len() + 12; // idenfier (8) and type (4) are cut before we are called + let orig_i = i; + let record_len = i.len() + NTLMSSP_IDTYPE_LEN; // idenfier (8) and type (4) are cut before we are called let (i, _lm_blob_len) = verify(le_u16, |&v| (v as usize) < record_len)(i)?; let (i, _lm_blob_maxlen) = le_u16(i)?; @@ -88,28 +105,23 @@ pub fn parse_ntlm_auth_record(i: &[u8]) -> IResult<&[u8], NTLMSSPAuthRecord> { let (i, user_blob_len) = verify(le_u16, |&v| (v as usize) < record_len)(i)?; let (i, _user_blob_maxlen) = le_u16(i)?; - let (i, _user_blob_offset) = verify(le_u32, |&v| (v as usize) < record_len)(i)?; + let (i, user_blob_offset) = verify(le_u32, |&v| (v as usize) < record_len)(i)?; let (i, host_blob_len) = verify(le_u16, |&v| (v as usize) < record_len)(i)?; let (i, _host_blob_maxlen) = le_u16(i)?; - let (i, _host_blob_offset) = verify(le_u32, |&v| (v as usize) < record_len)(i)?; + let (i, host_blob_offset) = verify(le_u32, |&v| (v as usize) < record_len)(i)?; let (i, _ssnkey_blob_len) = verify(le_u16, |&v| (v as usize) < record_len)(i)?; let (i, _ssnkey_blob_maxlen) = le_u16(i)?; let (i, _ssnkey_blob_offset) = verify(le_u32, |&v| (v as usize) < record_len)(i)?; let (i, nego_flags) = parse_ntlm_auth_nego_flags(i)?; - let (i, version) = cond(nego_flags.1==1, parse_ntlm_auth_version)(i)?; - - // subtrack 12 as idenfier (8) and type (4) are cut before we are called - // subtract 60 for the len/offset/maxlen fields above - let (i, _) = cond(nego_flags.1==1 && domain_blob_offset > 72, |b| take(domain_blob_offset - (12 + 60))(b))(i)?; - // or 52 if we have no version - let (i, _) = cond(nego_flags.1==0 && domain_blob_offset > 64, |b| take(domain_blob_offset - (12 + 52))(b))(i)?; + let (_, version) = cond(nego_flags.1==1, parse_ntlm_auth_version)(i)?; - let (i, domain_blob) = take(domain_blob_len)(i)?; - let (i, user_blob) = take(user_blob_len)(i)?; - let (i, host_blob) = take(host_blob_len)(i)?; + // Caller does not care about remaining input... + let (_, domain_blob) = extract_ntlm_substring(orig_i, domain_blob_offset, domain_blob_len)?; + let (_, user_blob) = extract_ntlm_substring(orig_i, user_blob_offset, user_blob_len)?; + let (_, host_blob) = extract_ntlm_substring(orig_i, host_blob_offset, host_blob_len)?; let record = NTLMSSPAuthRecord { domain: domain_blob,