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  if (SCDetectMimeEmailGetUrl(tx->mime_state, buf, buf_len, idx) != 1) {
198  return false;
199  }
200  return true;
201 }
202 
203 static int DetectMimeEmailReceivedSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
204 {
205  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_received_buffer_id) < 0)
206  return -1;
207 
209  return -1;
210 
211  return 0;
212 }
213 
214 static bool GetMimeEmailReceivedData(DetectEngineThreadCtx *det_ctx, const void *txv,
215  const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
216 {
217  SMTPTransaction *tx = (SMTPTransaction *)txv;
218 
219  if (tx->mime_state == NULL) {
220  return false;
221  }
222 
223  if (SCDetectMimeEmailGetDataArray(tx->mime_state, buf, buf_len, "received", idx) != 1) {
224  return false;
225  }
226  return true;
227 }
228 
230 
231 static int DetectMimeEmailBodyMd5Setup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
232 {
233  if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_body_md5_buffer_id) < 0)
234  return -1;
235 
237  return -1;
238 
239  if (!MimeBodyMd5IsEnabled()) {
240  // we registered the keyword if not explicitly disabled, so we are here in auto mode
241  SCMimeSmtpConfigBodyMd5(true);
242  }
243 
244  return 0;
245 }
246 
247 static bool GetMimeEmailBodyMd5Data(
248  const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
249 {
250  SMTPTransaction *tx = (SMTPTransaction *)txv;
251  if (tx->mime_state == NULL)
252  return false;
253 
254  SCDetectMimeEmailGetBodyMd5(tx->mime_state, data, data_len);
255 
256  return true;
257 }
258 
260 {
261  SCSigTableAppLiteElmt kw = { 0 };
262 
263  kw.name = "email.from";
264  kw.desc = "'From' field from an email";
265  kw.url = "/rules/email-keywords.html#email.from";
266  kw.Setup = DetectMimeEmailFromSetup;
269  g_mime_email_from_buffer_id = SCDetectHelperBufferMpmRegister(
270  "email.from", "MIME EMAIL FROM", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailFromData);
271 
272  kw.name = "email.subject";
273  kw.desc = "'Subject' field from an email";
274  kw.url = "/rules/email-keywords.html#email.subject";
275  kw.Setup = DetectMimeEmailSubjectSetup;
278  g_mime_email_subject_buffer_id = SCDetectHelperBufferMpmRegister("email.subject",
279  "MIME EMAIL SUBJECT", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailSubjectData);
280 
281  kw.name = "email.to";
282  kw.desc = "'To' field from an email";
283  kw.url = "/rules/email-keywords.html#email.to";
284  kw.Setup = DetectMimeEmailToSetup;
287  g_mime_email_to_buffer_id = SCDetectHelperBufferMpmRegister(
288  "email.to", "MIME EMAIL TO", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailToData);
289 
290  kw.name = "email.cc";
291  kw.desc = "'Cc' field from an email";
292  kw.url = "/rules/email-keywords.html#email.cc";
293  kw.Setup = DetectMimeEmailCcSetup;
296  g_mime_email_cc_buffer_id = SCDetectHelperBufferMpmRegister(
297  "email.cc", "MIME EMAIL CC", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailCcData);
298 
299  kw.name = "email.date";
300  kw.desc = "'Date' field from an email";
301  kw.url = "/rules/email-keywords.html#email.date";
302  kw.Setup = DetectMimeEmailDateSetup;
305  g_mime_email_date_buffer_id = SCDetectHelperBufferMpmRegister(
306  "email.date", "MIME EMAIL DATE", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailDateData);
307 
308  kw.name = "email.message_id";
309  kw.desc = "'Message-Id' field from an email";
310  kw.url = "/rules/email-keywords.html#email.message_id";
311  kw.Setup = DetectMimeEmailMessageIdSetup;
314  g_mime_email_message_id_buffer_id = SCDetectHelperBufferMpmRegister("email.message_id",
315  "MIME EMAIL Message-Id", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailMessageIdData);
316 
317  kw.name = "email.x_mailer";
318  kw.desc = "'X-Mailer' field from an email";
319  kw.url = "/rules/email-keywords.html#email.x_mailer";
320  kw.Setup = DetectMimeEmailXMailerSetup;
323  g_mime_email_x_mailer_buffer_id = SCDetectHelperBufferMpmRegister("email.x_mailer",
324  "MIME EMAIL X-Mailer", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailXMailerData);
325 
326  kw.name = "email.url";
327  kw.desc = "'Url' extracted from an email";
328  kw.url = "/rules/email-keywords.html#email.url";
329  kw.Setup = DetectMimeEmailUrlSetup;
332  g_mime_email_url_buffer_id = SCDetectHelperMultiBufferMpmRegister(
333  "email.url", "MIME EMAIL URL", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailUrlData);
334 
335  kw.name = "email.received";
336  kw.desc = "'Received' field from an email";
337  kw.url = "/rules/email-keywords.html#email.received";
338  kw.Setup = DetectMimeEmailReceivedSetup;
341  g_mime_email_received_buffer_id = SCDetectHelperMultiBufferMpmRegister("email.received",
342  "MIME EMAIL RECEIVED", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailReceivedData);
343 
344  if (!MimeBodyMd5IsDisabled()) {
345  // do not register the keyword if explicitly disabled
346  kw.name = "email.body_md5";
347  kw.desc = "'md5' hash generated from an email body";
348  kw.url = "/rules/email-keywords.html#email.body_md5";
349  kw.Setup = DetectMimeEmailBodyMd5Setup;
352  // We do not need a progress because SMTP tx has only progress 0 or 1
353  // even if we have a MimeSmtpMd5State enumeration
354  g_mime_email_body_md5_buffer_id = SCDetectHelperBufferMpmRegister("email.body_md5",
355  "MIME EMAIL BODY MD5", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailBodyMd5Data);
357  }
358 }
DetectEmailRegister
void DetectEmailRegister(void)
Definition: detect-email.c:259
detect-engine.h
SCSigTableAppLiteElmt::url
const char * url
keyword documentation url
Definition: detect-engine-helper.h:55
SIGMATCH_INFO_STICKY_BUFFER
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect.h:1674
detect-email.h
SCSigTableAppLiteElmt::name
const char * name
keyword name
Definition: detect-engine-helper.h:51
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
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:2229
DetectMd5ValidateCallback
bool DetectMd5ValidateCallback(const Signature *s, const char **sigerror, const DetectBufferType *map)
Definition: detect-engine.c:5013
SCSigTableAppLiteElmt
App-layer light version of SigTableElmt.
Definition: detect-engine-helper.h:49
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1244
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:72
SCDetectHelperKeywordRegister
uint16_t SCDetectHelperKeywordRegister(const SCSigTableAppLiteElmt *kw)
Definition: detect-engine-helper.c:103
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:80
detect-engine-buffer.h
SIGMATCH_INFO_MULTI_BUFFER
#define SIGMATCH_INFO_MULTI_BUFFER
Definition: detect.h:1684
detect-parse.h
DETECT_EMAIL_BODY_MD5
int DETECT_EMAIL_BODY_MD5
Definition: detect-email.c:229
Signature_
Signature container.
Definition: detect.h:668
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect.h:1649
app-layer-smtp.h
SMTPTransaction_::mime_state
MimeStateSMTP * mime_state
Definition: app-layer-smtp.h:85