]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb/ntlmssp: parse fields independently of order
authorPhilippe Antoine <pantoine@oisf.net>
Tue, 6 Dec 2022 13:34:37 +0000 (14:34 +0100)
committerVictor Julien <vjulien@oisf.net>
Thu, 22 Dec 2022 09:23:18 +0000 (10:23 +0100)
Instead of relying on the usual ordering...

Ticket: #5258

rust/src/smb/ntlmssp_records.rs

index 6026f7f217aec5b42ca8928e8d7d74e394562827..a548b7c512a1a4726cd5c1a33b775502f34390dd 100644 (file)
@@ -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,