detect/krb5: move krb5_msg_type to rust

Makes it a generic u32 on the way

Unit tests are covered by SV tests

Ticket: 6723
pull/13892/head
Philippe Antoine 1 year ago committed by Victor Julien
parent 5a4d280461
commit 0553dfa814

@ -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 <rules-integer-keywords>`.
* 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:<number>
krb5_msg_type:(mode) <number or string>
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

@ -18,8 +18,18 @@
// written by Pierre Chifflier <chifflier@wzdftpd.net>
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<u32> {
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::<u32, Krb5MessageType>(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<u32>);
// 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<u32>);
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,
);
}

@ -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 \

@ -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();

@ -268,7 +268,6 @@ enum DetectKeywordId {
DETECT_DNP3OBJ,
DETECT_KRB5_ERRCODE,
DETECT_KRB5_MSGTYPE,
DETECT_KRB5_CNAME,
DETECT_KRB5_SNAME,
DETECT_KRB5_TICKET_ENCRYPTION,

@ -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 <chifflier@wzdftpd.net>
*/
#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 */

@ -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 <chifflier@wzdftpd.net>
*/
#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 */
Loading…
Cancel
Save