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 
37 static int DetectMimeEmailFromSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
38 {
39  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_from_buffer_id) < 0)
40  return -1;
41 
43  return -1;
44 
45  return 0;
46 }
47 
48 static InspectionBuffer *GetMimeEmailFromData(DetectEngineThreadCtx *det_ctx,
49  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
50  const int list_id)
51 {
52  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
53  if (buffer->inspect == NULL) {
54  SMTPTransaction *tx = (SMTPTransaction *)txv;
55 
56  const uint8_t *b_email_from = NULL;
57  uint32_t b_email_from_len = 0;
58 
59  if (tx->mime_state == NULL)
60  return NULL;
61 
62  if (SCDetectMimeEmailGetData(tx->mime_state, &b_email_from, &b_email_from_len, "from") != 1)
63  return NULL;
64 
65  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_from, b_email_from_len);
66  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
67  }
68  return buffer;
69 }
70 
71 static int DetectMimeEmailSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
72 {
73  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_subject_buffer_id) < 0)
74  return -1;
75 
77  return -1;
78 
79  return 0;
80 }
81 
82 static InspectionBuffer *GetMimeEmailSubjectData(DetectEngineThreadCtx *det_ctx,
83  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
84  const int list_id)
85 {
86  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
87  if (buffer->inspect == NULL) {
88  SMTPTransaction *tx = (SMTPTransaction *)txv;
89 
90  const uint8_t *b_email_sub = NULL;
91  uint32_t b_email_sub_len = 0;
92 
93  if (tx->mime_state == NULL)
94  return NULL;
95 
96  if (SCDetectMimeEmailGetData(tx->mime_state, &b_email_sub, &b_email_sub_len, "subject") !=
97  1)
98  return NULL;
99 
100  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_sub, b_email_sub_len);
101  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
102  }
103  return buffer;
104 }
105 
106 static int DetectMimeEmailToSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
107 {
108  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_to_buffer_id) < 0)
109  return -1;
110 
112  return -1;
113 
114  return 0;
115 }
116 
117 static InspectionBuffer *GetMimeEmailToData(DetectEngineThreadCtx *det_ctx,
118  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
119  const int list_id)
120 {
121  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
122  if (buffer->inspect == NULL) {
123  SMTPTransaction *tx = (SMTPTransaction *)txv;
124 
125  const uint8_t *b_email_to = NULL;
126  uint32_t b_email_to_len = 0;
127 
128  if ((tx->mime_state != NULL)) {
129  if (SCDetectMimeEmailGetData(tx->mime_state, &b_email_to, &b_email_to_len, "to") != 1)
130  return NULL;
131  }
132 
133  if (b_email_to == NULL || b_email_to_len == 0)
134  return NULL;
135 
136  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_to, b_email_to_len);
137  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
138  }
139  return buffer;
140 }
141 
142 static int DetectMimeEmailCcSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
143 {
144  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_cc_buffer_id) < 0)
145  return -1;
146 
148  return -1;
149 
150  return 0;
151 }
152 
153 static InspectionBuffer *GetMimeEmailCcData(DetectEngineThreadCtx *det_ctx,
154  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
155  const int list_id)
156 {
157  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
158  if (buffer->inspect == NULL) {
159  SMTPTransaction *tx = (SMTPTransaction *)txv;
160 
161  const uint8_t *b_email_cc = NULL;
162  uint32_t b_email_cc_len = 0;
163 
164  if (tx->mime_state == NULL)
165  return NULL;
166 
167  if (SCDetectMimeEmailGetData(tx->mime_state, &b_email_cc, &b_email_cc_len, "cc") != 1)
168  return NULL;
169 
170  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_cc, b_email_cc_len);
171  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
172  }
173  return buffer;
174 }
175 
176 static int DetectMimeEmailDateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
177 {
178  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_date_buffer_id) < 0)
179  return -1;
180 
182  return -1;
183 
184  return 0;
185 }
186 
187 static InspectionBuffer *GetMimeEmailDateData(DetectEngineThreadCtx *det_ctx,
188  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
189  const int list_id)
190 {
191  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
192  if (buffer->inspect == NULL) {
193  SMTPTransaction *tx = (SMTPTransaction *)txv;
194 
195  const uint8_t *b_email_date = NULL;
196  uint32_t b_email_date_len = 0;
197 
198  if (tx->mime_state == NULL)
199  return NULL;
200 
201  if (SCDetectMimeEmailGetData(tx->mime_state, &b_email_date, &b_email_date_len, "date") != 1)
202  return NULL;
203 
204  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_date, b_email_date_len);
205  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
206  }
207  return buffer;
208 }
209 
210 static int DetectMimeEmailMessageIdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
211 {
212  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_message_id_buffer_id) < 0)
213  return -1;
214 
216  return -1;
217 
218  return 0;
219 }
220 
221 static InspectionBuffer *GetMimeEmailMessageIdData(DetectEngineThreadCtx *det_ctx,
222  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
223  const int list_id)
224 {
225  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
226  if (buffer->inspect == NULL) {
227  SMTPTransaction *tx = (SMTPTransaction *)txv;
228 
229  const uint8_t *b_email_msg_id = NULL;
230  uint32_t b_email_msg_id_len = 0;
231 
232  if (tx->mime_state == NULL)
233  return NULL;
234 
235  if (SCDetectMimeEmailGetData(
236  tx->mime_state, &b_email_msg_id, &b_email_msg_id_len, "message-id") != 1)
237  return NULL;
238 
239  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_msg_id, b_email_msg_id_len);
240  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
241  }
242  return buffer;
243 }
244 
245 static int DetectMimeEmailXMailerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
246 {
247  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_x_mailer_buffer_id) < 0)
248  return -1;
249 
251  return -1;
252 
253  return 0;
254 }
255 
256 static InspectionBuffer *GetMimeEmailXMailerData(DetectEngineThreadCtx *det_ctx,
257  const DetectEngineTransforms *transforms, Flow *f, const uint8_t _flow_flags, void *txv,
258  const int list_id)
259 {
260  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
261  if (buffer->inspect == NULL) {
262  SMTPTransaction *tx = (SMTPTransaction *)txv;
263 
264  const uint8_t *b_email_x_mailer = NULL;
265  uint32_t b_email_x_mailer_len = 0;
266 
267  if (tx->mime_state == NULL)
268  return NULL;
269 
270  if (SCDetectMimeEmailGetData(
271  tx->mime_state, &b_email_x_mailer, &b_email_x_mailer_len, "x-mailer") != 1)
272  return NULL;
273 
274  InspectionBufferSetup(det_ctx, list_id, buffer, b_email_x_mailer, b_email_x_mailer_len);
275  InspectionBufferApplyTransforms(det_ctx, buffer, transforms);
276  }
277  return buffer;
278 }
279 
280 static int DetectMimeEmailUrlSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
281 {
282  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_url_buffer_id) < 0)
283  return -1;
284 
286  return -1;
287 
288  return 0;
289 }
290 
291 static bool GetMimeEmailUrlData(DetectEngineThreadCtx *det_ctx, const void *txv,
292  const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
293 {
294  SMTPTransaction *tx = (SMTPTransaction *)txv;
295  if (tx->mime_state == NULL) {
296  return false;
297  }
298 
299  if (SCDetectMimeEmailGetUrl(tx->mime_state, buf, buf_len, idx) != 1) {
300  return false;
301  }
302  return true;
303 }
304 
305 static int DetectMimeEmailReceivedSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
306 {
307  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_received_buffer_id) < 0)
308  return -1;
309 
311  return -1;
312 
313  return 0;
314 }
315 
316 static bool GetMimeEmailReceivedData(DetectEngineThreadCtx *det_ctx, const void *txv,
317  const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
318 {
319  SMTPTransaction *tx = (SMTPTransaction *)txv;
320 
321  if (tx->mime_state == NULL) {
322  return false;
323  }
324 
325  if (SCDetectMimeEmailGetDataArray(tx->mime_state, buf, buf_len, "received", idx) != 1) {
326  return false;
327  }
328  return true;
329 }
330 
332 {
333  SCSigTableAppLiteElmt kw = { 0 };
334 
335  kw.name = "email.from";
336  kw.desc = "'From' field from an email";
337  kw.url = "/rules/email-keywords.html#email.from";
338  kw.Setup = DetectMimeEmailFromSetup;
341  g_mime_email_from_buffer_id = DetectHelperBufferMpmRegister(
342  "email.from", "MIME EMAIL FROM", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailFromData);
343 
344  kw.name = "email.subject";
345  kw.desc = "'Subject' field from an email";
346  kw.url = "/rules/email-keywords.html#email.subject";
347  kw.Setup = DetectMimeEmailSubjectSetup;
350  g_mime_email_subject_buffer_id = DetectHelperBufferMpmRegister("email.subject",
351  "MIME EMAIL SUBJECT", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailSubjectData);
352 
353  kw.name = "email.to";
354  kw.desc = "'To' field from an email";
355  kw.url = "/rules/email-keywords.html#email.to";
356  kw.Setup = DetectMimeEmailToSetup;
359  g_mime_email_to_buffer_id = DetectHelperBufferMpmRegister(
360  "email.to", "MIME EMAIL TO", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailToData);
361 
362  kw.name = "email.cc";
363  kw.desc = "'Cc' field from an email";
364  kw.url = "/rules/email-keywords.html#email.cc";
365  kw.Setup = DetectMimeEmailCcSetup;
368  g_mime_email_cc_buffer_id = DetectHelperBufferMpmRegister(
369  "email.cc", "MIME EMAIL CC", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailCcData);
370 
371  kw.name = "email.date";
372  kw.desc = "'Date' field from an email";
373  kw.url = "/rules/email-keywords.html#email.date";
374  kw.Setup = DetectMimeEmailDateSetup;
377  g_mime_email_date_buffer_id = DetectHelperBufferMpmRegister(
378  "email.date", "MIME EMAIL DATE", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailDateData);
379 
380  kw.name = "email.message_id";
381  kw.desc = "'Message-Id' field from an email";
382  kw.url = "/rules/email-keywords.html#email.message_id";
383  kw.Setup = DetectMimeEmailMessageIdSetup;
386  g_mime_email_message_id_buffer_id = DetectHelperBufferMpmRegister("email.message_id",
387  "MIME EMAIL Message-Id", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailMessageIdData);
388 
389  kw.name = "email.x_mailer";
390  kw.desc = "'X-Mailer' field from an email";
391  kw.url = "/rules/email-keywords.html#email.x_mailer";
392  kw.Setup = DetectMimeEmailXMailerSetup;
395  g_mime_email_x_mailer_buffer_id = DetectHelperBufferMpmRegister("email.x_mailer",
396  "MIME EMAIL X-Mailer", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailXMailerData);
397 
398  kw.name = "email.url";
399  kw.desc = "'Url' extracted from an email";
400  kw.url = "/rules/email-keywords.html#email.url";
401  kw.Setup = DetectMimeEmailUrlSetup;
404  g_mime_email_url_buffer_id = DetectHelperMultiBufferMpmRegister(
405  "email.url", "MIME EMAIL URL", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailUrlData);
406 
407  kw.name = "email.received";
408  kw.desc = "'Received' field from an email";
409  kw.url = "/rules/email-keywords.html#email.received";
410  kw.Setup = DetectMimeEmailReceivedSetup;
413  g_mime_email_received_buffer_id = DetectHelperMultiBufferMpmRegister("email.received",
414  "MIME EMAIL RECEIVED", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailReceivedData);
415 }
DetectEmailRegister
void DetectEmailRegister(void)
Definition: detect-email.c:331
DetectSignatureSetAppProto
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2313
detect-engine.h
SIGMATCH_INFO_STICKY_BUFFER
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect.h:1645
detect-email.h
DetectEngineTransforms
Definition: detect.h:415
InspectionBuffer
Definition: detect.h:380
Flow_
Flow data structure.
Definition: flow.h:356
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:931
rust.h
SCDetectBufferSetActiveList
int SCDetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int list)
Definition: detect-engine-buffer.c:29
InspectionBufferGet
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
Definition: detect-engine.c:1429
DetectHelperKeywordRegister
int DetectHelperKeywordRegister(const SCSigTableAppLiteElmt *kw)
Definition: detect-engine-helper.c:120
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1223
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:38
DetectHelperBufferMpmRegister
int DetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionBufferGetDataPtr GetData)
Definition: detect-engine-helper.c:64
detect-engine-helper.h
SMTPTransaction_
Definition: app-layer-smtp.h:72
detect-engine-content-inspection.h
flags
uint8_t flags
Definition: decode-gre.h:0
detect-engine-buffer.h
InspectionBufferApplyTransforms
void InspectionBufferApplyTransforms(DetectEngineThreadCtx *det_ctx, InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
Definition: detect-engine.c:1501
InspectionBuffer::inspect
const uint8_t * inspect
Definition: detect.h:381
InspectionBufferSetup
void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id, InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
Definition: detect-engine.c:1563
detect-parse.h
Signature_
Signature container.
Definition: detect.h:670
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect.h:1620
DetectHelperMultiBufferMpmRegister
int DetectHelperMultiBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionMultiBufferGetDataPtr GetData)
Definition: detect-engine-helper.c:97
app-layer-smtp.h
SMTPTransaction_::mime_state
MimeStateSMTP * mime_state
Definition: app-layer-smtp.h:85