]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: add email.received keyword
authorAlice Akaki <akakialice@gmail.com>
Wed, 9 Apr 2025 21:43:42 +0000 (17:43 -0400)
committerVictor Julien <victor@inliniac.net>
Thu, 17 Apr 2025 06:22:13 +0000 (08:22 +0200)
email.received matches on MIME EMAIL Received
This keyword maps to the EVE field email.received[]
It is a sticky buffer
Supports multiple buffer matching
Supports prefiltering

Ticket: #7599

doc/userguide/rules/email-keywords.rst
doc/userguide/rules/multi-buffer-matching.rst
rust/src/mime/detect.rs
src/detect-email.c

index c7a480f5a3fb0b667b7fb229bb31f7e2eb7fa34e..206c3837e62cbdcca664e15bab9f770b882d4fc7 100644 (file)
@@ -196,3 +196,29 @@ Example of a signature that would alert if an email contains the ``url`` ``test-
 .. container:: example-rule
 
   alert smtp any any -> any any (msg:"Test mime email url"; :example-rule-emphasis:`email.url; content:"test-site.org/blah/123/";` sid:1;)
+
+email.received
+--------------
+
+Matches ``Received`` field of an email.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ email.received; content:"<content to match against>";
+
+``email.received`` is a 'sticky buffer' and can be used as a ``fast_pattern``.
+
+``email.received`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+This keyword maps to the EVE field ``email.received[]``
+
+Example
+^^^^^^^
+
+Example of a signature that would alert if a packet contains the MIME field ``received`` with the value ``from [65.201.218.30] (helo=COZOXORY.club)by 173-66-46-112.wash.fios.verizon.net with esmtpa (Exim 4.86)(envelope-from )id 71cF63a9for mirjam@abrakadabra.ch; Mon, 29 Jul 2019 17:01:45 +0000``
+
+.. container:: example-rule
+
+  alert smtp any any -> any any (msg:"Test mime email received"; :example-rule-emphasis:`email.received; content:"from [65.201.218.30] (helo=COZOXORY.club)by 173-66-46-112.wash.fios.verizon.net with esmtpa (Exim 4.86)(envelope-from )id 71cF63a9for mirjam@abrakadabra.ch\; Mon, 29 Jul 2019 17:01:45 +0000";` sid:1;)
index 63a143d7662daaec75176baaad2077e28ef8bf18..5f894d222e3ea5da8271fb027f5586ff042712e2 100644 (file)
@@ -77,6 +77,7 @@ following keywords:
 * ``dns.answer.name``
 * ``dns.query.name``
 * ``dns.query``
+* ``email.received``
 * ``email.url``
 * ``file.data``
 * ``file.magic``
index d178ccbc3679677a245b43b869fbc3353b7891d5..a9fbb631a7afc04e31922d14568461aa9c7142c6 100644 (file)
@@ -60,3 +60,32 @@ pub unsafe extern "C" fn SCDetectMimeEmailGetUrl(
 
     return 0;
 }
+
+/// Intermediary function used in detect-email.c to access data from the MimeStateSMTP structure
+/// for array header fields.
+/// The hname parameter determines which data will be returned.
+#[no_mangle]
+pub unsafe extern "C" fn SCDetectMimeEmailGetDataArray(
+    ctx: &MimeStateSMTP, buffer: *mut *const u8, buffer_len: *mut u32,
+    hname: *const std::os::raw::c_char, idx: u32,
+) -> u8 {
+    let c_str = CStr::from_ptr(hname); //unsafe
+    let str = c_str.to_str().unwrap_or("");
+
+    let mut i = 0;
+    for h in &ctx.headers[..ctx.main_headers_nb] {
+        if mime::slice_equals_lowercase(&h.name, str.as_bytes()) {
+            if i == idx {
+                *buffer = h.value.as_ptr();
+                *buffer_len = h.value.len() as u32;
+                return 1;
+            }
+            i += 1;
+        }
+    }
+
+    *buffer = ptr::null();
+    *buffer_len = 0;
+
+    return 0;
+}
index 1c38a756021c23d550597037cba87dd0b56c47ad..385c166dd3a51be748d9bb15d9e60beac6e2852a 100644 (file)
@@ -31,6 +31,7 @@ static int g_mime_email_date_buffer_id = 0;
 static int g_mime_email_message_id_buffer_id = 0;
 static int g_mime_email_x_mailer_buffer_id = 0;
 static int g_mime_email_url_buffer_id = 0;
+static int g_mime_email_received_buffer_id = 0;
 
 static int DetectMimeEmailFromSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
 {
@@ -314,6 +315,46 @@ static InspectionBuffer *GetMimeEmailUrlData(DetectEngineThreadCtx *det_ctx,
     return buffer;
 }
 
+static int DetectMimeEmailReceivedSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
+{
+    if (DetectBufferSetActiveList(de_ctx, s, g_mime_email_received_buffer_id) < 0)
+        return -1;
+
+    if (DetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
+        return -1;
+
+    return 0;
+}
+
+static InspectionBuffer *GetMimeEmailReceivedData(DetectEngineThreadCtx *det_ctx,
+        const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
+        const int list_id, uint32_t idx)
+{
+    InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, idx);
+    if (buffer == NULL || buffer->initialized)
+        return buffer;
+
+    SMTPTransaction *tx = (SMTPTransaction *)txv;
+
+    const uint8_t *b_email_received = NULL;
+    uint32_t b_email_received_len = 0;
+
+    if (tx->mime_state == NULL) {
+        InspectionBufferSetupMultiEmpty(buffer);
+        return NULL;
+    }
+
+    if (SCDetectMimeEmailGetDataArray(
+                tx->mime_state, &b_email_received, &b_email_received_len, "received", idx) != 1) {
+        InspectionBufferSetupMultiEmpty(buffer);
+        return NULL;
+    }
+
+    InspectionBufferSetupMulti(det_ctx, buffer, transforms, b_email_received, b_email_received_len);
+    buffer->flags = DETECT_CI_FLAGS_SINGLE;
+    return buffer;
+}
+
 void DetectEmailRegister(void)
 {
     SCSigTableElmt kw = { 0 };
@@ -405,4 +446,15 @@ void DetectEmailRegister(void)
             DetectHelperMultiBufferMpmRegister("email.url", "MIME EMAIL URL", ALPROTO_SMTP, false,
                     true, // to server
                     GetMimeEmailUrlData);
+
+    kw.name = "email.received";
+    kw.desc = "'Received' field from an email";
+    kw.url = "/rules/email-keywords.html#email.received";
+    kw.Setup = (int (*)(void *, void *, const char *))DetectMimeEmailReceivedSetup;
+    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
+    DetectHelperKeywordRegister(&kw);
+    g_mime_email_received_buffer_id = DetectHelperMultiBufferMpmRegister("email.received",
+            "MIME EMAIL RECEIVED", ALPROTO_SMTP, false,
+            true, // to server
+            GetMimeEmailReceivedData);
 }