suricata
detect-email.c
Go to the documentation of this file.
1 /* Copyright (C) 2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "detect-engine.h"
19 #include "detect-engine-buffer.h"
20 #include "detect-engine-helper.h"
21 #include "detect-parse.h"
22 #include "app-layer-smtp.h"
23 #include "detect-email.h"
24 #include "rust.h"
26 
27 static int g_mime_email_from_buffer_id = 0;
28 static int g_mime_email_subject_buffer_id = 0;
29 static int g_mime_email_to_buffer_id = 0;
30 static int g_mime_email_cc_buffer_id = 0;
31 static int g_mime_email_date_buffer_id = 0;
32 static int g_mime_email_message_id_buffer_id = 0;
33 static int g_mime_email_x_mailer_buffer_id = 0;
34 static int g_mime_email_url_buffer_id = 0;
35 static int g_mime_email_received_buffer_id = 0;
36 static int g_mime_email_body_md5_buffer_id = 0;
37 
38 static int DetectMimeEmailFromSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
39 {
40  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_from_buffer_id) < 0)
41  return -1;
42 
44  return -1;
45 
46  return 0;
47 }
48 
49 static bool GetMimeEmailFromData(
50  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
51 {
52  SMTPTransaction *tx = (SMTPTransaction *)txv;
53  if (tx->mime_state == NULL)
54  return false;
55  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "from") == 1);
56 }
57 
58 static int DetectMimeEmailSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
59 {
60  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_subject_buffer_id) < 0)
61  return -1;
62 
64  return -1;
65 
66  return 0;
67 }
68 
69 static bool GetMimeEmailSubjectData(
70  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
71 {
72  SMTPTransaction *tx = (SMTPTransaction *)txv;
73  if (tx->mime_state == NULL)
74  return false;
75  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "subject") == 1);
76 }
77 
78 static int DetectMimeEmailToSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
79 {
80  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_to_buffer_id) < 0)
81  return -1;
82 
84  return -1;
85 
86  return 0;
87 }
88 
89 static bool GetMimeEmailToData(
90  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
91 {
92  SMTPTransaction *tx = (SMTPTransaction *)txv;
93  if (tx->mime_state == NULL)
94  return false;
95  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "to") == 1);
96 }
97 
98 static int DetectMimeEmailCcSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
99 {
100  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_cc_buffer_id) < 0)
101  return -1;
102 
104  return -1;
105 
106  return 0;
107 }
108 
109 static bool GetMimeEmailCcData(
110  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
111 {
112  SMTPTransaction *tx = (SMTPTransaction *)txv;
113  if (tx->mime_state == NULL)
114  return false;
115  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "cc") == 1);
116 }
117 
118 static int DetectMimeEmailDateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
119 {
120  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_date_buffer_id) < 0)
121  return -1;
122 
124  return -1;
125 
126  return 0;
127 }
128 
129 static bool GetMimeEmailDateData(
130  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
131 {
132  SMTPTransaction *tx = (SMTPTransaction *)txv;
133  if (tx->mime_state == NULL)
134  return false;
135  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "date") == 1);
136 }
137 
138 static int DetectMimeEmailMessageIdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
139 {
140  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_message_id_buffer_id) < 0)
141  return -1;
142 
144  return -1;
145 
146  return 0;
147 }
148 
149 static bool GetMimeEmailMessageIdData(
150  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
151 {
152  SMTPTransaction *tx = (SMTPTransaction *)txv;
153  if (tx->mime_state == NULL)
154  return false;
155  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "message-id") == 1);
156 }
157 
158 static int DetectMimeEmailXMailerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
159 {
160  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_x_mailer_buffer_id) < 0)
161  return -1;
162 
164  return -1;
165 
166  return 0;
167 }
168 
169 static bool GetMimeEmailXMailerData(
170  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
171 {
172  SMTPTransaction *tx = (SMTPTransaction *)txv;
173  if (tx->mime_state == NULL)
174  return false;
175  return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "x-mailer") == 1);
176 }
177 
178 static int DetectMimeEmailUrlSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
179 {
180  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_url_buffer_id) < 0)
181  return -1;
182 
184  return -1;
185 
186  return 0;
187 }
188 
189 static bool GetMimeEmailUrlData(DetectEngineThreadCtx *det_ctx, const void *txv,
190  const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
191 {
192  SMTPTransaction *tx = (SMTPTransaction *)txv;
193  if (tx->mime_state == NULL) {
194  return false;
195  }
196 
197  return SCDetectMimeEmailGetUrl(tx->mime_state, buf, buf_len, idx) == 1;
198 }
199 
200 static int DetectMimeEmailReceivedSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
201 {
202  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_received_buffer_id) < 0)
203  return -1;
204 
206  return -1;
207 
208  return 0;
209 }
210 
211 static bool GetMimeEmailReceivedData(DetectEngineThreadCtx *det_ctx, const void *txv,
212  const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
213 {
214  SMTPTransaction *tx = (SMTPTransaction *)txv;
215 
216  if (tx->mime_state == NULL) {
217  return false;
218  }
219 
220  return SCDetectMimeEmailGetDataArray(tx->mime_state, buf, buf_len, "received", idx) == 1;
221 }
222 
224 
225 static int DetectMimeEmailBodyMd5Setup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
226 {
227  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_body_md5_buffer_id) < 0)
228  return -1;
229 
231  return -1;
232 
233  if (!MimeBodyMd5IsEnabled()) {
234  // we registered the keyword if not explicitly disabled, so we are here in auto mode
235  SCMimeSmtpConfigBodyMd5(true);
236  }
237 
238  return 0;
239 }
240 
241 static bool GetMimeEmailBodyMd5Data(
242  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
243 {
244  SMTPTransaction *tx = (SMTPTransaction *)txv;
245  if (tx->mime_state == NULL)
246  return false;
247 
248  SCDetectMimeEmailGetBodyMd5(tx->mime_state, data, data_len);
249 
250  return true;
251 }
252 
254 {
255  SCSigTableAppLiteElmt kw = { 0 };
256 
257  kw.name = "email.from";
258  kw.desc = "'From' field from an email";
259  kw.url = "/rules/email-keywords.html#email.from";
260  kw.Setup = DetectMimeEmailFromSetup;
263  g_mime_email_from_buffer_id = SCDetectHelperBufferMpmRegister(
264  "email.from", "MIME EMAIL FROM", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailFromData);
265 
266  kw.name = "email.subject";
267  kw.desc = "'Subject' field from an email";
268  kw.url = "/rules/email-keywords.html#email.subject";
269  kw.Setup = DetectMimeEmailSubjectSetup;
272  g_mime_email_subject_buffer_id = SCDetectHelperBufferMpmRegister("email.subject",
273  "MIME EMAIL SUBJECT", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailSubjectData);
274 
275  kw.name = "email.to";
276  kw.desc = "'To' field from an email";
277  kw.url = "/rules/email-keywords.html#email.to";
278  kw.Setup = DetectMimeEmailToSetup;
281  g_mime_email_to_buffer_id = SCDetectHelperBufferMpmRegister(
282  "email.to", "MIME EMAIL TO", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailToData);
283 
284  kw.name = "email.cc";
285  kw.desc = "'Cc' field from an email";
286  kw.url = "/rules/email-keywords.html#email.cc";
287  kw.Setup = DetectMimeEmailCcSetup;
290  g_mime_email_cc_buffer_id = SCDetectHelperBufferMpmRegister(
291  "email.cc", "MIME EMAIL CC", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailCcData);
292 
293  kw.name = "email.date";
294  kw.desc = "'Date' field from an email";
295  kw.url = "/rules/email-keywords.html#email.date";
296  kw.Setup = DetectMimeEmailDateSetup;
299  g_mime_email_date_buffer_id = SCDetectHelperBufferMpmRegister(
300  "email.date", "MIME EMAIL DATE", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailDateData);
301 
302  kw.name = "email.message_id";
303  kw.desc = "'Message-Id' field from an email";
304  kw.url = "/rules/email-keywords.html#email.message_id";
305  kw.Setup = DetectMimeEmailMessageIdSetup;
308  g_mime_email_message_id_buffer_id = SCDetectHelperBufferMpmRegister("email.message_id",
309  "MIME EMAIL Message-Id", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailMessageIdData);
310 
311  kw.name = "email.x_mailer";
312  kw.desc = "'X-Mailer' field from an email";
313  kw.url = "/rules/email-keywords.html#email.x_mailer";
314  kw.Setup = DetectMimeEmailXMailerSetup;
317  g_mime_email_x_mailer_buffer_id = SCDetectHelperBufferMpmRegister("email.x_mailer",
318  "MIME EMAIL X-Mailer", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailXMailerData);
319 
320  kw.name = "email.url";
321  kw.desc = "'Url' extracted from an email";
322  kw.url = "/rules/email-keywords.html#email.url";
323  kw.Setup = DetectMimeEmailUrlSetup;
326  g_mime_email_url_buffer_id = SCDetectHelperMultiBufferMpmRegister(
327  "email.url", "MIME EMAIL URL", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailUrlData);
328 
329  kw.name = "email.received";
330  kw.desc = "'Received' field from an email";
331  kw.url = "/rules/email-keywords.html#email.received";
332  kw.Setup = DetectMimeEmailReceivedSetup;
335  g_mime_email_received_buffer_id = SCDetectHelperMultiBufferMpmRegister("email.received",
336  "MIME EMAIL RECEIVED", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailReceivedData);
337 
338  if (!MimeBodyMd5IsDisabled()) {
339  // do not register the keyword if explicitly disabled
340  kw.name = "email.body_md5";
341  kw.desc = "'md5' hash generated from an email body";
342  kw.url = "/rules/email-keywords.html#email.body_md5";
343  kw.Setup = DetectMimeEmailBodyMd5Setup;
346  // We do not need a progress because SMTP tx has only progress 0 or 1
347  // even if we have a MimeSmtpMd5State enumeration
348  g_mime_email_body_md5_buffer_id = SCDetectHelperBufferMpmRegister("email.body_md5",
349  "MIME EMAIL BODY MD5", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailBodyMd5Data);
351  }
352 }
DetectEmailRegister
void DetectEmailRegister(void)
Definition: detect-email.c:253
detect-engine.h
SCSigTableAppLiteElmt::url
const char * url
keyword documentation url
Definition: detect-engine-helper.h:55
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect-engine-register.h:311
detect-email.h
SCSigTableAppLiteElmt::name
const char * name
keyword name
Definition: detect-engine-helper.h:51
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:937
DetectBufferTypeRegisterValidateCallback
void DetectBufferTypeRegisterValidateCallback(const char *name, bool(*ValidateCallback)(const Signature *, const char **sigerror, const DetectBufferType *))
Definition: detect-engine.c:1481
rust.h
SCDetectBufferSetActiveList
int SCDetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int list)
Definition: detect-engine-buffer.c:29
SCDetectHelperBufferMpmRegister
int SCDetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionSingleBufferGetDataPtr GetData)
Definition: detect-engine-helper.c:47
SCSigTableAppLiteElmt::desc
const char * desc
keyword description
Definition: detect-engine-helper.h:53
SCDetectSignatureSetAppProto
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2234
DetectMd5ValidateCallback
bool DetectMd5ValidateCallback(const Signature *s, const char **sigerror, const DetectBufferType *map)
Definition: detect-engine.c:5053
SCSigTableAppLiteElmt
App-layer light version of SigTableElmt.
Definition: detect-engine-helper.h:49
SIGMATCH_INFO_MULTI_BUFFER
#define SIGMATCH_INFO_MULTI_BUFFER
Definition: detect-engine-register.h:343
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectEngineThreadCtx_
Definition: detect.h:1252
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:38
SCSigTableAppLiteElmt::flags
uint32_t flags
flags SIGMATCH_*
Definition: detect-engine-helper.h:57
detect-engine-helper.h
SMTPTransaction_
Definition: app-layer-smtp.h:73
SCDetectHelperKeywordRegister
uint16_t SCDetectHelperKeywordRegister(const SCSigTableAppLiteElmt *kw)
Definition: detect-engine-helper.c:122
detect-engine-content-inspection.h
flags
uint8_t flags
Definition: decode-gre.h:0
SCSigTableAppLiteElmt::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
function callback to parse and setup keyword in rule
Definition: detect-engine-helper.h:59
SCDetectHelperMultiBufferMpmRegister
int SCDetectHelperMultiBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionMultiBufferGetDataPtr GetData)
Definition: detect-engine-helper.c:99
detect-engine-buffer.h
detect-parse.h
DETECT_EMAIL_BODY_MD5
int DETECT_EMAIL_BODY_MD5
Definition: detect-email.c:223
Signature_
Signature container.
Definition: detect.h:672
SIGMATCH_INFO_STICKY_BUFFER
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect-engine-register.h:333
app-layer-smtp.h
SMTPTransaction_::mime_state
MimeStateSMTP * mime_state
Definition: app-layer-smtp.h:86