suricata
detect-tls-sni.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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 /**
19  * \file
20  *
21  * \author Mats Klepsland <mats.klepsland@gmail.com>
22  *
23  * Implements support for tls_sni keyword.
24  */
25 
26 #include "suricata-common.h"
27 #include "threads.h"
28 #include "debug.h"
29 #include "decode.h"
30 #include "detect.h"
31 
32 #include "detect-parse.h"
33 #include "detect-engine.h"
34 #include "detect-engine-mpm.h"
35 #include "detect-content.h"
36 #include "detect-pcre.h"
37 
38 #include "flow.h"
39 #include "flow-util.h"
40 #include "flow-var.h"
41 
42 #include "util-debug.h"
43 #include "util-unittest.h"
44 #include "util-spm.h"
45 #include "util-print.h"
46 
47 #include "stream-tcp.h"
48 
49 #include "app-layer.h"
50 #include "app-layer-ssl.h"
52 #include "detect-tls-sni.h"
53 
54 #include "util-unittest.h"
55 #include "util-unittest-helper.h"
56 
57 static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, const char *);
58 static void DetectTlsSniRegisterTests(void);
59 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
60  const DetectEngineTransforms *transforms,
61  Flow *_f, const uint8_t _flow_flags,
62  void *txv, const int list_id);
63 static int g_tls_sni_buffer_id = 0;
64 
65 /**
66  * \brief Registration function for keyword: tls_sni
67  */
69 {
71  sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer";
72  sigmatch_table[DETECT_AL_TLS_SNI].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-sni";
74  sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup;
76  sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests;
77 
79 
82 
85 
87  "TLS Server Name Indication (SNI) extension");
88 
89  g_tls_sni_buffer_id = DetectBufferTypeGetByName("tls_sni");
90 }
91 
92 
93 /**
94  * \brief this function setup the tls_sni modifier keyword used in the rule
95  *
96  * \param de_ctx Pointer to the Detection Engine Context
97  * \param s Pointer to the Signature to which the current keyword belongs
98  * \param str Should hold an empty string always
99  *
100  * \retval 0 On success
101  */
102 static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
103 {
104  DetectBufferSetActiveList(s, g_tls_sni_buffer_id);
105  s->alproto = ALPROTO_TLS;
106  return 0;
107 }
108 
109 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
110  const DetectEngineTransforms *transforms, Flow *_f,
111  const uint8_t _flow_flags, void *txv, const int list_id)
112 {
113  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
114  if (buffer->inspect == NULL) {
115  SSLState *ssl_state = (SSLState *)_f->alstate;
116 
117  if (ssl_state->client_connp.sni == NULL) {
118  return NULL;
119  }
120 
121  const uint32_t data_len = strlen(ssl_state->client_connp.sni);
122  const uint8_t *data = (uint8_t *)ssl_state->client_connp.sni;
123 
124  InspectionBufferSetup(buffer, data, data_len);
125  InspectionBufferApplyTransforms(buffer, transforms);
126  }
127 
128  return buffer;
129 }
130 
131 #ifdef UNITTESTS
132 
133 /**
134  * \test Test matching on a simple google.com SNI
135  */
136 static int DetectTlsSniTest01(void)
137 {
138  /* client hello */
139  uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0x82, 0x01, 0x00, 0x00, 0x7E,
140  0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87,
141  0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31,
142  0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC,
143  0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00,
144  0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D,
145  0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00,
146  0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35,
147  0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00,
148  0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40,
149  0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00,
150  0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B,
151  0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00,
152  0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00,
153  0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63,
154  0x6F, 0x6D, };
155 
156  Flow f;
157  SSLState *ssl_state = NULL;
158  Packet *p = NULL;
159  Signature *s = NULL;
160  ThreadVars tv;
161  DetectEngineThreadCtx *det_ctx = NULL;
162  TcpSession ssn;
164 
165  memset(&tv, 0, sizeof(ThreadVars));
166  memset(&f, 0, sizeof(Flow));
167  memset(&ssn, 0, sizeof(TcpSession));
168 
169  p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP,
170  "192.168.1.5", "192.168.1.1",
171  41424, 443);
172 
173  FLOW_INITIALIZE(&f);
174  f.protoctx = (void *)&ssn;
175  f.flags |= FLOW_IPV4;
176  f.proto = IPPROTO_TCP;
178 
179  p->flow = &f;
182  f.alproto = ALPROTO_TLS;
183 
185 
187  FAIL_IF_NULL(de_ctx);
188 
190  de_ctx->flags |= DE_QUIET;
191 
192  s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any "
193  "(msg:\"Test tls_sni option\"; "
194  "tls_sni; content:\"google.com\"; sid:1;)");
195  FAIL_IF_NULL(s);
196 
197  SigGroupBuild(de_ctx);
198  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
199 
200  FLOWLOCK_WRLOCK(&f);
201  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS,
202  STREAM_TOSERVER, buf, sizeof(buf));
203  FLOWLOCK_UNLOCK(&f);
204  FAIL_IF(r != 0);
205 
206  ssl_state = f.alstate;
207  FAIL_IF_NULL(ssl_state);
208 
209  /* do detect */
210  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
211 
213 
214  AppLayerParserThreadCtxFree(alp_tctx);
215  DetectEngineThreadCtxDeinit(&tv, det_ctx);
216  DetectEngineCtxFree(de_ctx);
217 
219  FLOW_DESTROY(&f);
220  UTHFreePacket(p);
221 
222  PASS;
223 }
224 
225 /**
226  * \test Test matching on a simple google.com SNI with pcre
227  */
228 static int DetectTlsSniTest02(void)
229 {
230  /* client hello */
231  uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0x82, 0x01, 0x00, 0x00, 0x7E,
232  0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87,
233  0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31,
234  0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC,
235  0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00,
236  0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D,
237  0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00,
238  0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35,
239  0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00,
240  0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40,
241  0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00,
242  0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B,
243  0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00,
244  0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00,
245  0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63,
246  0x6F, 0x6D, };
247 
248  Flow f;
249  SSLState *ssl_state = NULL;
250  Packet *p = NULL;
251  Signature *s = NULL;
252  ThreadVars tv;
253  DetectEngineThreadCtx *det_ctx = NULL;
254  TcpSession ssn;
256 
257  memset(&tv, 0, sizeof(ThreadVars));
258  memset(&f, 0, sizeof(Flow));
259  memset(&ssn, 0, sizeof(TcpSession));
260 
261  p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP,
262  "192.168.1.5", "192.168.1.1",
263  41424, 443);
264 
265  FLOW_INITIALIZE(&f);
266  f.protoctx = (void *)&ssn;
267  f.flags |= FLOW_IPV4;
268  f.proto = IPPROTO_TCP;
270 
271  p->flow = &f;
274  f.alproto = ALPROTO_TLS;
275 
277 
279  FAIL_IF_NULL(de_ctx);
280 
282  de_ctx->flags |= DE_QUIET;
283 
284  s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any "
285  "(msg:\"Test tls_sni option\"; "
286  "tls_sni; content:\"google\"; nocase; "
287  "pcre:\"/google\\.com$/i\"; sid:1;)");
288  FAIL_IF_NULL(s);
289 
290  s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any "
291  "(msg:\"Test tls_sni option\"; "
292  "tls_sni; content:\"google\"; nocase; "
293  "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)");
294  FAIL_IF_NULL(s);
295 
296  SigGroupBuild(de_ctx);
297  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
298 
299  FLOWLOCK_WRLOCK(&f);
300  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS,
301  STREAM_TOSERVER, buf, sizeof(buf));
302  FLOWLOCK_UNLOCK(&f);
303  FAIL_IF(r != 0);
304 
305  ssl_state = f.alstate;
306  FAIL_IF_NULL(ssl_state);
307 
308  /* do detect */
309  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
310 
313 
314  AppLayerParserThreadCtxFree(alp_tctx);
315  DetectEngineThreadCtxDeinit(&tv, det_ctx);
316  DetectEngineCtxFree(de_ctx);
317 
319  FLOW_DESTROY(&f);
320  UTHFreePacket(p);
321 
322  PASS;
323 }
324 
325 #endif
326 
327 static void DetectTlsSniRegisterTests(void)
328 {
329 #ifdef UNITTESTS
330  UtRegisterTest("DetectTlsSniTest01", DetectTlsSniTest01);
331  UtRegisterTest("DetectTlsSniTest02", DetectTlsSniTest02);
332 #endif
333 }
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1406
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1149
struct Flow_ * flow
Definition: decode.h:443
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
uint8_t proto
Definition: flow.h:343
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:242
#define PASS
Pass the test.
int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectMpmAppLayerRegistery *mpm_reg, int list_id)
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition: flow-util.c:95
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:202
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:239
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
const char * name
Definition: detect.h:1163
Signature container.
Definition: detect.h:495
#define TRUE
void * protoctx
Definition: flow.h:395
main detection engine ctx
Definition: detect.h:723
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
SSLv[2.0|3.[0|1|2|3]] state structure.
void * alstate
Definition: flow.h:433
#define DE_QUIET
Definition: detect.h:296
int DetectBufferTypeGetByName(const char *name)
#define str(s)
uint8_t flags
Definition: detect.h:724
void(* Free)(void *)
Definition: detect.h:1154
#define FLOW_DESTROY(f)
Definition: flow-util.h:115
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
uint16_t mpm_matcher
Definition: detect.h:772
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1743
#define SIG_FLAG_TOSERVER
Definition: detect.h:241
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
void DetectAppLayerInspectEngineRegister2(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr2 Callback2, InspectionBufferGetDataPtr GetData)
register inspect engine at start up time
Packet * UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...
uint8_t flowflags
Definition: decode.h:437
#define FLOW_PKT_TOSERVER
Definition: flow.h:200
AppProto alproto
Definition: detect.h:499
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
int DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
const char * desc
Definition: detect.h:1165
void DetectTlsSniRegister(void)
Registration function for keyword: tls_sni.
int mpm_default_matcher
Definition: util-mpm.h:170
void InspectionBufferSetup(InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
void InspectionBufferApplyTransforms(InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
#define SIGMATCH_NOOPT
Definition: detect.h:1331
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1132
const char * url
Definition: detect.h:1166
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define STREAM_TOSERVER
Definition: stream.h:31
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself...
#define PKT_HAS_FLOW
Definition: decode.h:1092
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
int DetectBufferSetActiveList(Signature *s, const int list)
const uint8_t * inspect
Definition: detect.h:347
#define DOC_URL
Definition: suricata.h:86
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
Per thread variable structure.
Definition: threadvars.h:57
AppProto alproto
application level protocol
Definition: flow.h:404
uint32_t flags
Definition: decode.h:441
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1157
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
uint8_t protomap
Definition: flow.h:399
Flow data structure.
Definition: flow.h:324
#define FLOW_IPV4
Definition: flow.h:93
uint32_t flags
Definition: flow.h:374
SSLStateConnp client_connp
#define PKT_STREAM_EST
Definition: decode.h:1090
void(* RegisterTests)(void)
Definition: detect.h:1155
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len)
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectMpmAppLayerRegistery *mpm_reg, int list_id), InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register a MPM engine