From: Victor Julien Date: Mon, 11 Apr 2022 10:33:43 +0000 (+0200) Subject: smb/ntlmssp: add stricter len/offset validation X-Git-Tag: suricata-5.0.9~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=46ed338fa041329f7a5ad6f0a6be2e3d9570440e;p=thirdparty%2Fsuricata.git smb/ntlmssp: add stricter len/offset validation (cherry picked from commit 053a9d2e685abe7639e23b1c7fad5ae7d68630e3) --- diff --git a/rust/src/smb/ntlmssp_records.rs b/rust/src/smb/ntlmssp_records.rs index 02a3eab709..dfa660b500 100644 --- a/rust/src/smb/ntlmssp_records.rs +++ b/rust/src/smb/ntlmssp_records.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Open Information Security Foundation +/* Copyright (C) 2017-2022 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 @@ -56,54 +56,66 @@ pub struct NTLMSSPAuthRecord<'a> { pub version: Option, } -named!(pub parse_ntlm_auth_record, - do_parse!( - _lm_blob_len: le_u16 - >> _lm_blob_maxlen: le_u16 - >> _lm_blob_offset: le_u32 - - >> _ntlmresp_blob_len: le_u16 - >> _ntlmresp_blob_maxlen: le_u16 - >> _ntlmresp_blob_offset: le_u32 - - >> domain_blob_len: le_u16 - >> _domain_blob_maxlen: le_u16 - >> domain_blob_offset: le_u32 - - >> user_blob_len: le_u16 - >> _user_blob_maxlen: le_u16 - >> _user_blob_offset: le_u32 - - >> host_blob_len: le_u16 - >> _host_blob_maxlen: le_u16 - >> _host_blob_offset: le_u32 - - >> _ssnkey_blob_len: le_u16 - >> _ssnkey_blob_maxlen: le_u16 - >> _ssnkey_blob_offset: le_u32 - - >> nego_flags: bits!(tuple!(take_bits!(u8, 6),take_bits!(u8,1),take_bits!(u32,25))) - >> version: cond!(nego_flags.1==1, parse_ntlm_auth_version) - - // subtrack 12 as idenfier (8) and type (4) are cut before we are called - // subtract 60 for the len/offset/maxlen fields above - >> cond!(nego_flags.1==1 && domain_blob_offset > 72, take!(domain_blob_offset - (12 + 60))) - - // or 52 if we have no version - >> cond!(nego_flags.1==0 && domain_blob_offset > 64, take!(domain_blob_offset - (12 + 52))) - - >> domain_blob: take!(domain_blob_len) - >> user_blob: take!(user_blob_len) - >> host_blob: take!(host_blob_len) - - >> ( NTLMSSPAuthRecord { - domain: domain_blob, - user: user_blob, - host: host_blob, - - version: version, - }) -)); +pub fn parse_ntlm_auth_record(i: &[u8]) -> nom::IResult<&[u8], NTLMSSPAuthRecord> { + let record_len = i.len() + 12; // idenfier (8) and type (4) are cut before we are called + + let (i, _lm_blob_len) = verify!(i, le_u16, |v| (v as usize) < record_len)?; + let (i, _lm_blob_maxlen) = le_u16(i)?; + let (i, _lm_blob_offset) = verify!(i, le_u32, |v| (v as usize) < record_len)?; + + let (i, _ntlmresp_blob_len) = verify!(i, le_u16, |v| (v as usize) < record_len)?; + let (i, _ntlmresp_blob_maxlen) = le_u16(i)?; + let (i, _ntlmresp_blob_offset) = verify!(i, le_u32, |v| (v as usize) < record_len)?; + + let (i, domain_blob_len) = verify!(i, le_u16, |v| (v as usize) < record_len)?; + let (i, _domain_blob_maxlen) = le_u16(i)?; + let (i, domain_blob_offset) = verify!(i, le_u32, |v| (v as usize) < record_len)?; + + let (i, user_blob_len) = verify!(i, le_u16, |v| (v as usize) < record_len)?; + let (i, _user_blob_maxlen) = le_u16(i)?; + let (i, _user_blob_offset) = verify!(i, le_u32, |v| (v as usize) < record_len)?; + + let (i, host_blob_len) = verify!(i, le_u16, |v| (v as usize) < record_len)?; + let (i, _host_blob_maxlen) = le_u16(i)?; + let (i, _host_blob_offset) = verify!(i, le_u32, |v| (v as usize) < record_len)?; + + let (i, _ssnkey_blob_len) = verify!(i, le_u16, |v| (v as usize) < record_len)?; + let (i, _ssnkey_blob_maxlen) = le_u16(i)?; + let (i, _ssnkey_blob_offset) = verify!(i, le_u32, |v| (v as usize) < record_len)?; + + let (i, nego_flags) = bits!(i, tuple!(take_bits!(u8, 6),take_bits!(u8,1),take_bits!(u32,25)))?; + + let (i, version) = cond!(i, nego_flags.1==1, parse_ntlm_auth_version)?; + + // 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 = if nego_flags.1 == 1 && domain_blob_offset > 72 { + take!(i, domain_blob_offset - (12 + 16))?.0 + } else { + i + }; + //let (i, _) = cond!(i, nego_flags.1==1 && domain_blob_offset > 72, |b| take!(domain_blob_offset - (12 + 60)))?; + // or 52 if we have no version + let i = if nego_flags.1 == 0 && domain_blob_offset > 64 { + take!(i, domain_blob_offset - (12 + 52))?.0 + } else { + i + }; + //let (i, _) = cond!(i, nego_flags.1==0 && domain_blob_offset > 64, |b| take!(domain_blob_offset - (12 + 52)))?; + + let (i, domain_blob) = take!(i, domain_blob_len)?; + let (i, user_blob) = take!(i, user_blob_len)?; + let (i, host_blob) = take!(i, host_blob_len)?; + + let record = NTLMSSPAuthRecord { + domain: domain_blob, + user: user_blob, + host: host_blob, + + version, + }; + Ok((i, record)) +} #[derive(Debug,PartialEq)] pub struct NTLMSSPRecord<'a> {