From 1b6615da0175b0a8b7744f27de957cf0bf4c7b2d Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 31 Mar 2022 12:45:07 -0600 Subject: [PATCH] smb: protocol detection on pattern without midstream To recognize a protocol, Suricata first looks for patterns, which can be confirmed by a probing parser. If this does not work, Suricata can try to run some probing parsers on some ports. This is the case for SMB. This commit makes handling the confirming and the probing paser differently even if they share much code. The confirmation parser knows that a pattern has been found. So, it must not do the midstream case of looking for this pattern in the whole buffer, but only check it at the beginning. But it must reverse direction if needed. Ticket #4849 Backported manually by jason.ish@oisf.net. --- rust/src/smb/smb.rs | 48 ++++++++++++++++++++++++++++++++++++--------- src/app-layer-smb.c | 29 +++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index c25c3723a3..1882680555 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -58,6 +58,8 @@ pub static mut SMB_CFG_MAX_WRITE_SIZE: u32 = 0; pub static mut SMB_CFG_MAX_WRITE_QUEUE_SIZE: u32 = 0; pub static mut SMB_CFG_MAX_WRITE_QUEUE_CNT: u32 = 0; +pub const MIN_REC_SIZE: u16 = 32 + 4; // SMB hdr + nbss hdr + pub static mut SURICATA_SMB_FILE_CONFIG: Option<&'static SuricataFileContext> = None; #[no_mangle] @@ -1950,16 +1952,18 @@ pub extern "C" fn rs_smb_parse_response_tcp_gap( return -1; } -// probing parser -// return 1 if found, 0 is not found -#[no_mangle] -pub extern "C" fn rs_smb_probe_tcp(direction: u8, - input: *const u8, len: u32, - rdir: *mut u8) - -> i8 +fn smb_probe_tcp(direction: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> i8 { - let slice = build_slice!(input, len as usize); - match search_smb_record(slice) { + let r = if begins { + if slice[0] == NBSS_MSGTYPE_SESSION_MESSAGE { + Ok((&slice[..4], &slice[4..])) + } else { + Err(nom::Err::Error(error_position!(slice, nom::ErrorKind::Eof))) + } + } else { + search_smb_record(slice) + }; + match r { Ok((_, ref data)) => { SCLogDebug!("smb found"); match parse_smb_version(data) { @@ -2052,6 +2056,32 @@ pub extern "C" fn rs_smb_probe_tcp(direction: u8, return -1 } +// probing confirmation parser +// return 1 if found, 0 is not found +#[no_mangle] +pub extern "C" fn rs_smb_probe_begins_tcp(direction: u8, input: *const u8, len: u32, rdir: *mut u8) + -> i8 +{ + if len < MIN_REC_SIZE as u32 { + return 0; + } + let slice = build_slice!(input, len as usize); + return smb_probe_tcp(direction, slice, rdir, true); +} + +// probing confirmation parser +// return 1 if found, 0 is not found +#[no_mangle] +pub extern "C" fn rs_smb_probe_tcp(direction: u8, input: *const u8, len: u32, rdir: *mut u8) + -> i8 +{ + if len < MIN_REC_SIZE as u32 { + return 0; + } + let slice = build_slice!(input, len as usize); + return smb_probe_tcp(direction, slice, rdir, false); +} + #[no_mangle] pub extern "C" fn rs_smb_state_get_tx_count(state: &mut SMBState) -> u64 diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 54880f5f84..f150218153 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -98,6 +98,27 @@ static uint16_t SMBTCPProbe(Flow *f, uint8_t direction, } } +static uint16_t SMBTCPProbeBegins(Flow *f, uint8_t direction, + const uint8_t *input, uint32_t len, uint8_t *rdir) +{ + SCLogDebug("SMBTCPProbeBegins"); + + if (len < MIN_REC_SIZE) { + return ALPROTO_UNKNOWN; + } + + const int r = rs_smb_probe_begins_tcp(direction, input, len, rdir); + switch (r) { + case 1: + return ALPROTO_SMB; + case 0: + return ALPROTO_UNKNOWN; + case -1: + default: + return ALPROTO_FAILED; + } +} + /** \internal * \brief as SMB3 records have no direction indicator, fall * back to the port numbers for a hint @@ -223,18 +244,18 @@ static int SMBRegisterPatternsForProtocolDetection(void) int r = 0; /* SMB1 */ r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - "|ff|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbe, + "|ff|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbeBegins, MIN_REC_SIZE, MIN_REC_SIZE); r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - "|ff|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbe, + "|ff|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbeBegins, MIN_REC_SIZE, MIN_REC_SIZE); /* SMB2/3 */ r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - "|fe|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbe, + "|fe|SMB", 8, 4, STREAM_TOSERVER, SMBTCPProbeBegins, MIN_REC_SIZE, MIN_REC_SIZE); r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - "|fe|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbe, + "|fe|SMB", 8, 4, STREAM_TOCLIENT, SMBTCPProbeBegins, MIN_REC_SIZE, MIN_REC_SIZE); /* SMB3 encrypted records */ -- 2.47.2