From 0c55fe3515413fda036d701e9b23c79173fe1f8c Mon Sep 17 00:00:00 2001 From: Sascha Steinbiss Date: Wed, 11 Oct 2023 22:25:46 +0200 Subject: [PATCH] detect: add mqtt.connect.protocolstring Ticket: OISF#6396 --- doc/userguide/rules/mqtt-keywords.rst | 13 ++++ rust/src/mqtt/detect.rs | 20 +++++ src/Makefile.am | 2 + src/detect-engine-register.c | 2 + src/detect-engine-register.h | 1 + src/detect-mqtt-connect-protocol-string.c | 94 +++++++++++++++++++++++ src/detect-mqtt-connect-protocol-string.h | 29 +++++++ 7 files changed, 161 insertions(+) create mode 100644 src/detect-mqtt-connect-protocol-string.c create mode 100644 src/detect-mqtt-connect-protocol-string.h diff --git a/doc/userguide/rules/mqtt-keywords.rst b/doc/userguide/rules/mqtt-keywords.rst index 21776ac357..058a17b7ff 100644 --- a/doc/userguide/rules/mqtt-keywords.rst +++ b/doc/userguide/rules/mqtt-keywords.rst @@ -163,6 +163,19 @@ Examples:: ``mqtt.connect.password`` is a 'sticky buffer' and can be used as ``fast_pattern``. +mqtt.connect.protocol_string +---------------------------- + +Match on the protocol string in the MQTT CONNECT message. In contrast to ``mqtt.protocol_version`` this is a property that is only really relevant in the initial CONNECT communication and never used again; hence it is organized under ``mqtt.connect``. + +Examples:: + + mqtt.connect.protocol_string; content:"MQTT"; + mqtt.connect.protocol_string; content:"MQIsdp"; + +``mqtt.connect.protocol_string`` is a 'sticky buffer' and can be used as ``fast_pattern``. + + mqtt.connect.username --------------------- diff --git a/rust/src/mqtt/detect.rs b/rust/src/mqtt/detect.rs index b47a84f744..df0c78e849 100644 --- a/rust/src/mqtt/detect.rs +++ b/rust/src/mqtt/detect.rs @@ -231,6 +231,26 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willmessage( return 0; } +#[no_mangle] +pub unsafe extern "C" fn rs_mqtt_tx_get_connect_protocol_string( + tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { + for msg in tx.msg.iter() { + if let MQTTOperation::CONNECT(ref cv) = msg.op { + let p = &cv.protocol_string; + if !p.is_empty() { + *buffer = p.as_ptr(); + *buffer_len = p.len() as u32; + return 1; + } + } + } + + *buffer = ptr::null(); + *buffer_len = 0; + return 0; +} + #[no_mangle] pub unsafe extern "C" fn rs_mqtt_tx_get_connack_sessionpresent( tx: &MQTTTransaction, session_present: *mut bool, diff --git a/src/Makefile.am b/src/Makefile.am index a125e2a432..f8033de41b 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -250,6 +250,7 @@ noinst_HEADERS = \ detect-mqtt-connect-clientid.h \ detect-mqtt-connect-flags.h \ detect-mqtt-connect-password.h \ + detect-mqtt-connect-protocol-string.h \ detect-mqtt-connect-username.h \ detect-mqtt-connect-willmessage.h \ detect-mqtt-connect-willtopic.h \ @@ -862,6 +863,7 @@ libsuricata_c_a_SOURCES = \ detect-mqtt-connect-clientid.c \ detect-mqtt-connect-flags.c \ detect-mqtt-connect-password.c \ + detect-mqtt-connect-protocol-string.c \ detect-mqtt-connect-username.c \ detect-mqtt-connect-willmessage.c \ detect-mqtt-connect-willtopic.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index af247a1b4f..bd8f665196 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -219,6 +219,7 @@ #include "detect-mqtt-connect-clientid.h" #include "detect-mqtt-connect-username.h" #include "detect-mqtt-connect-password.h" +#include "detect-mqtt-connect-protocol-string.h" #include "detect-mqtt-connect-willtopic.h" #include "detect-mqtt-connect-willmessage.h" #include "detect-mqtt-connack-sessionpresent.h" @@ -677,6 +678,7 @@ void SigTableSetup(void) DetectMQTTConnectClientIDRegister(); DetectMQTTConnectUsernameRegister(); DetectMQTTConnectPasswordRegister(); + DetectMQTTConnectProtocolStringRegister(); DetectMQTTConnectWillTopicRegister(); DetectMQTTConnectWillMessageRegister(); DetectMQTTConnackSessionPresentRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 92acd84f04..abc1a403dd 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -299,6 +299,7 @@ enum DetectKeywordId { DETECT_AL_MQTT_CONNECT_CLIENTID, DETECT_AL_MQTT_CONNECT_USERNAME, DETECT_AL_MQTT_CONNECT_PASSWORD, + DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING, DETECT_AL_MQTT_CONNECT_WILLTOPIC, DETECT_AL_MQTT_CONNECT_WILLMESSAGE, DETECT_AL_MQTT_CONNACK_SESSION_PRESENT, diff --git a/src/detect-mqtt-connect-protocol-string.c b/src/detect-mqtt-connect-protocol-string.c new file mode 100644 index 0000000000..421b293845 --- /dev/null +++ b/src/detect-mqtt-connect-protocol-string.c @@ -0,0 +1,94 @@ +/* Copyright (C) 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. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.protocolstring sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-mqtt-connect-protocol-string.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.protocol_string" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-protocol_string" +#define BUFFER_NAME "mqtt.connect.protocol_string" +#define BUFFER_DESC "MQTT CONNECT protocol string" +static int g_buffer_id = 0; + +static int DetectMQTTConnectProtocolStringSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_protocol_string(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectProtocolStringRegister(void) +{ + /* mqtt.connect.protocol_string sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].desc = + "sticky buffer to match on the MQTT CONNECT protocol string"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].Setup = + DetectMQTTConnectProtocolStringSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-protocol-string.h b/src/detect-mqtt-connect-protocol-string.h new file mode 100644 index 0000000000..3bbb21ab10 --- /dev/null +++ b/src/detect-mqtt-connect-protocol-string.h @@ -0,0 +1,29 @@ +/* Copyright (C) 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 Sascha Steinbiss + */ + +#ifndef __DETECT_MQTT_CONNECT_PROTOCOLSTRING_H__ +#define __DETECT_MQTT_CONNECT_PROTOCOLSTRING_H__ + +void DetectMQTTConnectProtocolStringRegister(void); + +#endif /* __DETECT_MQTT_CONNECT_PROTOCOLSTRING_H__ */ -- 2.47.2