rust/smb: convert parser to nom7 functions (SMB2)

pull/6705/head
Pierre Chifflier 4 years ago committed by Victor Julien
parent 5cadb878ff
commit 8d77ce1ffc

@ -15,7 +15,7 @@
* 02110-1301, USA. * 02110-1301, USA.
*/ */
use nom; use nom7::Err;
use crate::core::*; use crate::core::*;
@ -392,13 +392,13 @@ pub fn smb2_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
_ => false, _ => false,
} }
}, },
Err(nom::Err::Incomplete(_n)) => { Err(Err::Incomplete(_n)) => {
SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _n); SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _n);
events.push(SMBEvent::MalformedData); events.push(SMBEvent::MalformedData);
false false
}, },
Err(nom::Err::Error(_e)) | Err(Err::Error(_e)) |
Err(nom::Err::Failure(_e)) => { Err(Err::Failure(_e)) => {
SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _e); SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _e);
events.push(SMBEvent::MalformedData); events.push(SMBEvent::MalformedData);
false false

@ -15,40 +15,41 @@
* 02110-1301, USA. * 02110-1301, USA.
*/ */
use nom;
use nom::IResult;
use nom::combinator::rest;
use nom::number::streaming::{le_u8, le_u16, le_u32, le_u64};
use crate::smb::smb::*; use crate::smb::smb::*;
use crate::smb::nbss_records::NBSS_MSGTYPE_SESSION_MESSAGE; use crate::smb::nbss_records::NBSS_MSGTYPE_SESSION_MESSAGE;
use nom7::bits::{bits, streaming::take as take_bits};
use nom7::bytes::streaming::{tag, take};
use nom7::combinator::{cond, map_parser, rest};
use nom7::error::{make_error, Error, ErrorKind};
use nom7::multi::count;
use nom7::number::streaming::{le_u8, le_u16, le_u32, le_u64};
use nom7::sequence::tuple;
use nom7::{Err, IResult, Needed};
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2SecBlobRecord<'a> { pub struct Smb2SecBlobRecord<'a> {
pub data: &'a[u8], pub data: &'a[u8],
} }
named!(pub parse_smb2_sec_blob<Smb2SecBlobRecord>, pub fn parse_smb2_sec_blob(i: &[u8]) -> IResult<&[u8], Smb2SecBlobRecord> {
do_parse!( let (i, data) = rest(i)?;
data: rest Ok((i, Smb2SecBlobRecord { data }))
>> ( Smb2SecBlobRecord { }
data: data,
})
));
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2RecordDir<> { pub struct Smb2RecordDir<> {
pub request: bool, pub request: bool,
} }
named!(pub parse_smb2_record_direction<Smb2RecordDir>, pub fn parse_smb2_record_direction(i: &[u8]) -> IResult<&[u8], Smb2RecordDir> {
do_parse!( let (i, _server_component) = tag(b"\xfeSMB")(i)?;
_server_component: tag!(b"\xfeSMB") let (i, _skip) = take(12_usize)(i)?;
>> _skip: take!(12) let (i, flags) = le_u8(i)?;
>> flags: le_u8 let record = Smb2RecordDir {
>> (Smb2RecordDir { request: flags & 0x01 == 0,
request: flags & 0x01 == 0, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2Record<'a> { pub struct Smb2Record<'a> {
@ -69,49 +70,50 @@ impl<'a> Smb2Record<'a> {
} }
fn parse_smb2_request_flags(i:&[u8]) -> IResult<&[u8],(u8,u8,u8,u32,u8,u8,u8,u8)> { fn parse_smb2_request_flags(i:&[u8]) -> IResult<&[u8],(u8,u8,u8,u32,u8,u8,u8,u8)> {
bits!(i, bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple((
tuple!( take_bits(2u8), // reserved / unused
take_bits!(2u8), // reserved / unused take_bits(1u8), // replay op
take_bits!(1u8), // replay op take_bits(1u8), // dfs op
take_bits!(1u8), // dfs op take_bits(24u32), // reserved / unused
take_bits!(24u32), // reserved / unused take_bits(1u8), // signing
take_bits!(1u8), // signing take_bits(1u8), // chained
take_bits!(1u8), // chained take_bits(1u8), // async
take_bits!(1u8), // async take_bits(1u8) // response
take_bits!(1u8) // response )))(i)
)) }
}
pub fn parse_smb2_request_record(i: &[u8]) -> IResult<&[u8], Smb2Record> {
named!(pub parse_smb2_request_record<Smb2Record>, let (i, _server_component) = tag(b"\xfeSMB")(i)?;
do_parse!( let (i, hlen) = le_u16(i)?;
_server_component: tag!(b"\xfeSMB") let (i, _credit_charge) = le_u16(i)?;
>> hlen: le_u16 let (i, _channel_seq) = le_u16(i)?;
>> _credit_charge: le_u16 let (i, _reserved) = take(2_usize)(i)?;
>> _channel_seq: le_u16 let (i, command) = le_u16(i)?;
>> _reserved: take!(2) let (i, _credits_requested) = le_u16(i)?;
>> command: le_u16 let (i, flags) = parse_smb2_request_flags(i)?;
>> _credits_requested: le_u16 let (i, chain_offset) = le_u32(i)?;
>> flags: parse_smb2_request_flags let (i, message_id) = le_u64(i)?;
>> chain_offset: le_u32 let (i, _process_id) = le_u32(i)?;
>> message_id: le_u64 let (i, tree_id) = le_u32(i)?;
>> _process_id: le_u32 let (i, session_id) = le_u64(i)?;
>> tree_id: le_u32 let (i, _signature) = take(16_usize)(i)?;
>> session_id: le_u64 let (i, data) = if chain_offset > hlen as u32 {
>> _signature: take!(16) take(chain_offset - hlen as u32)(i)?
// there is probably a cleaner way to do this } else {
>> data_c: cond!(chain_offset > hlen as u32, take!(chain_offset - hlen as u32)) rest(i)?
>> data_r: cond!(chain_offset <= hlen as u32, rest) };
>> (Smb2Record { let record = Smb2Record {
direction: flags.7, direction: flags.7,
nt_status: 0, nt_status: 0,
command:command, command,
message_id: message_id, message_id,
tree_id: tree_id, tree_id,
async_id: 0, async_id: 0,
session_id: session_id, session_id,
data: if data_c != None { data_c.unwrap() } else { data_r.unwrap() } data,
}) };
)); Ok((i, record))
}
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2NegotiateProtocolRequestRecord<'a> { pub struct Smb2NegotiateProtocolRequestRecord<'a> {
@ -119,23 +121,23 @@ pub struct Smb2NegotiateProtocolRequestRecord<'a> {
pub client_guid: &'a[u8], pub client_guid: &'a[u8],
} }
named!(pub parse_smb2_request_negotiate_protocol<Smb2NegotiateProtocolRequestRecord>, pub fn parse_smb2_request_negotiate_protocol(i: &[u8]) -> IResult<&[u8], Smb2NegotiateProtocolRequestRecord> {
do_parse!( let (i, _struct_size) = take(2_usize)(i)?;
_struct_size: take!(2) let (i, dialects_count) = le_u16(i)?;
>> dialects_count: le_u16 let (i, _sec_mode) = le_u16(i)?;
>> _sec_mode: le_u16 let (i, _reserved1) = le_u16(i)?;
>> _reserved1: le_u16 let (i, _capabilities) = le_u32(i)?;
>> _capabilities: le_u32 let (i, client_guid) = take(16_usize)(i)?;
>> client_guid: take!(16) let (i, _ctx_offset) = le_u32(i)?;
>> _ctx_offset: le_u32 let (i, _ctx_cnt) = le_u16(i)?;
>> _ctx_cnt: le_u16 let (i, _reserved2) = le_u16(i)?;
>> _reserved2: le_u16 let (i, dia_vec) = count(le_u16, dialects_count as usize)(i)?;
>> dia_vec: count!(le_u16, dialects_count as usize) let record = Smb2NegotiateProtocolRequestRecord {
>> (Smb2NegotiateProtocolRequestRecord { dialects_vec: dia_vec,
dialects_vec: dia_vec, client_guid,
client_guid: client_guid, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2NegotiateProtocolResponseRecord<'a> { pub struct Smb2NegotiateProtocolResponseRecord<'a> {
@ -143,28 +145,28 @@ pub struct Smb2NegotiateProtocolResponseRecord<'a> {
pub server_guid: &'a[u8], pub server_guid: &'a[u8],
} }
named!(pub parse_smb2_response_negotiate_protocol<Smb2NegotiateProtocolResponseRecord>, pub fn parse_smb2_response_negotiate_protocol(i: &[u8]) -> IResult<&[u8], Smb2NegotiateProtocolResponseRecord> {
do_parse!( let (i, _struct_size) = take(2_usize)(i)?;
_struct_size: take!(2) let (i, _skip1) = take(2_usize)(i)?;
>> _skip1: take!(2) let (i, dialect) = le_u16(i)?;
>> dialect: le_u16 let (i, _ctx_cnt) = le_u16(i)?;
>> _ctx_cnt: le_u16 let (i, server_guid) = take(16_usize)(i)?;
>> server_guid: take!(16) let record = Smb2NegotiateProtocolResponseRecord {
>> (Smb2NegotiateProtocolResponseRecord { dialect,
dialect, server_guid
server_guid };
}) Ok((i, record))
)); }
named!(pub parse_smb2_response_negotiate_protocol_error<Smb2NegotiateProtocolResponseRecord>, pub fn parse_smb2_response_negotiate_protocol_error(i: &[u8]) -> IResult<&[u8], Smb2NegotiateProtocolResponseRecord> {
do_parse!( let (i, _struct_size) = take(2_usize)(i)?;
_struct_size: take!(2) let (i, _skip1) = take(2_usize)(i)?;
>> _skip1: take!(2) let record = Smb2NegotiateProtocolResponseRecord {
>> (Smb2NegotiateProtocolResponseRecord { dialect: 0,
dialect: 0, server_guid: &[],
server_guid: &[], };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
@ -172,55 +174,49 @@ pub struct Smb2SessionSetupRequestRecord<'a> {
pub data: &'a[u8], pub data: &'a[u8],
} }
named!(pub parse_smb2_request_session_setup<Smb2SessionSetupRequestRecord>, pub fn parse_smb2_request_session_setup(i: &[u8]) -> IResult<&[u8], Smb2SessionSetupRequestRecord> {
do_parse!( let (i, _struct_size) = take(2_usize)(i)?;
_struct_size: take!(2) let (i, _flags) = le_u8(i)?;
>> _flags: le_u8 let (i, _security_mode) = le_u8(i)?;
>> _security_mode: le_u8 let (i, _capabilities) = le_u32(i)?;
>> _capabilities: le_u32 let (i, _channel) = le_u32(i)?;
>> _channel: le_u32 let (i, _sec_offset) = le_u16(i)?;
>> _sec_offset: le_u16 let (i, _sec_len) = le_u16(i)?;
>> _sec_len: le_u16 let (i, _prev_ssn_id) = take(8_usize)(i)?;
>> _prev_ssn_id: take!(8) let (i, data) = rest(i)?;
>> data: rest let record = Smb2SessionSetupRequestRecord { data };
>> (Smb2SessionSetupRequestRecord { Ok((i, record))
data:data, }
})
));
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2TreeConnectRequestRecord<'a> { pub struct Smb2TreeConnectRequestRecord<'a> {
pub share_name: &'a[u8], pub share_name: &'a[u8],
} }
named!(pub parse_smb2_request_tree_connect<Smb2TreeConnectRequestRecord>, pub fn parse_smb2_request_tree_connect(i: &[u8]) -> IResult<&[u8], Smb2TreeConnectRequestRecord> {
do_parse!( let (i, _struct_size) = take(2_usize)(i)?;
_struct_size: take!(2) let (i, _offset_length) = take(4_usize)(i)?;
>> _offset_length: take!(4) let (i, data) = rest(i)?;
>> data: rest let record = Smb2TreeConnectRequestRecord {
>> (Smb2TreeConnectRequestRecord { share_name:data,
share_name:data, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2TreeConnectResponseRecord<> { pub struct Smb2TreeConnectResponseRecord<> {
pub share_type: u8, pub share_type: u8,
} }
named!(pub parse_smb2_response_tree_connect<Smb2TreeConnectResponseRecord>, pub fn parse_smb2_response_tree_connect(i: &[u8]) -> IResult<&[u8], Smb2TreeConnectResponseRecord> {
do_parse!( let (i, _struct_size) = take(2_usize)(i)?;
_struct_size: take!(2) let (i, share_type) = le_u8(i)?;
>> share_type: le_u8 let (i, _share_flags) = le_u32(i)?;
>> _share_flags: le_u32 let (i, _share_caps) = le_u32(i)?;
>> _share_caps: le_u32 let (i, _access_mask) = le_u32(i)?;
>> _access_mask: le_u32 let record = Smb2TreeConnectResponseRecord { share_type };
>> (Smb2TreeConnectResponseRecord { Ok((i, record))
share_type }
})
));
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2CreateRequestRecord<'a> { pub struct Smb2CreateRequestRecord<'a> {
@ -229,22 +225,22 @@ pub struct Smb2CreateRequestRecord<'a> {
pub data: &'a[u8], pub data: &'a[u8],
} }
named!(pub parse_smb2_request_create<Smb2CreateRequestRecord>, pub fn parse_smb2_request_create(i: &[u8]) -> IResult<&[u8], Smb2CreateRequestRecord> {
do_parse!( let (i, _skip1) = take(36_usize)(i)?;
_skip1: take!(36) let (i, disposition) = le_u32(i)?;
>> disposition: le_u32 let (i, create_options) = le_u32(i)?;
>> create_options: le_u32 let (i, _file_name_offset) = le_u16(i)?;
>> _file_name_offset: le_u16 let (i, file_name_length) = le_u16(i)?;
>> file_name_length: le_u16 let (i, _skip2) = take(8_usize)(i)?;
>> _skip2: take!(8) let (i, data) = take(file_name_length)(i)?;
>> data: take!(file_name_length) let (i, _skip3) = rest(i)?;
>> _skip3: rest let record = Smb2CreateRequestRecord {
>> (Smb2CreateRequestRecord { disposition,
disposition, create_options,
create_options, data
data };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2IOCtlRequestRecord<'a> { pub struct Smb2IOCtlRequestRecord<'a> {
@ -254,26 +250,26 @@ pub struct Smb2IOCtlRequestRecord<'a> {
pub data: &'a[u8], pub data: &'a[u8],
} }
named!(pub parse_smb2_request_ioctl<Smb2IOCtlRequestRecord>, pub fn parse_smb2_request_ioctl(i: &[u8]) -> IResult<&[u8], Smb2IOCtlRequestRecord> {
do_parse!( let (i, _skip) = take(2_usize) (i)?;// structure size
_skip: take!(2) // structure size let (i, _) = take(2_usize) (i)?;// reserved
>> take!(2) // reserved let (i, func) = le_u32(i)?;
>> func: le_u32 let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let (i, _indata_offset) = le_u32(i)?;
>> _indata_offset: le_u32 let (i, indata_len) = le_u32(i)?;
>> indata_len: le_u32 let (i, _) = take(4_usize)(i)?;
>> take!(4) let (i, _outdata_offset) = le_u32(i)?;
>> _outdata_offset: le_u32 let (i, _outdata_len) = le_u32(i)?;
>> _outdata_len: le_u32 let (i, _) = take(12_usize)(i)?;
>> take!(12) let (i, data) = take(indata_len)(i)?;
>> data: take!(indata_len) let record = Smb2IOCtlRequestRecord {
>> (Smb2IOCtlRequestRecord { is_pipe: (func == 0x0011c017),
is_pipe: (func == 0x0011c017), function: func,
function: func, guid,
guid:guid, data,
data:data, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2IOCtlResponseRecord<'a> { pub struct Smb2IOCtlResponseRecord<'a> {
@ -286,73 +282,69 @@ pub struct Smb2IOCtlResponseRecord<'a> {
pub outdata_offset: u32, pub outdata_offset: u32,
} }
named!(pub parse_smb2_response_ioctl<Smb2IOCtlResponseRecord>, pub fn parse_smb2_response_ioctl(i: &[u8]) -> IResult<&[u8], Smb2IOCtlResponseRecord> {
do_parse!( let (i, _skip) = take(2_usize)(i)?; // structure size
_skip: take!(2) // structure size let (i, _) = take(2_usize)(i)?; // reserved
>> take!(2) // reserved let (i, func) = le_u32(i)?;
>> func: le_u32 let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let (i, indata_offset) = le_u32(i)?;
>> indata_offset: le_u32 let (i, indata_len) = le_u32(i)?;
>> indata_len: le_u32 let (i, outdata_offset) = le_u32(i)?;
>> outdata_offset: le_u32 let (i, outdata_len) = le_u32(i)?;
>> outdata_len: le_u32 let (i, _) = take(8_usize)(i)?;
>> take!(8) let (i, _) = take(indata_len)(i)?;
>> take!(indata_len) let (i, data) = take(outdata_len)(i)?;
>> data: take!(outdata_len) let record = Smb2IOCtlResponseRecord {
>> (Smb2IOCtlResponseRecord { is_pipe: (func == 0x0011c017),
is_pipe: (func == 0x0011c017), guid,
guid:guid, data,
data:data, indata_len,
indata_len:indata_len, outdata_len,
outdata_len:outdata_len, indata_offset,
indata_offset:indata_offset, outdata_offset,
outdata_offset:outdata_offset, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2CloseRequestRecord<'a> { pub struct Smb2CloseRequestRecord<'a> {
pub guid: &'a[u8], pub guid: &'a[u8],
} }
named!(pub parse_smb2_request_close<Smb2CloseRequestRecord>, pub fn parse_smb2_request_close(i: &[u8]) -> IResult<&[u8], Smb2CloseRequestRecord> {
do_parse!( let (i, _skip) = take(8_usize)(i)?;
_skip: take!(8) let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let record = Smb2CloseRequestRecord { guid };
>> (Smb2CloseRequestRecord { Ok((i, record))
guid }
})
));
#[derive(Debug)] #[derive(Debug)]
pub struct Smb2SetInfoRequestRenameRecord<'a> { pub struct Smb2SetInfoRequestRenameRecord<'a> {
pub name: &'a[u8], pub name: &'a[u8],
} }
named!(pub parse_smb2_request_setinfo_rename<Smb2SetInfoRequestData>, pub fn parse_smb2_request_setinfo_rename(i: &[u8]) -> IResult<&[u8], Smb2SetInfoRequestData> {
do_parse!( let (i, _replace) = le_u8(i)?;
_replace: le_u8 let (i, _reserved) = take(7_usize)(i)?;
>> _reserved: take!(7) let (i, _root_handle) = take(8_usize)(i)?;
>> _root_handle: take!(8) let (i, name_len) = le_u32(i)?;
>> name_len: le_u32 let (i, name) = take(name_len)(i)?;
>> name: take!(name_len) let record = Smb2SetInfoRequestData::RENAME(Smb2SetInfoRequestRenameRecord { name });
>> (Smb2SetInfoRequestData::RENAME(Smb2SetInfoRequestRenameRecord { Ok((i, record))
name }
}))
));
#[derive(Debug)] #[derive(Debug)]
pub struct Smb2SetInfoRequestDispoRecord { pub struct Smb2SetInfoRequestDispoRecord {
pub delete: bool, pub delete: bool,
} }
named!(pub parse_smb2_request_setinfo_disposition<&[u8], Smb2SetInfoRequestData>, pub fn parse_smb2_request_setinfo_disposition(i: &[u8]) -> IResult<&[u8], Smb2SetInfoRequestData> {
do_parse!( let (i, info) = le_u8(i)?;
info: le_u8 >> let record = Smb2SetInfoRequestData::DISPOSITION(Smb2SetInfoRequestDispoRecord {
(Smb2SetInfoRequestData::DISPOSITION(Smb2SetInfoRequestDispoRecord { delete: info & 1 != 0,
delete: info & 1 != 0, });
})) Ok((i, record))
)); }
#[derive(Debug)] #[derive(Debug)]
pub enum Smb2SetInfoRequestData<'a> { pub enum Smb2SetInfoRequestData<'a> {
@ -387,24 +379,27 @@ fn parse_smb2_request_setinfo_data(
return Ok((i, Smb2SetInfoRequestData::UNHANDLED)); return Ok((i, Smb2SetInfoRequestData::UNHANDLED));
} }
named!(pub parse_smb2_request_setinfo<Smb2SetInfoRequestRecord>, pub fn parse_smb2_request_setinfo(i: &[u8]) -> IResult<&[u8], Smb2SetInfoRequestRecord> {
do_parse!( let (i, _struct_size) = le_u16(i)?;
_struct_size: le_u16 let (i, class) = le_u8(i)?;
>> class: le_u8 let (i, infolvl) = le_u8(i)?;
>> infolvl: le_u8 let (i, setinfo_size) = le_u32(i)?;
>> setinfo_size: le_u32 let (i, _setinfo_offset) = le_u16(i)?;
>> _setinfo_offset: le_u16 let (i, _reserved) = take(2_usize)(i)?;
>> _reserved: take!(2) let (i, _additional_info) = le_u32(i)?;
>> _additional_info: le_u32 let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let (i, data) = map_parser(
>> data: flat_map!(take!(setinfo_size), call!(parse_smb2_request_setinfo_data, class, infolvl)) take(setinfo_size),
>> (Smb2SetInfoRequestRecord { |b| parse_smb2_request_setinfo_data(b, class, infolvl)
guid: guid, )(i)?;
class: class, let record = Smb2SetInfoRequestRecord {
infolvl: infolvl, guid,
data: data, class,
}) infolvl,
)); data,
};
Ok((i, record))
}
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2WriteRequestRecord<'a> { pub struct Smb2WriteRequestRecord<'a> {
@ -415,24 +410,24 @@ pub struct Smb2WriteRequestRecord<'a> {
} }
// can be called on incomplete records // can be called on incomplete records
named!(pub parse_smb2_request_write<Smb2WriteRequestRecord>, pub fn parse_smb2_request_write(i: &[u8]) -> IResult<&[u8], Smb2WriteRequestRecord> {
do_parse!( let (i, _skip1) = take(4_usize)(i)?;
_skip1: take!(4) let (i, wr_len) = le_u32(i)?;
>> wr_len: le_u32 let (i, wr_offset) = le_u64(i)?;
>> wr_offset: le_u64 let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let (i, _channel) = le_u32(i)?;
>> _channel: le_u32 let (i, _remaining_bytes) = le_u32(i)?;
>> _remaining_bytes: le_u32 let (i, _write_flags) = le_u32(i)?;
>> _write_flags: le_u32 let (i, _skip2) = take(4_usize)(i)?;
>> _skip2: take!(4) let (i, data) = parse_smb2_data(i, wr_len)?;
>> data: call!(parse_smb2_data, wr_len) let record = Smb2WriteRequestRecord {
>> (Smb2WriteRequestRecord { wr_len,
wr_len:wr_len, wr_offset,
wr_offset:wr_offset, guid,
guid:guid, data,
data:data, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2ReadRequestRecord<'a> { pub struct Smb2ReadRequestRecord<'a> {
@ -441,22 +436,22 @@ pub struct Smb2ReadRequestRecord<'a> {
pub guid: &'a[u8], pub guid: &'a[u8],
} }
named!(pub parse_smb2_request_read<Smb2ReadRequestRecord>, pub fn parse_smb2_request_read(i: &[u8]) -> IResult<&[u8], Smb2ReadRequestRecord> {
do_parse!( let (i, _skip1) = take(4_usize)(i)?;
_skip1: take!(4) let (i, rd_len) = le_u32(i)?;
>> rd_len: le_u32 let (i, rd_offset) = le_u64(i)?;
>> rd_offset: le_u64 let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let (i, _min_count) = le_u32(i)?;
>> _min_count: le_u32 let (i, _channel) = le_u32(i)?;
>> _channel: le_u32 let (i, _remaining_bytes) = le_u32(i)?;
>> _remaining_bytes: le_u32 let (i, _skip2) = take(4_usize)(i)?;
>> _skip2: take!(4) let record = Smb2ReadRequestRecord {
>> (Smb2ReadRequestRecord { rd_len,
rd_len:rd_len, rd_offset,
rd_offset:rd_offset, guid,
guid:guid, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2ReadResponseRecord<'a> { pub struct Smb2ReadResponseRecord<'a> {
@ -473,24 +468,24 @@ fn parse_smb2_data<'a>(i: &'a[u8], len: u32)
if len as usize > i.len() { if len as usize > i.len() {
rest(i) rest(i)
} else { } else {
take!(i, len) take(len)(i)
} }
} }
// can be called on incomplete records // can be called on incomplete records
named!(pub parse_smb2_response_read<Smb2ReadResponseRecord>, pub fn parse_smb2_response_read(i: &[u8]) -> IResult<&[u8], Smb2ReadResponseRecord> {
do_parse!( let (i, _struct_size) = le_u16(i)?;
_struct_size: le_u16 let (i, _data_offset) = le_u16(i)?;
>> _data_offset: le_u16 let (i, rd_len) = le_u32(i)?;
>> rd_len: le_u32 let (i, _rd_rem) = le_u32(i)?;
>> _rd_rem: le_u32 let (i, _padding) = take(4_usize)(i)?;
>> _padding: take!(4) let (i, data) = parse_smb2_data(i, rd_len)?;
>> data: call!(parse_smb2_data, rd_len) let record = Smb2ReadResponseRecord {
>> (Smb2ReadResponseRecord { len: rd_len,
len : rd_len, data,
data : data, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2CreateResponseRecord<'a> { pub struct Smb2CreateResponseRecord<'a> {
@ -502,77 +497,77 @@ pub struct Smb2CreateResponseRecord<'a> {
pub size: u64, pub size: u64,
} }
named!(pub parse_smb2_response_create<Smb2CreateResponseRecord>, pub fn parse_smb2_response_create(i: &[u8]) -> IResult<&[u8], Smb2CreateResponseRecord> {
do_parse!( let (i, _ssize) = le_u16(i)?;
_ssize: le_u16 let (i, _oplock) = le_u8(i)?;
>> _oplock: le_u8 let (i, _resp_flags) = le_u8(i)?;
>> _resp_flags: le_u8 let (i, _create_action) = le_u32(i)?;
>> _create_action: le_u32 let (i, create_ts) = le_u64(i)?;
>> create_ts: le_u64 let (i, last_access_ts) = le_u64(i)?;
>> last_access_ts: le_u64 let (i, last_write_ts) = le_u64(i)?;
>> last_write_ts: le_u64 let (i, last_change_ts) = le_u64(i)?;
>> last_change_ts: le_u64 let (i, _alloc_size) = le_u64(i)?;
>> _alloc_size: le_u64 let (i, eof) = le_u64(i)?;
>> eof: le_u64 let (i, _attrs) = le_u32(i)?;
>> _attrs: le_u32 let (i, _padding) = take(4_usize)(i)?;
>> _padding: take!(4) let (i, guid) = take(16_usize)(i)?;
>> guid: take!(16) let (i, _skip2) = take(8_usize)(i)?;
>> _skip2: take!(8) let record = Smb2CreateResponseRecord {
>> (Smb2CreateResponseRecord { guid,
guid : guid, create_ts: SMBFiletime::new(create_ts),
create_ts: SMBFiletime::new(create_ts), last_access_ts: SMBFiletime::new(last_access_ts),
last_access_ts: SMBFiletime::new(last_access_ts), last_write_ts: SMBFiletime::new(last_write_ts),
last_write_ts: SMBFiletime::new(last_write_ts), last_change_ts: SMBFiletime::new(last_change_ts),
last_change_ts: SMBFiletime::new(last_change_ts), size: eof,
size: eof, };
}) Ok((i, record))
)); }
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct Smb2WriteResponseRecord<> { pub struct Smb2WriteResponseRecord<> {
pub wr_cnt: u32, pub wr_cnt: u32,
} }
named!(pub parse_smb2_response_write<Smb2WriteResponseRecord>, pub fn parse_smb2_response_write(i: &[u8]) -> IResult<&[u8], Smb2WriteResponseRecord> {
do_parse!( let (i, _skip1) = take(4_usize)(i)?;
_skip1: take!(4) let (i, wr_cnt) = le_u32(i)?;
>> wr_cnt: le_u32 let (i, _skip2) = take(6_usize)(i)?;
>> _skip2: take!(6) let record = Smb2WriteResponseRecord { wr_cnt };
>> (Smb2WriteResponseRecord { Ok((i, record))
wr_cnt : wr_cnt, }
})
)); pub fn parse_smb2_response_record(i: &[u8]) -> IResult<&[u8], Smb2Record> {
let (i, _) = tag(b"\xfeSMB")(i)?;
named!(pub parse_smb2_response_record<Smb2Record>, let (i, hlen) = le_u16(i)?;
do_parse!( let (i, _credit_charge) = le_u16(i)?;
tag!(b"\xfeSMB") let (i, nt_status) = le_u32(i)?;
>> hlen: le_u16 let (i, command) = le_u16(i)?;
>> _credit_charge: le_u16 let (i, _credit_granted) = le_u16(i)?;
>> nt_status: le_u32 let (i, flags) = parse_smb2_request_flags(i)?;
>> command: le_u16 let (i, chain_offset) = le_u32(i)?;
>> _credit_granted: le_u16 let (i, message_id) = le_u64(i)?;
>> flags: parse_smb2_request_flags let (i, _process_id) = cond(flags.6 == 0, le_u32)(i)?;
>> chain_offset: le_u32 let (i, tree_id) = cond(flags.6 == 0, le_u32)(i)?;
>> message_id: le_u64 let (i, async_id) = cond(flags.6 == 1, le_u64)(i)?;
>> _process_id: cond!(flags.6==0, le_u32) let (i, session_id) = le_u64(i)?;
>> tree_id: cond!(flags.6==0, le_u32) let (i, _signature) = take(16_usize)(i)?;
>> async_id: cond!(flags.6==1, le_u64) let (i, data) = if chain_offset > hlen as u32 {
>> session_id: le_u64 take(chain_offset - hlen as u32)(i)?
>> _signature: take!(16) } else {
// there is probably a cleaner way to do this rest(i)?
>> data_c: cond!(chain_offset > hlen as u32, take!(chain_offset - hlen as u32)) };
>> data_r: cond!(chain_offset <= hlen as u32, rest) let record = Smb2Record {
>> (Smb2Record { direction: flags.7,
direction: flags.7, nt_status,
nt_status: nt_status, message_id,
message_id: message_id, tree_id: tree_id.unwrap_or(0),
tree_id: tree_id.unwrap_or(0), async_id: async_id.unwrap_or(0),
async_id: async_id.unwrap_or(0), session_id,
session_id: session_id, command,
command:command, data,
data: data_c.or(data_r).unwrap() };
}) Ok((i, record))
)); }
fn smb_basic_search(d: &[u8]) -> usize { fn smb_basic_search(d: &[u8]) -> usize {
let needle = b"SMB"; let needle = b"SMB";
@ -588,12 +583,12 @@ fn smb_basic_search(d: &[u8]) -> usize {
return 0; return 0;
} }
pub fn search_smb_record<'a>(i: &'a [u8]) -> nom::IResult<&'a [u8], &'a [u8]> { pub fn search_smb_record<'a>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
let mut d = i; let mut d = i;
while d.len() >= 4 { while d.len() >= 4 {
let index = smb_basic_search(d); let index = smb_basic_search(d);
if index == 0 { if index == 0 {
return Err(nom::Err::Error((d, nom::error::ErrorKind::Eof))); return Err(Err::Error(make_error(d, ErrorKind::Eof)));
} }
if d[index - 1] == 0xfe || d[index - 1] == 0xff || d[index - 1] == 0xfd { if d[index - 1] == 0xfe || d[index - 1] == 0xff || d[index - 1] == 0xfd {
// if we have enough data, check nbss // if we have enough data, check nbss
@ -603,5 +598,5 @@ pub fn search_smb_record<'a>(i: &'a [u8]) -> nom::IResult<&'a [u8], &'a [u8]> {
} }
d = &d[index + 3..]; d = &d[index + 3..];
} }
Err(nom::Err::Incomplete(nom::Needed::Size(4 as usize - d.len()))) Err(Err::Incomplete(Needed::new(4 as usize - d.len())))
} }

Loading…
Cancel
Save