smb2: track max read/write size and enforce its values

pull/7262/head
Victor Julien 4 years ago
parent 594acec5dc
commit f28888513a

@ -31,6 +31,12 @@ pub enum SMBEvent {
RequestToClient,
/// A response was seen in the to server direction,
ResponseToServer,
/// READ request asking for more than `max_read_size`
ReadRequestTooLarge,
/// READ response bigger than `max_read_size`
ReadResponseTooLarge,
/// WRITE request for more than `max_write_size`
WriteRequestTooLarge,
}
impl SMBTransaction {

@ -724,6 +724,7 @@ pub fn u32_as_bytes(i: u32) -> [u8;4] {
return [o1, o2, o3, o4]
}
#[derive(Default, Debug)]
pub struct SMBState<> {
/// map ssn/tree/msgid to vec (guid/name/share)
pub ssn2vec_map: HashMap<SMBCommonHdr, Vec<u8>>,
@ -777,6 +778,9 @@ pub struct SMBState<> {
/// them while inspecting DCERPC REQUEST txs
pub dcerpc_ifaces: Option<Vec<DCERPCIface>>,
pub max_read_size: u32,
pub max_write_size: u32,
/// Timestamp in seconds of last update. This is packet time,
/// potentially coming from pcaps.
ts: u64,
@ -818,6 +822,7 @@ impl SMBState {
dialect_vec: None,
dcerpc_ifaces: None,
ts: 0,
..Default::default()
}
}

@ -128,6 +128,12 @@ pub fn smb2_read_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
return;
}
if state.max_read_size > 0 && rd.len > state.max_read_size {
state.set_event(SMBEvent::ReadResponseTooLarge);
state.set_skip(Direction::ToClient, rd.len, rd.data.len() as u32);
return;
}
SCLogDebug!("SMBv2: read response => {:?}", rd);
// get the request info. If we don't have it, there is nothing
@ -245,6 +251,12 @@ pub fn smb2_write_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
}
match parse_smb2_request_write(r.data) {
Ok((_, wr)) => {
if state.max_read_size != 0 && wr.wr_len > state.max_write_size {
state.set_event(SMBEvent::WriteRequestTooLarge);
state.set_skip(Direction::ToServer, wr.wr_len, wr.data.len() as u32);
return;
}
/* update key-guid map */
let guid_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GUID);
state.ssn2vec_map.insert(guid_key, wr.guid.to_vec());
@ -480,13 +492,17 @@ pub fn smb2_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
SMB2_COMMAND_READ => {
match parse_smb2_request_read(r.data) {
Ok((_, rd)) => {
SCLogDebug!("SMBv2 READ: GUID {:?} requesting {} bytes at offset {}",
rd.guid, rd.rd_len, rd.rd_offset);
if state.max_read_size != 0 && rd.rd_len > state.max_read_size {
events.push(SMBEvent::ReadRequestTooLarge);
} else {
SCLogDebug!("SMBv2 READ: GUID {:?} requesting {} bytes at offset {}",
rd.guid, rd.rd_len, rd.rd_offset);
// store read guid,offset in map
let guid_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_OFFSET);
let guidoff = SMBFileGUIDOffset::new(rd.guid.to_vec(), rd.rd_offset);
state.ssn2vecoffset_map.insert(guid_key, guidoff);
// store read guid,offset in map
let guid_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_OFFSET);
let guidoff = SMBFileGUIDOffset::new(rd.guid.to_vec(), rd.rd_offset);
state.ssn2vecoffset_map.insert(guid_key, guidoff);
}
},
_ => {
events.push(SMBEvent::MalformedData);
@ -767,6 +783,9 @@ pub fn smb2_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
SCLogDebug!("SERVER dialect => {}", &smb2_dialect_string(rd.dialect));
state.dialect = rd.dialect;
state.max_read_size = rd.max_read_size;
state.max_write_size = rd.max_write_size;
let found2 = match state.get_negotiate_tx(2) {
Some(tx) => {
if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data {

@ -157,6 +157,9 @@ pub fn parse_smb2_request_negotiate_protocol(i: &[u8]) -> IResult<&[u8], Smb2Neg
pub struct Smb2NegotiateProtocolResponseRecord<'a> {
pub dialect: u16,
pub server_guid: &'a[u8],
pub max_trans_size: u32,
pub max_read_size: u32,
pub max_write_size: u32,
}
pub fn parse_smb2_response_negotiate_protocol(i: &[u8]) -> IResult<&[u8], Smb2NegotiateProtocolResponseRecord> {
@ -165,9 +168,16 @@ pub fn parse_smb2_response_negotiate_protocol(i: &[u8]) -> IResult<&[u8], Smb2Ne
let (i, dialect) = le_u16(i)?;
let (i, _ctx_cnt) = le_u16(i)?;
let (i, server_guid) = take(16_usize)(i)?;
let (i, _capabilities) = le_u32(i)?;
let (i, max_trans_size) = le_u32(i)?;
let (i, max_read_size) = le_u32(i)?;
let (i, max_write_size) = le_u32(i)?;
let record = Smb2NegotiateProtocolResponseRecord {
dialect,
server_guid
server_guid,
max_trans_size,
max_read_size,
max_write_size
};
Ok((i, record))
}
@ -178,6 +188,9 @@ pub fn parse_smb2_response_negotiate_protocol_error(i: &[u8]) -> IResult<&[u8],
let record = Smb2NegotiateProtocolResponseRecord {
dialect: 0,
server_guid: &[],
max_trans_size: 0,
max_read_size: 0,
max_write_size: 0
};
Ok((i, record))
}

Loading…
Cancel
Save