diff --git a/doc/userguide/rules/email-keywords.rst b/doc/userguide/rules/email-keywords.rst index 8c9ec97477..c7a480f5a3 100644 --- a/doc/userguide/rules/email-keywords.rst +++ b/doc/userguide/rules/email-keywords.rst @@ -170,3 +170,29 @@ Example of a signature that would alert if a packet contains the MIME field ``x- .. container:: example-rule alert smtp any any -> any any (msg:"Test mime email x-mailer"; :example-rule-emphasis:`email.x_mailer; content:"Microsoft Office Outlook, Build 11.0.5510";` sid:1;) + +email.url +--------- + +Matches ``URL`` extracted of an email. + +Comparison is case-sensitive. + +Syntax:: + + email.url; content:""; + +``email.url`` is a 'sticky buffer' and can be used as a ``fast_pattern``. + +``email.url`` supports multiple buffer matching, see :doc:`multi-buffer-matching`. + +This keyword maps to the EVE field ``email.url[]`` + +Example +^^^^^^^ + +Example of a signature that would alert if an email contains the ``url`` ``test-site.org/blah/123/``. + +.. 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;) diff --git a/doc/userguide/rules/multi-buffer-matching.rst b/doc/userguide/rules/multi-buffer-matching.rst index 166e37c84e..63a143d766 100644 --- a/doc/userguide/rules/multi-buffer-matching.rst +++ b/doc/userguide/rules/multi-buffer-matching.rst @@ -77,6 +77,7 @@ following keywords: * ``dns.answer.name`` * ``dns.query.name`` * ``dns.query`` +* ``email.url`` * ``file.data`` * ``file.magic`` * ``file.name`` diff --git a/rust/src/mime/detect.rs b/rust/src/mime/detect.rs index 57d8f10214..d178ccbc36 100644 --- a/rust/src/mime/detect.rs +++ b/rust/src/mime/detect.rs @@ -43,3 +43,20 @@ pub unsafe extern "C" fn SCDetectMimeEmailGetData( return 0; } + +#[no_mangle] +pub unsafe extern "C" fn SCDetectMimeEmailGetUrl( + ctx: &MimeStateSMTP, buffer: *mut *const u8, buffer_len: *mut u32, idx: u32, +) -> u8 { + if !ctx.urls.is_empty() && idx < ctx.urls.len() as u32 { + let url = &ctx.urls[idx as usize]; + *buffer = url.as_ptr(); + *buffer_len = url.len() as u32; + return 1; + } + + *buffer = ptr::null(); + *buffer_len = 0; + + return 0; +} diff --git a/src/detect-email.c b/src/detect-email.c index 8ec76d5eb6..1c38a75602 100644 --- a/src/detect-email.c +++ b/src/detect-email.c @@ -21,6 +21,7 @@ #include "app-layer-smtp.h" #include "detect-email.h" #include "rust.h" +#include "detect-engine-content-inspection.h" static int g_mime_email_from_buffer_id = 0; static int g_mime_email_subject_buffer_id = 0; @@ -29,6 +30,7 @@ static int g_mime_email_cc_buffer_id = 0; 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 DetectMimeEmailFromSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) { @@ -273,6 +275,45 @@ static InspectionBuffer *GetMimeEmailXMailerData(DetectEngineThreadCtx *det_ctx, return buffer; } +static int DetectMimeEmailUrlSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_mime_email_url_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetMimeEmailUrlData(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_url = NULL; + uint32_t b_email_url_len = 0; + + if (tx->mime_state == NULL) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + if (SCDetectMimeEmailGetUrl(tx->mime_state, &b_email_url, &b_email_url_len, idx) != 1) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(det_ctx, buffer, transforms, b_email_url, b_email_url_len); + buffer->flags = DETECT_CI_FLAGS_SINGLE; + return buffer; +} + void DetectEmailRegister(void) { SCSigTableElmt kw = { 0 }; @@ -353,4 +394,15 @@ void DetectEmailRegister(void) "MIME EMAIL X-Mailer", ALPROTO_SMTP, false, true, // to server GetMimeEmailXMailerData); + + kw.name = "email.url"; + kw.desc = "'Url' extracted from an email"; + kw.url = "/rules/email-keywords.html#email.url"; + kw.Setup = (int (*)(void *, void *, const char *))DetectMimeEmailUrlSetup; + kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + DetectHelperKeywordRegister(&kw); + g_mime_email_url_buffer_id = + DetectHelperMultiBufferMpmRegister("email.url", "MIME EMAIL URL", ALPROTO_SMTP, false, + true, // to server + GetMimeEmailUrlData); }