From cbf43996eab1c067d58f1418fd0a80e700dcfe35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20P=C3=A9rez=20Gonz=C3=A1lez?= Date: Thu, 28 Apr 2022 12:57:51 +0200 Subject: [PATCH 1/4] smb: add smb.version keyword Ticket: #5075 --- rust/src/smb/detect.rs | 70 +++++++++++++++ src/Makefile.am | 2 + src/detect-engine-register.c | 3 + src/detect-engine-register.h | 1 + src/detect-smb-version.c | 159 +++++++++++++++++++++++++++++++++++ src/detect-smb-version.h | 25 ++++++ 6 files changed, 260 insertions(+) create mode 100644 src/detect-smb-version.c create mode 100644 src/detect-smb-version.h diff --git a/rust/src/smb/detect.rs b/rust/src/smb/detect.rs index c85a6f59ce33..3445274bbcaf 100644 --- a/rust/src/smb/detect.rs +++ b/rust/src/smb/detect.rs @@ -21,6 +21,9 @@ use crate::smb::smb::*; use crate::dcerpc::detect::{DCEIfaceData, DCEOpnumData, DETECT_DCE_OPNUM_RANGE_UNINITIALIZED}; use crate::dcerpc::dcerpc::DCERPC_TYPE_REQUEST; use crate::detect::uint::detect_match_uint; +use std::ffi::CStr; +use std::os::raw::{c_char, c_void}; +use crate::smb::smb::SMBTransaction; #[no_mangle] pub unsafe extern "C" fn rs_smb_tx_get_share(tx: &mut SMBTransaction, @@ -192,3 +195,70 @@ pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_domain(tx: &mut SMBTransaction, *buffer_len = 0; return 0; } + +#[no_mangle] +pub unsafe extern "C" fn rs_smb_version_match( + tx: &mut SMBTransaction, version_data: &mut u8, +) -> u8 { + + let version = tx.vercmd.get_version(); + if version == *version_data { + return 1; + } + + return 0; +} + + +#[no_mangle] +pub unsafe extern "C" fn rs_smb_version_parse(carg: *const c_char) -> *mut c_void { + if carg.is_null() { + return std::ptr::null_mut(); + } + + if let Ok(arg) = CStr::from_ptr(carg).to_str() { + if let Ok(detect) = parse_version_data(arg) { + return Box::into_raw(Box::new(detect)) as *mut _; + } + } + + return std::ptr::null_mut(); +} + +#[no_mangle] +pub unsafe extern "C" fn rs_smb_version_free(ptr: *mut c_void) { + if ptr != std::ptr::null_mut() { + std::mem::drop(Box::from_raw(ptr as *mut u8)); + } +} + +fn parse_version_data(arg: &str) -> Result { + let arg = arg.trim(); + let version = u8::from_str_radix(&arg, 10).map_err(|_| ())?; + + if version != 1 && version != 2 { + return Err(()); + } + + return Ok(version); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_cmd_data() { + assert_eq!(Err(()), parse_version_data("0")); + assert_eq!(1u8, parse_version_data("1").unwrap()); + assert_eq!(2u8, parse_version_data("2").unwrap()); + assert_eq!(Err(()), parse_version_data("3")); + } + + #[test] + fn test_parse_cmd_data_with_spaces() { + assert_eq!(1u8, parse_version_data(" 1").unwrap()); + assert_eq!(2u8, parse_version_data(" 2 ").unwrap()); + } + +} diff --git a/src/Makefile.am b/src/Makefile.am index 48a5ce850ce2..a5c79cf48555 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -292,6 +292,7 @@ noinst_HEADERS = \ detect-sip-uri.h \ detect-smb-ntlmssp.h \ detect-smb-share.h \ + detect-smb-version.h \ detect-snmp-community.h \ detect-snmp-pdu_type.h \ detect-snmp-usm.h \ @@ -901,6 +902,7 @@ libsuricata_c_a_SOURCES = \ detect-sip-uri.c \ detect-smb-ntlmssp.c \ detect-smb-share.c \ + detect-smb-version.c \ detect-snmp-community.c \ detect-snmp-pdu_type.c \ detect-snmp-usm.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index df6e4a738ffc..95a759d0b3da 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -76,6 +76,7 @@ #include "detect-config.h" #include "detect-smb-share.h" +#include "detect-smb-version.h" #include "detect-base64-decode.h" #include "detect-base64-data.h" @@ -601,6 +602,8 @@ void SigTableSetup(void) DetectSmbShareRegister(); DetectSmbNtlmsspUserRegister(); DetectSmbNtlmsspDomainRegister(); + DetectSmbVersionRegister(); + DetectTlsRegister(); DetectTlsValidityRegister(); DetectTlsVersionRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 7d6c457ef9b0..249867877482 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -197,6 +197,7 @@ enum DetectKeywordId { DETECT_SMB_SHARE, DETECT_SMB_NTLMSSP_USER, DETECT_SMB_NTLMSSP_DOMAIN, + DETECT_SMB_VERSION, DETECT_ASN1, diff --git a/src/detect-smb-version.c b/src/detect-smb-version.c new file mode 100644 index 000000000000..8589a632dfdf --- /dev/null +++ b/src/detect-smb-version.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2022-2023 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. + */ + +/** + * \file + * + * \author Eloy PĂ©rez + * \author Jason Taylor + * + * Implements the smb.version keyword + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "detect-smb-version.h" +#include "rust.h" + +#define BUFFER_NAME "smb_version" +#define KEYWORD_NAME "smb.version" +#define KEYWORD_ID DETECT_SMB_VERSION + +static int g_smb_version_list_id = 0; + +static void DetectSmbVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + + SCLogDebug("smb_version: DetectSmbVersionFree"); + rs_smb_version_free(ptr); +} + +/** + * \brief Creates a SigMatch for the "smb.version" keyword being sent as argument, + * and appends it to the rs_smb_version_match Signature(s). + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 on success, -1 on failure + */ + +static int DetectSmbVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + SCLogDebug("smb_version: DetectSmbVersionSetup"); + + if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) + return -1; + + if (arg == NULL) { + SCLogError("Error parsing smb.version option in signature, it needs a value"); + return -1; + } + + void *dod = rs_smb_version_parse(arg); + if (dod == NULL) { + SCLogError("Error parsing smb.version option in signature"); + return -1; + } + + if (DetectGetLastSMFromLists(s, DETECT_SMB_VERSION, -1)) { + SCLogError("Can't use 2 or more smb.version declarations in " + "the same sig. Invalidating signature."); + return -1; + } + + SigMatch *sm = SigMatchAlloc(); + + if (sm == NULL) { + DetectSmbVersionFree(de_ctx, dod); + return -1; + } + + sm->type = DETECT_SMB_VERSION; + sm->ctx = dod; + + SigMatchAppendSMToList(s, sm, g_smb_version_list_id); + return 0; +} + +/** + * \brief App layer match function for the "smb.version" keyword. + * + * \param t Pointer to the ThreadVars instance. + * \param det_ctx Pointer to the DetectEngineThreadCtx. + * \param f Pointer to the flow. + * \param flags Pointer to the flags indicating the flow direction. + * \param state Pointer to the app layer state data. + * \param s Pointer to the Signature instance. + * \param m Pointer to the SigMatch. + * + * \retval 1 On Match. + * \retval 0 On no match. + */ + +static int DetectSmbVersionMatchRust(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + + SCLogDebug("smb_version: DetectSmbVersionMatchRust"); + + int matchvalue = rs_smb_version_match(txv, (void *)m); + + if (matchvalue != 1) { + SCLogDebug("rs_smb_version_match: didn't match"); + SCReturnInt(0); + } else { + SCLogDebug("rs_smb_version_match: matched!"); + return matchvalue; + } +} + +/** + * \brief Registers the keyword handlers for the "smb_version" keyword. + */ + +void DetectSmbVersionRegister(void) +{ + sigmatch_table[DETECT_SMB_VERSION].name = KEYWORD_NAME; + sigmatch_table[DETECT_SMB_VERSION].Setup = DetectSmbVersionSetup; + sigmatch_table[DETECT_SMB_VERSION].Match = NULL; + sigmatch_table[DETECT_SMB_VERSION].AppLayerTxMatch = DetectSmbVersionMatchRust; + sigmatch_table[DETECT_SMB_VERSION].Free = DetectSmbVersionFree; + sigmatch_table[DETECT_SMB_VERSION].desc = "smb keyword to match on SMB version"; + sigmatch_table[DETECT_FLOW_AGE].url = "/rules/smb-keywords.html#smb-version"; + + DetectAppLayerInspectEngineRegister2( + BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2( + BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); + + g_smb_version_list_id = DetectBufferTypeRegister(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} \ No newline at end of file diff --git a/src/detect-smb-version.h b/src/detect-smb-version.h new file mode 100644 index 000000000000..11bdb1feae26 --- /dev/null +++ b/src/detect-smb-version.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2022-2023 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. + */ + +#ifndef __DETECT_SMB_VERSION_H__ +#define __DETECT_SMB_VERSION_H__ + +/** \brief registers the keyword into the engine. Called from + * detect.c::SigTableSetup() */ +void DetectSmbVersionRegister(void); + +#endif /* __DETECT_SMB_VERSION_H__ */ \ No newline at end of file From 12db93a5c50d7355998448a731cebec4ef4f2dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20P=C3=A9rez=20Gonz=C3=A1lez?= Date: Thu, 28 Apr 2022 12:59:03 +0200 Subject: [PATCH 2/4] smb: add smb.keyword documentation --- doc/userguide/rules/smb-keywords.rst | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/doc/userguide/rules/smb-keywords.rst b/doc/userguide/rules/smb-keywords.rst index 02cf190bc794..80debd3ca300 100644 --- a/doc/userguide/rules/smb-keywords.rst +++ b/doc/userguide/rules/smb-keywords.rst @@ -58,3 +58,45 @@ Examples:: ``smb.ntlmssp_domain`` is a 'sticky buffer'. ``smb.ntlmssp_domain`` can be used as ``fast_pattern``. + +smb.version +-------------- + +Used to match the SMB version, that can be 1 or 2. + +Example signatures:: + + alert smb any any -> any any (msg: "SMB1 version rule"; smb.version: 1; sid: 44;) + alert smb any any -> any any (msg: "SMB2 version rule"; smb.version: 2; sid: 45;) + +Matching in transition from SMBv1 to SMBv2 +******************************************** + +In the initial negotiation protocol request, a client supporting SMBv1 and SMBv2 can send an initial SMBv1 request and receive an SMBv2 response from server, indicating that SMBv2 will be used. + +This first SMBv2 response made by the server will match as SMBv1, since the entire transaction will be considered a SMBv1 transaction. + +Does `smb.version` match SMBv3? +**************************************** + +Yes, it will match SMBv3 messages using `smb.version: 2;`, which will match SMBv2 and SMBv3, since they use the same version identifier in the SMB header. + +This keyword will use the Protocol ID specified in SMB header to determine the version. Here is a summary of the Protocol ID codes: + +- 0xffSMB is SMB1 `header `_ +- 0xfeSMB is SMB2 `normal header `_ (can be `sync `_ or `async `_) +- 0xfdSMB is SMB2 `transform header `_. This is only valid for the SMB 3.x dialect family. +- 0xfcSMB is SMB2 `transform compression header `_ (can be `chained `_ or `unchained `_). These ones requires the use of 3.1.1 dialect. + +The Protocol ID in header distinguishes only SMB1 and SMB2 since they are totally different protocols with total different message formats, types and implementation. + +On the other hand SMB3 is more an extension for SMB2. When using SMB2 we can select one of the following dialects for the conversation between client and server: + +- 2.0.2 +- 2.1 +- 3.0 +- 3.0.2 +- 3.1.1 + +We say we are using SMB3 when we select a 3.x dialect for the conversation, so you can use SMB3.0, SMB3.0.2 or SMB3.1.1. The higher you choose, the more capabilities you have, but the message syntax and message command number remains the same. + From 28f85ad6a76ad13e2ff2401f3b67411a0373c490 Mon Sep 17 00:00:00 2001 From: jason taylor Date: Wed, 30 Aug 2023 18:44:07 +0000 Subject: [PATCH 3/4] rust: fix rustfmt warnings for smb detect Signed-off-by: jason taylor --- rust/src/smb/detect.rs | 82 ++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/rust/src/smb/detect.rs b/rust/src/smb/detect.rs index 3445274bbcaf..4bc80c919ede 100644 --- a/rust/src/smb/detect.rs +++ b/rust/src/smb/detect.rs @@ -15,22 +15,20 @@ * 02110-1301, USA. */ -use std::ptr; use crate::core::*; -use crate::smb::smb::*; -use crate::dcerpc::detect::{DCEIfaceData, DCEOpnumData, DETECT_DCE_OPNUM_RANGE_UNINITIALIZED}; use crate::dcerpc::dcerpc::DCERPC_TYPE_REQUEST; +use crate::dcerpc::detect::{DCEIfaceData, DCEOpnumData, DETECT_DCE_OPNUM_RANGE_UNINITIALIZED}; use crate::detect::uint::detect_match_uint; +use crate::smb::smb::SMBTransaction; +use crate::smb::smb::*; use std::ffi::CStr; use std::os::raw::{c_char, c_void}; -use crate::smb::smb::SMBTransaction; +use std::ptr; #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_share(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern "C" fn rs_smb_tx_get_share( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::TREECONNECT(ref x)) = tx.type_data { SCLogDebug!("is_pipe {}", x.is_pipe); if !x.is_pipe { @@ -46,11 +44,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_share(tx: &mut SMBTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_named_pipe(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern "C" fn rs_smb_tx_get_named_pipe( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::TREECONNECT(ref x)) = tx.type_data { SCLogDebug!("is_pipe {}", x.is_pipe); if x.is_pipe { @@ -66,12 +62,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_named_pipe(tx: &mut SMBTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_stub_data(tx: &mut SMBTransaction, - direction: u8, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern "C" fn rs_smb_tx_get_stub_data( + tx: &mut SMBTransaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::DCERPC(ref x)) = tx.type_data { let vref = if direction == Direction::ToServer as u8 { &x.stub_data_ts @@ -91,10 +84,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_stub_data(tx: &mut SMBTransaction, } #[no_mangle] -pub extern "C" fn rs_smb_tx_match_dce_opnum(tx: &mut SMBTransaction, - dce_data: &mut DCEOpnumData) - -> u8 -{ +pub extern "C" fn rs_smb_tx_match_dce_opnum( + tx: &mut SMBTransaction, dce_data: &mut DCEOpnumData, +) -> u8 { SCLogDebug!("rs_smb_tx_get_dce_opnum: start"); if let Some(SMBTransactionTypeData::DCERPC(ref x)) = tx.type_data { if x.req_cmd == DCERPC_TYPE_REQUEST { @@ -118,17 +110,13 @@ pub extern "C" fn rs_smb_tx_match_dce_opnum(tx: &mut SMBTransaction, * dce_opnum and dce_stub_data) * - only match on approved ifaces (so ack_result == 0) */ #[no_mangle] -pub extern "C" fn rs_smb_tx_get_dce_iface(state: &mut SMBState, - tx: &mut SMBTransaction, - dce_data: &mut DCEIfaceData) - -> u8 -{ +pub extern "C" fn rs_smb_tx_get_dce_iface( + state: &mut SMBState, tx: &mut SMBTransaction, dce_data: &mut DCEIfaceData, +) -> u8 { let if_uuid = dce_data.if_uuid.as_slice(); let is_dcerpc_request = match tx.type_data { - Some(SMBTransactionTypeData::DCERPC(ref x)) => { - x.req_cmd == DCERPC_TYPE_REQUEST - }, - _ => { false }, + Some(SMBTransactionTypeData::DCERPC(ref x)) => x.req_cmd == DCERPC_TYPE_REQUEST, + _ => false, }; if !is_dcerpc_request { return 0; @@ -137,13 +125,18 @@ pub extern "C" fn rs_smb_tx_get_dce_iface(state: &mut SMBState, Some(ref x) => x, _ => { return 0; - }, + } }; SCLogDebug!("looking for UUID {:?}", if_uuid); for i in ifaces { - SCLogDebug!("stored UUID {:?} acked {} ack_result {}", i, i.acked, i.ack_result); + SCLogDebug!( + "stored UUID {:?} acked {} ack_result {}", + i, + i.acked, + i.ack_result + ); if i.acked && i.ack_result == 0 && i.uuid == if_uuid { if let Some(x) = &dce_data.du16 { @@ -159,11 +152,9 @@ pub extern "C" fn rs_smb_tx_get_dce_iface(state: &mut SMBState, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_user(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_user( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::SESSIONSETUP(ref x)) = tx.type_data { if let Some(ref ntlmssp) = x.ntlmssp { *buffer = ntlmssp.user.as_ptr(); @@ -178,11 +169,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_user(tx: &mut SMBTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_domain(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_domain( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::SESSIONSETUP(ref x)) = tx.type_data { if let Some(ref ntlmssp) = x.ntlmssp { *buffer = ntlmssp.domain.as_ptr(); @@ -200,7 +189,6 @@ pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_domain(tx: &mut SMBTransaction, pub unsafe extern "C" fn rs_smb_version_match( tx: &mut SMBTransaction, version_data: &mut u8, ) -> u8 { - let version = tx.vercmd.get_version(); if version == *version_data { return 1; @@ -209,7 +197,6 @@ pub unsafe extern "C" fn rs_smb_version_match( return 0; } - #[no_mangle] pub unsafe extern "C" fn rs_smb_version_parse(carg: *const c_char) -> *mut c_void { if carg.is_null() { @@ -260,5 +247,4 @@ mod tests { assert_eq!(1u8, parse_version_data(" 1").unwrap()); assert_eq!(2u8, parse_version_data(" 2 ").unwrap()); } - } From d32e5cb56830683d0b5fb34750ff5b9327ca1570 Mon Sep 17 00:00:00 2001 From: jason taylor Date: Wed, 30 Aug 2023 18:50:19 +0000 Subject: [PATCH 4/4] detect: update smb.version keyword Signed-off-by: jason taylor --- doc/userguide/rules/smb-keywords.rst | 21 ++++++++++++--------- rust/src/smb/detect.rs | 21 +++++++++++---------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/doc/userguide/rules/smb-keywords.rst b/doc/userguide/rules/smb-keywords.rst index 80debd3ca300..fd0e0a90bcbb 100644 --- a/doc/userguide/rules/smb-keywords.rst +++ b/doc/userguide/rules/smb-keywords.rst @@ -59,27 +59,29 @@ Examples:: ``smb.ntlmssp_domain`` can be used as ``fast_pattern``. + smb.version --------------- +------------ -Used to match the SMB version, that can be 1 or 2. +Keyword to match on SMB version. + +Examples:: -Example signatures:: + alert smb $HOME_NET any -> any any (msg:"SMBv1 version rule"; smb.version:1; sid:1;) + alert smb $HOME_NET any -> any any (msg:"SMBv2 version rule"; smb.version:2; sid:2;) - alert smb any any -> any any (msg: "SMB1 version rule"; smb.version: 1; sid: 44;) - alert smb any any -> any any (msg: "SMB2 version rule"; smb.version: 2; sid: 45;) Matching in transition from SMBv1 to SMBv2 -******************************************** +****************************************** In the initial negotiation protocol request, a client supporting SMBv1 and SMBv2 can send an initial SMBv1 request and receive an SMBv2 response from server, indicating that SMBv2 will be used. This first SMBv2 response made by the server will match as SMBv1, since the entire transaction will be considered a SMBv1 transaction. -Does `smb.version` match SMBv3? -**************************************** +Will `smb.version` match SMBv3 traffic? +*************************************** -Yes, it will match SMBv3 messages using `smb.version: 2;`, which will match SMBv2 and SMBv3, since they use the same version identifier in the SMB header. +Yes, it will match SMBv3 messages using `smb.version:2;`, which will match SMBv2 and SMBv3, since they use the same version identifier in the SMB header. This keyword will use the Protocol ID specified in SMB header to determine the version. Here is a summary of the Protocol ID codes: @@ -100,3 +102,4 @@ On the other hand SMB3 is more an extension for SMB2. When using SMB2 we can sel We say we are using SMB3 when we select a 3.x dialect for the conversation, so you can use SMB3.0, SMB3.0.2 or SMB3.1.1. The higher you choose, the more capabilities you have, but the message syntax and message command number remains the same. +SMB version and dialect are separate components. In the case of SMBv3 for instance, the SMB version will be 2 but the dialect will be 3.x. \ No newline at end of file diff --git a/rust/src/smb/detect.rs b/rust/src/smb/detect.rs index 4bc80c919ede..698d741367df 100644 --- a/rust/src/smb/detect.rs +++ b/rust/src/smb/detect.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Open Information Security Foundation +/* Copyright (C) 2017-2023 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 @@ -190,6 +190,7 @@ pub unsafe extern "C" fn rs_smb_version_match( tx: &mut SMBTransaction, version_data: &mut u8, ) -> u8 { let version = tx.vercmd.get_version(); + SCLogDebug!("smb_version: version returned: {}", version); if version == *version_data { return 1; } @@ -212,16 +213,11 @@ pub unsafe extern "C" fn rs_smb_version_parse(carg: *const c_char) -> *mut c_voi return std::ptr::null_mut(); } -#[no_mangle] -pub unsafe extern "C" fn rs_smb_version_free(ptr: *mut c_void) { - if ptr != std::ptr::null_mut() { - std::mem::drop(Box::from_raw(ptr as *mut u8)); - } -} - fn parse_version_data(arg: &str) -> Result { let arg = arg.trim(); - let version = u8::from_str_radix(&arg, 10).map_err(|_| ())?; + let version: u8 = arg.parse().map_err(|_| ())?; + + SCLogDebug!("smb_version: sig parse arg: {} version: {}", arg, version); if version != 1 && version != 2 { return Err(()); @@ -230,6 +226,11 @@ fn parse_version_data(arg: &str) -> Result { return Ok(version); } +#[no_mangle] +pub unsafe extern "C" fn rs_smb_version_free(ptr: *mut c_void) { + std::mem::drop(Box::from_raw(ptr as *mut u8)); +} + #[cfg(test)] mod tests { use super::*; @@ -247,4 +248,4 @@ mod tests { assert_eq!(1u8, parse_version_data(" 1").unwrap()); assert_eq!(2u8, parse_version_data(" 2 ").unwrap()); } -} +} \ No newline at end of file