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

(cherry picked from commit f28888513a)
pull/7288/head
Victor Julien 4 years ago
parent 2ba9ad53eb
commit 9f969e2545

@ -30,6 +30,13 @@ pub enum SMBEvent {
FileOverlap = 7,
RequestToClient = 8,
ResponseToServer = 9,
/// READ request asking for more than `max_read_size`
ReadRequestTooLarge = 10,
/// READ response bigger than `max_read_size`
ReadResponseTooLarge = 11,
/// WRITE request for more than `max_write_size`
WriteRequestTooLarge = 12,
}
impl SMBEvent {
@ -45,6 +52,9 @@ impl SMBEvent {
7 => Some(SMBEvent::FileOverlap),
8 => Some(SMBEvent::RequestToClient),
9 => Some(SMBEvent::ResponseToServer),
10 => Some(SMBEvent::ReadRequestTooLarge),
11 => Some(SMBEvent::ReadResponseTooLarge),
12 => Some(SMBEvent::WriteRequestTooLarge),
_ => None,
}
}
@ -63,6 +73,9 @@ pub fn smb_str_to_event(instr: &str) -> i32 {
"file_overlap" => SMBEvent::FileOverlap as i32,
"request_to_client" => SMBEvent::RequestToClient as i32,
"response_to_server" => SMBEvent::ResponseToServer as i32,
"read_request_too_large" => SMBEvent::ReadRequestTooLarge as i32,
"read_response_too_large" => SMBEvent::ReadResponseTooLarge as i32,
"write_request_too_large" => SMBEvent::WriteRequestTooLarge as i32,
_ => -1,
}
}

@ -796,6 +796,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,
@ -831,6 +834,8 @@ impl SMBState {
dialect_vec: None,
dcerpc_ifaces: None,
ts: 0,
max_read_size: 0,
max_write_size: 0,
}
}
@ -2186,6 +2191,9 @@ pub extern "C" fn rs_smb_state_get_event_info_by_id(event_id: std::os::raw::c_in
SMBEvent::FileOverlap => { "file_overlap\0" },
SMBEvent::RequestToClient => { "request_to_client\0" },
SMBEvent::ResponseToServer => { "response_to_server\0" },
SMBEvent::ReadRequestTooLarge => { "read_request_too_large\0" },
SMBEvent::ReadResponseTooLarge => { "read_response_too_large\0" },
SMBEvent::WriteRequestTooLarge => { "write_request_too_large\0" },
};
unsafe{
*event_name = estr.as_ptr() as *const std::os::raw::c_char;

@ -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(STREAM_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
@ -247,6 +253,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(STREAM_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());
@ -459,13 +471,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);
@ -746,6 +762,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 {

@ -154,6 +154,9 @@ named!(pub parse_smb2_request_negotiate_protocol<Smb2NegotiateProtocolRequestRec
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,
}
named!(pub parse_smb2_response_negotiate_protocol<Smb2NegotiateProtocolResponseRecord>,
@ -163,9 +166,16 @@ named!(pub parse_smb2_response_negotiate_protocol<Smb2NegotiateProtocolResponseR
>> dialect: le_u16
>> _ctx_cnt: le_u16
>> server_guid: take!(16)
>> _capabilities: le_u32
>> max_trans_size: le_u32
>> max_read_size: le_u32
>> max_write_size: le_u32
>> (Smb2NegotiateProtocolResponseRecord {
dialect,
server_guid
server_guid,
max_trans_size,
max_read_size,
max_write_size
})
));
@ -176,10 +186,12 @@ named!(pub parse_smb2_response_negotiate_protocol_error<Smb2NegotiateProtocolRes
>> (Smb2NegotiateProtocolResponseRecord {
dialect: 0,
server_guid: &[],
max_trans_size: 0,
max_read_size: 0,
max_write_size: 0
})
));
#[derive(Debug,PartialEq)]
pub struct Smb2SessionSetupRequestRecord<'a> {
pub data: &'a[u8],

Loading…
Cancel
Save