Skip to content

Commit

Permalink
Add negation support for TLS and corresponding unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron committed Oct 1, 2021
1 parent 8536048 commit f8b4cdf
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 14 deletions.
5 changes: 3 additions & 2 deletions doc/userguide/rules/tls-keywords.rst
Expand Up @@ -153,11 +153,12 @@ Example::
tls.version
-----------

Match on negotiated TLS/SSL version.
Match on negotiated TLS/SSL version. Supports negation of the version match.

Supported values: "1.0", "1.1", "1.2", "1.3"
Supported values: "1.0", "1.1", "1.2", "1.3", "!1.0", "!1.1", "!1.2", "!1.3"

It is also possible to match versions using a hex string.
These can also be inverted.

Examples::

Expand Down
25 changes: 17 additions & 8 deletions src/detect-tls-version.c
Expand Up @@ -54,7 +54,7 @@
/**
* \brief Regex for parsing "id" option, matching number or "number"
*/
#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9\\.]+\")\\s*$"
#define PARSE_REGEX "^\\s*(!?[A-z0-9\\.]+|\"[A-z0-9\\.]+\")\\s*$"

static DetectParseRegex parse_regex;

Expand Down Expand Up @@ -135,6 +135,11 @@ static int DetectTlsVersionMatch (DetectEngineThreadCtx *det_ctx,
ret = 1;
}

if (tls_data->flags & SIGMATCH_HANDLE_NEGATION) {
/* Inverse match result for negated sig */
ret = (ret == 0) ? 1 : 0;
}

SCReturnInt(ret);
}

Expand All @@ -152,9 +157,9 @@ static DetectTlsVersionData *DetectTlsVersionParse (DetectEngineCtx *de_ctx, con
uint16_t temp;
DetectTlsVersionData *tls = NULL;
int ret = 0, res = 0;
size_t pcre2len;
int ov[MAX_SUBSTRINGS];

ret = DetectParsePcreExec(&parse_regex, str, 0, 0);
ret = DetectParsePcreExec(&parse_regex, str, 0, 0, ov, MAX_SUBSTRINGS);
if (ret < 1 || ret > 3) {
SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.version option");
goto error;
Expand All @@ -163,11 +168,9 @@ static DetectTlsVersionData *DetectTlsVersionParse (DetectEngineCtx *de_ctx, con
if (ret > 1) {
char ver_ptr[64];
char *tmp_str;
pcre2len = sizeof(ver_ptr);
res = pcre2_substring_copy_bynumber(
parse_regex.match, 1, (PCRE2_UCHAR8 *)ver_ptr, &pcre2len);
res = pcre_copy_substring((char *)str, ov, MAX_SUBSTRINGS, 1, ver_ptr, sizeof(ver_ptr));
if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_copy_bynumber failed");
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
goto error;
}

Expand All @@ -185,6 +188,11 @@ static DetectTlsVersionData *DetectTlsVersionParse (DetectEngineCtx *de_ctx, con
tmp_str += 1;
}

if (tmp_str[0] == '!') {
tls->flags |= SIGMATCH_HANDLE_NEGATION;
tmp_str++;
}

if (strncmp("1.0", tmp_str, 3) == 0) {
temp = TLS_VERSION_10;
} else if (strncmp("1.1", tmp_str, 3) == 0) {
Expand All @@ -203,7 +211,8 @@ static DetectTlsVersionData *DetectTlsVersionParse (DetectEngineCtx *de_ctx, con

tls->ver = temp;

SCLogDebug("will look for tls %"PRIu16"", tls->ver);
SCLogDebug("will look for tls %s%" PRIu16 "",
(tls->flags & SIGMATCH_HANDLE_NEGATION) ? "!" : "", tls->ver);
}

return tls;
Expand Down
115 changes: 111 additions & 4 deletions src/tests/detect-tls-version.c
Expand Up @@ -32,6 +32,7 @@ static int DetectTlsVersionTestParse01 (void)
tls = DetectTlsVersionParse(NULL, "1.0");
FAIL_IF_NULL(tls);
FAIL_IF_NOT(tls->ver == TLS_VERSION_10);
FAIL_IF(tls->flags & SIGMATCH_HANDLE_NEGATION);
DetectTlsVersionFree(NULL, tls);
PASS;
}
Expand All @@ -50,6 +51,21 @@ static int DetectTlsVersionTestParse02 (void)
PASS;
}

/**
* \test DetectTlsVersionTestParse03 is a test to make sure that we parse the "id"
* option correctly when given valid (negated) id option
*/
static int DetectTlsVersionTestParse03(void)
{
DetectTlsVersionData *tls = NULL;
tls = DetectTlsVersionParse(NULL, "!1.0");
FAIL_IF_NULL(tls);
FAIL_IF_NOT(tls->ver == TLS_VERSION_10);
FAIL_IF_NOT(tls->flags & SIGMATCH_HANDLE_NEGATION);
DetectTlsVersionFree(NULL, tls);
PASS;
}

#include "stream-tcp-reassemble.h"

/** \test Send a get request in three chunks + more data. */
Expand Down Expand Up @@ -86,7 +102,7 @@ static int DetectTlsVersionTestDetect01(void)
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_TLS;

StreamTcpInitConfig(true);
StreamTcpInitConfig(TRUE);

DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Expand Down Expand Up @@ -139,7 +155,7 @@ static int DetectTlsVersionTestDetect01(void)
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);

StreamTcpFreeConfig(true);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);

