diff --git a/doc/userguide/rules/kerberos-keywords.rst b/doc/userguide/rules/kerberos-keywords.rst index b005b1def6..a52ff9f4e1 100644 --- a/doc/userguide/rules/kerberos-keywords.rst +++ b/doc/userguide/rules/kerberos-keywords.rst @@ -7,6 +7,8 @@ krb5_msg_type This keyword allows to match the Kerberos messages by its type (integer). It is possible to specify the following values defined in RFC4120: +krb5_msg_type uses :ref:`unsigned 32-bit integer `. + * 10 (AS-REQ) * 11 (AS-REP) * 12 (TGS-REQ) @@ -15,15 +17,15 @@ It is possible to specify the following values defined in RFC4120: Syntax:: - krb5_msg_type: + krb5_msg_type:(mode) Signature examples:: alert krb5 any any -> any any (msg:"Kerberos 5 AS-REQ message"; krb5_msg_type:10; sid:3; rev:1;) - alert krb5 any any -> any any (msg:"Kerberos 5 AS-REP message"; krb5_msg_type:11; sid:4; rev:1;) + alert krb5 any any -> any any (msg:"Kerberos 5 AS-REP message"; krb5_msg_type:AS_REP; sid:4; rev:1;) alert krb5 any any -> any any (msg:"Kerberos 5 TGS-REQ message"; krb5_msg_type:12; sid:5; rev:1;) alert krb5 any any -> any any (msg:"Kerberos 5 TGS-REP message"; krb5_msg_type:13; sid:6; rev:1;) - alert krb5 any any -> any any (msg:"Kerberos 5 ERROR message"; krb5_msg_type:30; sid:7; rev:1;) + alert krb5 any any -> any any (msg:"Kerberos 5 not ERROR message"; krb5_msg_type:!30; sid:7; rev:1;) .. note:: AP-REQ and AP-REP are not currently supported since those messages diff --git a/rust/src/krb/detect.rs b/rust/src/krb/detect.rs index 0b68493308..fde5af4605 100644 --- a/rust/src/krb/detect.rs +++ b/rust/src/krb/detect.rs @@ -18,8 +18,18 @@ // written by Pierre Chifflier use crate::krb::krb5::{test_weak_encryption, KRB5Transaction}; -use suricata_sys::sys::DetectEngineThreadCtx; +use suricata_sys::sys::AppProtoEnum::ALPROTO_KRB5; +use suricata_sys::sys::{ + AppProto, DetectEngineCtx, DetectEngineThreadCtx, Flow, SCDetectHelperBufferRegister, + SCDetectHelperKeywordRegister, SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, + SCSigTableAppLiteElmt, SigMatchCtx, Signature, +}; +use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER}; +use crate::detect::uint::{ + detect_parse_uint_enum, DetectUintData, SCDetectU32Free, SCDetectU32Match, +}; +use crate::detect::{SIGMATCH_INFO_ENUM_UINT, SIGMATCH_INFO_MULTI_UINT}; use kerberos_parser::krb5::EncryptionType; use nom7::branch::alt; @@ -29,14 +39,9 @@ use nom7::combinator::{all_consuming, map_res, opt}; use nom7::multi::many1; use nom7::IResult; -use std::ffi::CStr; +use std::ffi::{c_int, CStr}; use std::os::raw::c_void; -#[no_mangle] -pub unsafe extern "C" fn SCKrb5TxGetMsgType(tx: &KRB5Transaction, ptr: *mut u32) { - *ptr = tx.msg_type.0; -} - /// Get error code, if present in transaction /// Return 0 if error code was filled, else 1 #[no_mangle] @@ -345,3 +350,97 @@ mod tests { } } } + +static mut G_KRB5_MSG_TYPE_KW_ID: u16 = 0; +static mut G_KRB5_MSG_TYPE_BUFFER_ID: c_int = 0; + +// We should apply the derive on the kerberos_parser MessageType +#[repr(u32)] +#[derive(EnumStringU32)] +#[allow(non_camel_case_types)] +pub enum Krb5MessageType { + AS_REQ = 10, + AS_REP = 11, + TGS_REQ = 12, + TGS_REP = 13, + AP_REQ = 14, + AP_REP = 15, + RESERVED16 = 16, + RESERVED17 = 17, + SAFE = 20, + PRIV = 21, + CRED = 22, + ERROR = 30, +} + +unsafe extern "C" fn krb5_parse_msg_type( + ustr: *const std::os::raw::c_char, +) -> *mut DetectUintData { + let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Some(ctx) = detect_parse_uint_enum::(s) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn krb5_msg_type_setup( + de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, +) -> c_int { + if SCDetectSignatureSetAppProto(s, ALPROTO_KRB5 as AppProto) != 0 { + return -1; + } + let ctx = krb5_parse_msg_type(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SCSigMatchAppendSMToList( + de, + s, + G_KRB5_MSG_TYPE_KW_ID, + ctx as *mut SigMatchCtx, + G_KRB5_MSG_TYPE_BUFFER_ID, + ) + .is_null() + { + krb5_msg_type_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn krb5_msg_type_match( + _de: *mut DetectEngineThreadCtx, _f: *mut Flow, _flags: u8, _state: *mut c_void, + tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx, +) -> c_int { + let tx = cast_pointer!(tx, KRB5Transaction); + let ctx = cast_pointer!(ctx, DetectUintData); + // kerberos_parser crate defines MessageType as u32 and not u8... + return SCDetectU32Match(tx.msg_type.0, ctx); +} + +unsafe extern "C" fn krb5_msg_type_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectUintData); + SCDetectU32Free(ctx); +} + +#[no_mangle] +pub unsafe extern "C" fn SCDetectKrb5MsgTypeRegister() { + let kw = SCSigTableAppLiteElmt { + name: b"krb5_msg_type\0".as_ptr() as *const libc::c_char, + desc: b"match Kerberos 5 message type\0".as_ptr() as *const libc::c_char, + url: b"/rules/kerberos-keywords.html#krb5-msg-type\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(krb5_msg_type_match), + Setup: Some(krb5_msg_type_setup), + Free: Some(krb5_msg_type_free), + flags: SIGMATCH_INFO_MULTI_UINT | SIGMATCH_INFO_ENUM_UINT, + }; + G_KRB5_MSG_TYPE_KW_ID = SCDetectHelperKeywordRegister(&kw); + G_KRB5_MSG_TYPE_BUFFER_ID = SCDetectHelperBufferRegister( + b"krb5_msg_type\0".as_ptr() as *const libc::c_char, + ALPROTO_KRB5 as AppProto, + STREAM_TOCLIENT | STREAM_TOSERVER, + ); +} diff --git a/src/Makefile.am b/src/Makefile.am index a19ba29f07..91105a8a4f 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -244,7 +244,6 @@ noinst_HEADERS = \ detect-ja4-hash.h \ detect-krb5-cname.h \ detect-krb5-errcode.h \ - detect-krb5-msgtype.h \ detect-krb5-sname.h \ detect-krb5-ticket-encryption.h \ detect-l3proto.h \ @@ -845,7 +844,6 @@ libsuricata_c_a_SOURCES = \ detect-ja4-hash.c \ detect-krb5-cname.c \ detect-krb5-errcode.c \ - detect-krb5-msgtype.c \ detect-krb5-sname.c \ detect-krb5-ticket-encryption.c \ detect-l3proto.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 3f167f4b30..74e00c1595 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -198,7 +198,6 @@ #include "detect-ipv6hdr.h" #include "detect-krb5-cname.h" #include "detect-krb5-errcode.h" -#include "detect-krb5-msgtype.h" #include "detect-krb5-sname.h" #include "detect-krb5-ticket-encryption.h" #include "detect-sip-method.h" @@ -742,7 +741,7 @@ void SigTableSetup(void) DetectIpv6hdrRegister(); DetectKrb5CNameRegister(); DetectKrb5ErrCodeRegister(); - DetectKrb5MsgTypeRegister(); + SCDetectKrb5MsgTypeRegister(); DetectKrb5SNameRegister(); DetectKrb5TicketEncryptionRegister(); DetectSipMethodRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 0e5e52242c..e37adfd010 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -268,7 +268,6 @@ enum DetectKeywordId { DETECT_DNP3OBJ, DETECT_KRB5_ERRCODE, - DETECT_KRB5_MSGTYPE, DETECT_KRB5_CNAME, DETECT_KRB5_SNAME, DETECT_KRB5_TICKET_ENCRYPTION, diff --git a/src/detect-krb5-msgtype.c b/src/detect-krb5-msgtype.c deleted file mode 100644 index ab83a6b5be..0000000000 --- a/src/detect-krb5-msgtype.c +++ /dev/null @@ -1,243 +0,0 @@ -/* Copyright (C) 2018-2020 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 Pierre Chifflier - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-byte.h" - -#include "detect-parse.h" -#include "detect-engine.h" - -#include "detect-krb5-msgtype.h" - -#include "rust.h" - -/** - * \brief Regex for parsing our keyword options - */ -#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9_\\.]+\")\\s*$" -static DetectParseRegex parse_regex; - -/* Prototypes of functions registered in DetectKrb5MsgTypeRegister below */ -static int DetectKrb5MsgTypeMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); -static int DetectKrb5MsgTypeSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectKrb5MsgTypeFree (DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectKrb5MsgTypeRegisterTests (void); -#endif - -static int g_krb5_msg_type_list_id = 0; - -/** - * \brief Registration function for krb5_msg_type: keyword - * - * This function is called once in the 'lifetime' of the engine. - */ -void DetectKrb5MsgTypeRegister(void) -{ - sigmatch_table[DETECT_KRB5_MSGTYPE].name = "krb5_msg_type"; - sigmatch_table[DETECT_KRB5_MSGTYPE].desc = "match Kerberos 5 message type"; - sigmatch_table[DETECT_KRB5_MSGTYPE].url = "/rules/kerberos-keywords.html#krb5-msg-type"; - sigmatch_table[DETECT_KRB5_MSGTYPE].Match = NULL; - sigmatch_table[DETECT_KRB5_MSGTYPE].AppLayerTxMatch = DetectKrb5MsgTypeMatch; - sigmatch_table[DETECT_KRB5_MSGTYPE].Setup = DetectKrb5MsgTypeSetup; - sigmatch_table[DETECT_KRB5_MSGTYPE].Free = DetectKrb5MsgTypeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_KRB5_MSGTYPE].RegisterTests = DetectKrb5MsgTypeRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister("krb5_msg_type", ALPROTO_KRB5, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister("krb5_msg_type", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - /* set up the PCRE for keyword parsing */ - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - g_krb5_msg_type_list_id = DetectBufferTypeRegister("krb5_msg_type"); - SCLogDebug("g_krb5_msg_type_list_id %d", g_krb5_msg_type_list_id); -} - -/** - * \brief This function is used to match KRB5 rule option on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch with context that we will cast into DetectKrb5Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectKrb5MsgTypeMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - uint32_t msg_type; - const DetectKrb5MsgTypeData *dd = (const DetectKrb5MsgTypeData *)ctx; - - SCEnter(); - - SCKrb5TxGetMsgType(txv, &msg_type); - - if (dd->msg_type == msg_type) - SCReturnInt(1); - - SCReturnInt(0); -} - -/** - * \brief This function is used to parse options passed via krb5_msgtype: keyword - * - * \param krb5str Pointer to the user provided krb5_msg_type options - * - * \retval krb5d pointer to DetectKrb5Data on success - * \retval NULL on failure - */ -static DetectKrb5MsgTypeData *DetectKrb5MsgTypeParse (const char *krb5str) -{ - DetectKrb5MsgTypeData *krb5d = NULL; - char arg1[4] = ""; - int res = 0; - size_t pcre2len; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, krb5str, 0, 0); - if (ret != 2) { - SCLogError("parse error, ret %" PRId32 "", ret); - goto error; - } - - pcre2len = sizeof(arg1); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - krb5d = SCMalloc(sizeof (DetectKrb5MsgTypeData)); - if (unlikely(krb5d == NULL)) - goto error; - if (StringParseUint8(&krb5d->msg_type, 10, 0, - (const char *)arg1) < 0) { - goto error; - } - pcre2_match_data_free(match); - return krb5d; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (krb5d) - SCFree(krb5d); - return NULL; -} - -/** - * \brief parse the options from the 'krb5_msg_type' keyword in the rule into - * the Signature data structure. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param krb5str pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectKrb5MsgTypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) -{ - DetectKrb5MsgTypeData *krb5d = NULL; - - if (SCDetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) - return -1; - - krb5d = DetectKrb5MsgTypeParse(krb5str); - if (krb5d == NULL) - goto error; - - if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_KRB5_MSGTYPE, (SigMatchCtx *)krb5d, - g_krb5_msg_type_list_id) == NULL) { - goto error; - } - - return 0; - -error: - if (krb5d != NULL) - DetectKrb5MsgTypeFree(de_ctx, krb5d); - return -1; -} - -/** - * \brief this function will free memory associated with DetectKrb5Data - * - * \param ptr pointer to DetectKrb5Data - */ -static void DetectKrb5MsgTypeFree(DetectEngineCtx *de_ctx, void *ptr) { - DetectKrb5MsgTypeData *krb5d = (DetectKrb5MsgTypeData *)ptr; - - SCFree(krb5d); -} - -#ifdef UNITTESTS - -/** - * \test description of the test - */ - -static int DetectKrb5MsgTypeParseTest01 (void) -{ - DetectKrb5MsgTypeData *krb5d = DetectKrb5MsgTypeParse("10"); - FAIL_IF_NULL(krb5d); - FAIL_IF(!(krb5d->msg_type == 10)); - DetectKrb5MsgTypeFree(NULL, krb5d); - PASS; -} - -static int DetectKrb5MsgTypeSignatureTest01 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, "alert krb5 any any -> any any (krb5_msg_type:10; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \brief this function registers unit tests for DetectKrb5MsgType - */ -static void DetectKrb5MsgTypeRegisterTests(void) -{ - UtRegisterTest("DetectKrb5MsgTypeParseTest01", DetectKrb5MsgTypeParseTest01); - UtRegisterTest("DetectKrb5MsgTypeSignatureTest01", - DetectKrb5MsgTypeSignatureTest01); -} -#endif /* UNITTESTS */ diff --git a/src/detect-krb5-msgtype.h b/src/detect-krb5-msgtype.h deleted file mode 100644 index 2be0a579c4..0000000000 --- a/src/detect-krb5-msgtype.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2015-2017 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 Pierre Chifflier - */ - -#ifndef SURICATA_DETECT_KRB5_MSGTYPE_H -#define SURICATA_DETECT_KRB5_MSGTYPE_H - -typedef struct DetectKrb5MsgTypeData_ { - uint8_t msg_type; -} DetectKrb5MsgTypeData; - -void DetectKrb5MsgTypeRegister(void); - -#endif /* SURICATA_DETECT_KRB5_MSGTYPE_H */