From: Mats Klepsland Date: Thu, 15 Nov 2018 18:49:11 +0000 (+0100) Subject: app-layer-ssl: generate JA3S fingerprints X-Git-Tag: suricata-5.0.0-rc1~472 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a4471987bacca2ab92a7400ed925923f0f533c83;p=thirdparty%2Fsuricata.git app-layer-ssl: generate JA3S fingerprints Generate JA3S fingerprints based on fields in the ServerHello record. --- diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 96411cd268..ae7aa46e90 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -668,14 +668,12 @@ static inline int TLSDecodeHSHelloVersion(SSLState *ssl_state, ssl_state->curr_connp->version = TLS_VERSION_13_PRE_DRAFT16; } - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - ssl_config.enable_ja3 && ssl_state->ja3_str == NULL) { - - ssl_state->ja3_str = Ja3BufferInit(); - if (ssl_state->ja3_str == NULL) + if (ssl_config.enable_ja3 && ssl_state->curr_connp->ja3_str == NULL) { + ssl_state->curr_connp->ja3_str = Ja3BufferInit(); + if (ssl_state->curr_connp->ja3_str == NULL) return -1; - int rc = Ja3BufferAddValue(&ssl_state->ja3_str, version); + int rc = Ja3BufferAddValue(&ssl_state->curr_connp->ja3_str, version); if (rc != 0) return -1; } @@ -761,59 +759,63 @@ static inline int TLSDecodeHSHelloCipherSuites(SSLState *ssl_state, if (!(HAS_SPACE(2))) goto invalid_length; + uint16_t cipher_suites_length; + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { - /* Skip cipher suite */ + cipher_suites_length = 2; + } else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + cipher_suites_length = *input << 8 | *(input + 1); input += 2; } else { - uint16_t cipher_suites_length = *input << 8 | *(input + 1); - input += 2; + return -1; + } - if (!(HAS_SPACE(cipher_suites_length))) - goto invalid_length; + if (!(HAS_SPACE(cipher_suites_length))) + goto invalid_length; - /* Cipher suites length should always be divisible by 2 */ - if ((cipher_suites_length % 2) != 0) { - goto invalid_length; - } + /* Cipher suites length should always be divisible by 2 */ + if ((cipher_suites_length % 2) != 0) { + goto invalid_length; + } - if (ssl_config.enable_ja3) { - int rc; + if (ssl_config.enable_ja3) { + int rc; - JA3Buffer *ja3_cipher_suites = Ja3BufferInit(); - if (ja3_cipher_suites == NULL) - return -1; + JA3Buffer *ja3_cipher_suites = Ja3BufferInit(); + if (ja3_cipher_suites == NULL) + return -1; - uint16_t processed_len = 0; - /* coverity[tainted_data] */ - while (processed_len < cipher_suites_length) - { - if (!(HAS_SPACE(2))) { - Ja3BufferFree(&ja3_cipher_suites); - goto invalid_length; - } + uint16_t processed_len = 0; + /* coverity[tainted_data] */ + while (processed_len < cipher_suites_length) + { + if (!(HAS_SPACE(2))) { + Ja3BufferFree(&ja3_cipher_suites); + goto invalid_length; + } - uint16_t cipher_suite = *input << 8 | *(input + 1); - input += 2; + uint16_t cipher_suite = *input << 8 | *(input + 1); + input += 2; - if (TLSDecodeValueIsGREASE(cipher_suite) != 1) { - rc = Ja3BufferAddValue(&ja3_cipher_suites, cipher_suite); - if (rc != 0) { - return -1; - } + if (TLSDecodeValueIsGREASE(cipher_suite) != 1) { + rc = Ja3BufferAddValue(&ja3_cipher_suites, cipher_suite); + if (rc != 0) { + return -1; } - - processed_len += 2; } - rc = Ja3BufferAppendBuffer(&ssl_state->ja3_str, &ja3_cipher_suites); - if (rc == -1) { - return -1; - } + processed_len += 2; + } - } else { - /* Skip cipher suites */ - input += cipher_suites_length; + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, + &ja3_cipher_suites); + if (rc == -1) { + return -1; } + + } else { + /* Skip cipher suites */ + input += cipher_suites_length; } return (input - initial_input); @@ -1113,14 +1115,20 @@ static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state, JA3Buffer *ja3_elliptic_curves = NULL; JA3Buffer *ja3_elliptic_curves_pf = NULL; - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - ssl_config.enable_ja3) { + if (ssl_config.enable_ja3) { ja3_extensions = Ja3BufferInit(); - ja3_elliptic_curves = Ja3BufferInit(); - ja3_elliptic_curves_pf = Ja3BufferInit(); - if (ja3_extensions == NULL || ja3_elliptic_curves == NULL || - ja3_elliptic_curves_pf == NULL) + if (ja3_extensions == NULL) goto error; + + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + ja3_elliptic_curves = Ja3BufferInit(); + if (ja3_elliptic_curves == NULL) + goto error; + + ja3_elliptic_curves_pf = Ja3BufferInit(); + if (ja3_elliptic_curves_pf == NULL) + goto error; + } } /* Extensions are optional (RFC5246 section 7.4.1.2) */ @@ -1239,8 +1247,7 @@ static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state, } } - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - ssl_config.enable_ja3) { + if (ssl_config.enable_ja3) { if (TLSDecodeValueIsGREASE(ext_type) != 1) { rc = Ja3BufferAddValue(&ja3_extensions, ext_type); if (rc != 0) @@ -1252,20 +1259,23 @@ static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state, } end: - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - ssl_config.enable_ja3) { - rc = Ja3BufferAppendBuffer(&ssl_state->ja3_str, &ja3_extensions); + if (ssl_config.enable_ja3) { + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, + &ja3_extensions); if (rc == -1) goto error; - rc = Ja3BufferAppendBuffer(&ssl_state->ja3_str, &ja3_elliptic_curves); - if (rc == -1) - goto error; + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, + &ja3_elliptic_curves); + if (rc == -1) + goto error; - rc = Ja3BufferAppendBuffer(&ssl_state->ja3_str, - &ja3_elliptic_curves_pf); - if (rc == -1) - goto error; + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, + &ja3_elliptic_curves_pf); + if (rc == -1) + goto error; + } } return (input - initial_input); @@ -1343,9 +1353,8 @@ static int TLSDecodeHandshakeHello(SSLState *ssl_state, if (ret < 0) goto end; - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - ssl_config.enable_ja3 && ssl_state->ja3_hash == NULL) { - ssl_state->ja3_hash = Ja3GenerateHash(ssl_state->ja3_str); + if (ssl_config.enable_ja3 && ssl_state->curr_connp->ja3_hash == NULL) { + ssl_state->curr_connp->ja3_hash = Ja3GenerateHash(ssl_state->curr_connp->ja3_str); } end: @@ -2596,10 +2605,14 @@ static void SSLStateFree(void *p) if (ssl_state->server_connp.session_id) SCFree(ssl_state->server_connp.session_id); - if (ssl_state->ja3_str) - Ja3BufferFree(&ssl_state->ja3_str); - if (ssl_state->ja3_hash) - SCFree(ssl_state->ja3_hash); + if (ssl_state->client_connp.ja3_str) + Ja3BufferFree(&ssl_state->client_connp.ja3_str); + if (ssl_state->client_connp.ja3_hash) + SCFree(ssl_state->client_connp.ja3_hash); + if (ssl_state->server_connp.ja3_str) + Ja3BufferFree(&ssl_state->server_connp.ja3_str); + if (ssl_state->server_connp.ja3_hash) + SCFree(ssl_state->server_connp.ja3_hash); AppLayerDecoderEventsFreeEvents(&ssl_state->decoder_events); diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index d58bcef0e0..0c3133a6ae 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -208,6 +208,9 @@ typedef struct SSLStateConnp_ { uint32_t cert_log_flag; + JA3Buffer *ja3_str; + char *ja3_hash; + /* buffer for the tls record. * We use a malloced buffer, if the record is fragmented */ uint8_t *trec; @@ -240,9 +243,6 @@ typedef struct SSLState_ { uint32_t current_flags; - JA3Buffer *ja3_str; - char *ja3_hash; - SSLStateConnp *curr_connp; SSLStateConnp client_connp; diff --git a/src/detect-tls-ja3-hash.c b/src/detect-tls-ja3-hash.c index 41b580b516..daefa443b1 100644 --- a/src/detect-tls-ja3-hash.c +++ b/src/detect-tls-ja3-hash.c @@ -138,12 +138,12 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, if (buffer->inspect == NULL) { const SSLState *ssl_state = (SSLState *)f->alstate; - if (ssl_state->ja3_hash == NULL) { + if (ssl_state->client_connp.ja3_hash == NULL) { return NULL; } - const uint32_t data_len = strlen(ssl_state->ja3_hash); - const uint8_t *data = (uint8_t *)ssl_state->ja3_hash; + const uint32_t data_len = strlen(ssl_state->client_connp.ja3_hash); + const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_hash; InspectionBufferSetup(buffer, data, data_len); InspectionBufferApplyTransforms(buffer, transforms); diff --git a/src/detect-tls-ja3-string.c b/src/detect-tls-ja3-string.c index cd92645cb7..d253fc289e 100644 --- a/src/detect-tls-ja3-string.c +++ b/src/detect-tls-ja3-string.c @@ -128,13 +128,13 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, if (buffer->inspect == NULL) { const SSLState *ssl_state = (SSLState *)f->alstate; - if (ssl_state->ja3_str == NULL || - ssl_state->ja3_str->data == NULL) { + if (ssl_state->client_connp.ja3_str == NULL || + ssl_state->client_connp.ja3_str->data == NULL) { return NULL; } - const uint32_t data_len = strlen(ssl_state->ja3_str->data); - const uint8_t *data = (uint8_t *)ssl_state->ja3_str->data; + const uint32_t data_len = strlen(ssl_state->client_connp.ja3_str->data); + const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_str->data; InspectionBufferSetup(buffer, data, data_len); InspectionBufferApplyTransforms(buffer, transforms); diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 9284f79f14..9f92d24b22 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -199,17 +199,18 @@ static void JsonTlsLogNotAfter(json_t *js, SSLState *ssl_state) static void JsonTlsLogJa3Hash(json_t *js, SSLState *ssl_state) { - if (ssl_state->ja3_hash != NULL) { - json_object_set_new(js, "hash", json_string(ssl_state->ja3_hash)); + if (ssl_state->client_connp.ja3_hash != NULL) { + json_object_set_new(js, "hash", + json_string(ssl_state->client_connp.ja3_hash)); } } static void JsonTlsLogJa3String(json_t *js, SSLState *ssl_state) { - if ((ssl_state->ja3_str != NULL) && - ssl_state->ja3_str->data != NULL) { + if ((ssl_state->client_connp.ja3_str != NULL) && + ssl_state->client_connp.ja3_str->data != NULL) { json_object_set_new(js, "string", - json_string(ssl_state->ja3_str->data)); + json_string(ssl_state->client_connp.ja3_str->data)); } } diff --git a/src/tests/detect-tls-ja3-hash.c b/src/tests/detect-tls-ja3-hash.c index 70702b112e..3e666a9aa3 100644 --- a/src/tests/detect-tls-ja3-hash.c +++ b/src/tests/detect-tls-ja3-hash.c @@ -106,7 +106,7 @@ static int DetectTlsJa3HashTest01(void) ssl_state = f.alstate; FAIL_IF_NULL(ssl_state); - FAIL_IF_NULL(ssl_state->ja3_hash); + FAIL_IF_NULL(ssl_state->client_connp.ja3_hash); SigMatchSignatures(&tv, de_ctx, det_ctx, p); @@ -202,7 +202,7 @@ static int DetectTlsJa3HashTest02(void) ssl_state = f.alstate; FAIL_IF_NULL(ssl_state); - FAIL_IF_NULL(ssl_state->ja3_hash); + FAIL_IF_NULL(ssl_state->client_connp.ja3_hash); SigMatchSignatures(&tv, de_ctx, det_ctx, p); diff --git a/src/tests/detect-tls-ja3-string.c b/src/tests/detect-tls-ja3-string.c index 913e0c864e..2363c8d8ad 100644 --- a/src/tests/detect-tls-ja3-string.c +++ b/src/tests/detect-tls-ja3-string.c @@ -105,8 +105,8 @@ static int DetectTlsJa3StringTest01(void) ssl_state = f.alstate; FAIL_IF_NULL(ssl_state); - FAIL_IF_NULL(ssl_state->ja3_str); - FAIL_IF_NULL(ssl_state->ja3_str->data); + FAIL_IF_NULL(ssl_state->client_connp.ja3_str); + FAIL_IF_NULL(ssl_state->client_connp.ja3_str->data); SigMatchSignatures(&tv, de_ctx, det_ctx, p); diff --git a/src/util-lua-ja3.c b/src/util-lua-ja3.c index 28c90a2f48..7029e2f2c1 100644 --- a/src/util-lua-ja3.c +++ b/src/util-lua-ja3.c @@ -73,11 +73,12 @@ static int Ja3GetHash(lua_State *luastate) SSLState *ssl_state = (SSLState *)state; - if (ssl_state->ja3_hash == NULL) + if (ssl_state->client_connp.ja3_hash == NULL) return LuaCallbackError(luastate, "error: no JA3 hash"); - return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->ja3_hash, - strlen(ssl_state->ja3_hash)); + return LuaPushStringBuffer(luastate, + (uint8_t *)ssl_state->client_connp.ja3_hash, + strlen(ssl_state->client_connp.ja3_hash)); } static int Ja3GetString(lua_State *luastate) @@ -95,11 +96,13 @@ static int Ja3GetString(lua_State *luastate) SSLState *ssl_state = (SSLState *)state; - if (ssl_state->ja3_str == NULL || ssl_state->ja3_str->data == NULL) + if (ssl_state->client_connp.ja3_str == NULL || + ssl_state->client_connp.ja3_str->data == NULL) return LuaCallbackError(luastate, "error: no JA3 str"); - return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->ja3_str->data, - ssl_state->ja3_str->used); + return LuaPushStringBuffer(luastate, + (uint8_t *)ssl_state->client_connp.ja3_str->data, + ssl_state->client_connp.ja3_str->used); } /** *\brief Register JA3 Lua extensions */