UTHFreePackets(&p, 1);
Expand Down Expand Up @@ -180,7 +196,7 @@ static int DetectTlsVersionTestDetect02(void)
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
f.alproto = ALPROTO_TLS;

StreamTcpInitConfig(true);
StreamTcpInitConfig(TRUE);

DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Expand Down Expand Up @@ -228,7 +244,96 @@ static int DetectTlsVersionTestDetect02(void)
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);

StreamTcpFreeConfig(true);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);

UTHFreePackets(&p, 1);

PASS;
}

/*
* Test that a TLS version 1.0 packet will match on a !1.1 version signature
*/
static int DetectTlsVersionTestDetect03(void)
{
Flow f;
uint8_t tlsbuf1[] = { 0x16 };
uint32_t tlslen1 = sizeof(tlsbuf1);
uint8_t tlsbuf2[] = { 0x03 };
uint32_t tlslen2 = sizeof(tlsbuf2);
uint8_t tlsbuf3[] = { 0x01 };
uint32_t tlslen3 = sizeof(tlsbuf3);
uint8_t tlsbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 };
uint32_t tlslen4 = sizeof(tlsbuf4);
TcpSession ssn;
Packet *p = NULL;
Signature *s = NULL;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx = NULL;
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();

memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));

p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);

FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.proto = IPPROTO_TCP;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
f.alproto = ALPROTO_TLS;

StreamTcpInitConfig(TRUE);

DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);

de_ctx->flags |= DE_QUIET;

s = de_ctx->sig_list =
SigInit(de_ctx, "alert tls any any -> any any (msg:\"TLS\"; tls.version:!1.1; sid:1;)");
FAIL_IF_NULL(s);

SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);

int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1);
FAIL_IF(r != 0);

r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2);
FAIL_IF(r != 0);

r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3);
FAIL_IF(r != 0);

r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4);
FAIL_IF(r != 0);

SSLState *ssl_state = f.alstate;
FAIL_IF_NULL(ssl_state);

FAIL_IF(ssl_state->client_connp.content_type != 0x16);

FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10);

/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);

FAIL_IF_NOT(PacketAlertCheck(p, 1));

AppLayerParserThreadCtxFree(alp_tctx);
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);

DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);

StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);

UTHFreePackets(&p, 1);
Expand All @@ -243,8 +348,10 @@ static void DetectTlsVersionRegisterTests(void)
{
UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01);
UtRegisterTest("DetectTlsVersionTestParse02", DetectTlsVersionTestParse02);
UtRegisterTest("DetectTlsVersionTestParse03", DetectTlsVersionTestParse03);
UtRegisterTest("DetectTlsVersionTestDetect01",
DetectTlsVersionTestDetect01);
UtRegisterTest("DetectTlsVersionTestDetect02",
DetectTlsVersionTestDetect02);
UtRegisterTest("DetectTlsVersionTestDetect03", DetectTlsVersionTestDetect03);
}

0 comments on commit f8b4cdf

Please sign in to comment.