From b34392051dd7c5c75c64144294bb4d496d4a491f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 1 Mar 2018 10:30:02 +0100 Subject: [PATCH] smb3: parse transform records --- rust/src/smb/mod.rs | 1 + rust/src/smb/smb.rs | 49 +++++++++++++++++++++++++++++------- rust/src/smb/smb2_records.rs | 23 +++++------------ rust/src/smb/smb3.rs | 42 +++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 26 deletions(-) create mode 100644 rust/src/smb/smb3.rs diff --git a/rust/src/smb/mod.rs b/rust/src/smb/mod.rs index 0019da92b5..7a3e518390 100644 --- a/rust/src/smb/mod.rs +++ b/rust/src/smb/mod.rs @@ -26,6 +26,7 @@ pub mod smb1; pub mod smb1_session; pub mod smb2; pub mod smb2_session; +pub mod smb3; pub mod dcerpc; pub mod session; pub mod log; diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 25161181cd..2e84557b5a 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -44,6 +44,7 @@ use smb::smb2_records::*; use smb::smb1::*; use smb::smb2::*; +use smb::smb3::*; use smb::dcerpc::*; use smb::session::*; use smb::events::*; @@ -1053,7 +1054,7 @@ impl SMBState { match parse_smb_version(&nbss_part_hdr.data) { IResult::Done(_, ref smb) => { SCLogDebug!("SMB {:?}", smb); - if smb.version == 255u8 { // SMB1 + if smb.version == 0xff_u8 { // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(&nbss_part_hdr.data) { IResult::Done(_, ref r) => { @@ -1077,7 +1078,7 @@ impl SMBState { _ => { }, } - } else if smb.version == 254u8 { // SMB2 + } else if smb.version == 0xfe_u8 { // SMB2 SCLogDebug!("SMBv2 record"); match parse_smb2_request_record(&nbss_part_hdr.data) { IResult::Done(_, ref smb_record) => { @@ -1092,6 +1093,7 @@ impl SMBState { _ => { }, } } + // no SMB3 here yet, will buffer full records }, _ => { }, } @@ -1151,7 +1153,7 @@ impl SMBState { // gap if self.ts_gap { SCLogDebug!("TODO TS trying to catch up after GAP (input {})", cur_i.len()); - match search_smb2_record(cur_i) { + match search_smb_record(cur_i) { IResult::Done(_, pg) => { SCLogDebug!("smb record found"); let smb2_offset = cur_i.len() - pg.data.len(); @@ -1179,7 +1181,7 @@ impl SMBState { match parse_smb_version(&nbss_hdr.data) { IResult::Done(_, ref smb) => { SCLogDebug!("SMB {:?}", smb); - if smb.version == 255u8 { // SMB1 + if smb.version == 0xff_u8 { // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(&nbss_hdr.data) { IResult::Done(_, ref smb_record) => { @@ -1190,7 +1192,7 @@ impl SMBState { return 1; }, } - } else if smb.version == 254u8 { // SMB2 + } else if smb.version == 0xfe_u8 { // SMB2 let mut nbss_data = nbss_hdr.data; while nbss_data.len() > 0 { SCLogDebug!("SMBv2 record"); @@ -1207,6 +1209,20 @@ impl SMBState { }, } } + } else if smb.version == 0xfd_u8 { // SMB3 transform + let mut nbss_data = nbss_hdr.data; + while nbss_data.len() > 0 { + SCLogDebug!("SMBv3 transform record"); + match parse_smb3_transform_record(&nbss_data) { + IResult::Done(nbss_data_rem, ref _smb3_record) => { + nbss_data = nbss_data_rem; + }, + _ => { + self.set_event(SMBEvent::MalformedData); + return 1; + }, + } + } } }, _ => { @@ -1305,6 +1321,7 @@ impl SMBState { _ => { }, } } + // no SMB3 here yet, will buffer full records }, _ => { }, } @@ -1361,8 +1378,8 @@ impl SMBState { } // gap if self.tc_gap { - SCLogDebug!("TODO TC trying to catch up after GAP (input {})", cur_i.len()); - match search_smb2_record(cur_i) { + SCLogDebug!("TC trying to catch up after GAP (input {})", cur_i.len()); + match search_smb_record(cur_i) { IResult::Done(_, pg) => { SCLogDebug!("smb record found"); let smb2_offset = cur_i.len() - pg.data.len(); @@ -1390,7 +1407,7 @@ impl SMBState { match parse_smb_version(&nbss_hdr.data) { IResult::Done(_, ref smb) => { SCLogDebug!("SMB {:?}", smb); - if smb.version == 255u8 { // SMB1 + if smb.version == 0xff_u8 { // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(&nbss_hdr.data) { IResult::Done(_, ref smb_record) => { @@ -1401,7 +1418,7 @@ impl SMBState { return 1; }, } - } else if smb.version == 254u8 { // SMB2 + } else if smb.version == 0xfe_u8 { // SMB2 let mut nbss_data = nbss_hdr.data; while nbss_data.len() > 0 { SCLogDebug!("SMBv2 record"); @@ -1416,6 +1433,20 @@ impl SMBState { }, } } + } else if smb.version == 0xfd_u8 { // SMB3 transform + let mut nbss_data = nbss_hdr.data; + while nbss_data.len() > 0 { + SCLogDebug!("SMBv3 transform record"); + match parse_smb3_transform_record(&nbss_data) { + IResult::Done(nbss_data_rem, ref _smb3_record) => { + nbss_data = nbss_data_rem; + }, + _ => { + self.set_event(SMBEvent::MalformedData); + return 1; + }, + } + } } }, IResult::Incomplete(_) => { diff --git a/rust/src/smb/smb2_records.rs b/rust/src/smb/smb2_records.rs index cf93221207..7024668618 100644 --- a/rust/src/smb/smb2_records.rs +++ b/rust/src/smb/smb2_records.rs @@ -15,7 +15,7 @@ * 02110-1301, USA. */ -use nom::{rest, le_u8, le_u16, le_u32, le_u64, IResult, AsBytes}; +use nom::{rest, le_u8, le_u16, le_u32, le_u64, AsBytes}; #[derive(Debug,PartialEq)] pub struct Smb2SecBlobRecord<'a> { @@ -405,28 +405,17 @@ named!(pub parse_smb2_response_record, )); #[derive(Debug,PartialEq)] -pub struct Smb2RecordPostGap<'a> { +pub struct SmbRecordPostGap<'a> { pub data: &'a[u8], } -named!(pub search_smb2_record, +named!(pub search_smb_record, do_parse!( alt!(take_until!([0xfe, 0x53, 0x4d, 0x42].as_bytes())| // SMB2 - take_until!([0xff, 0x53, 0x4d, 0x42].as_bytes())) // SMB1 + take_until!([0xff, 0x53, 0x4d, 0x42].as_bytes())| // SMB1 + take_until!([0xfd, 0x53, 0x4d, 0x42].as_bytes())) // SMB3 transform hdr >> data : rest - >> ( Smb2RecordPostGap { + >> ( SmbRecordPostGap { data:data, }) )); - -pub fn search_smb2_record_f<'a>(input: &'a [u8]) - -> IResult<&'a [u8], Smb2RecordPostGap> -{ - return closure!(&'a [u8], do_parse!( - take_until!([0xfe, 0x53, 0x4d, 0x42].as_bytes()) - >> data : rest - >> ( Smb2RecordPostGap { - data:data, - }) - ))(input); -} diff --git a/rust/src/smb/smb3.rs b/rust/src/smb/smb3.rs new file mode 100644 index 0000000000..2d74951f07 --- /dev/null +++ b/rust/src/smb/smb3.rs @@ -0,0 +1,42 @@ +/* Copyright (C) 2018 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 + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use nom::{le_u16, le_u32, le_u64}; + +#[derive(Debug,PartialEq)] +pub struct Smb3TransformRecord<'a> { + pub session_id: u64, + pub enc_algo: u16, + pub enc_data: &'a[u8], +} + +named!(pub parse_smb3_transform_record, + do_parse!( + tag!(b"\xfdSMB") + >> signature: take!(16) + >> nonce: take!(16) + >> msg_size: le_u32 + >> reserved: le_u16 + >> enc_algo: le_u16 + >> session_id: le_u64 + >> enc_data: take!(msg_size) + >> ( Smb3TransformRecord { + session_id: session_id, + enc_algo: enc_algo, + enc_data: enc_data, + }) +));