From: Victor Julien Date: Thu, 22 Dec 2016 11:45:17 +0000 (+0100) Subject: ssh: convert app-layer parser to be tx aware X-Git-Tag: suricata-4.0.0-beta1~352 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3ee4989ba7c10531d80e17e95bfa2d13951afc20;p=thirdparty%2Fsuricata.git ssh: convert app-layer parser to be tx aware Like with SSL, there is only a single 'tx'. --- diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 7eb529407d..0b965eb748 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -494,9 +494,96 @@ static void SSHStateFree(void *state) if (s->srv_hdr.banner_buffer != NULL) SCFree(s->srv_hdr.banner_buffer); + //AppLayerDecoderEventsFreeEvents(&s->decoder_events); + + if (s->de_state != NULL) { + DetectEngineStateFree(s->de_state); + } + SCFree(s); } +static int SSHStateHasTxDetectState(void *state) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state->de_state) + return 1; + return 0; +} + +static int SSHSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SshState *ssh_state = (SshState *)state; + ssh_state->de_state = de_state; + return 0; +} + +static DetectEngineState *SSHGetTxDetectState(void *vtx) +{ + SshState *ssh_state = (SshState *)vtx; + return ssh_state->de_state; +} + +static void SSHStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *SSHGetTx(void *state, uint64_t tx_id) +{ + SshState *ssh_state = (SshState *)state; + return ssh_state; +} + +static uint64_t SSHGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static void SSHSetTxLogged(void *state, void *tx, uint32_t logger) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state) + ssh_state->logged |= logger; +} + +static int SSHGetTxLogged(void *state, void *tx, uint32_t logger) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state && (ssh_state->logged & logger)) { + return 1; + } + return 0; +} + +static int SSHGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return SSH_STATE_FINISHED; +} + +static int SSHGetAlstateProgress(void *tx, uint8_t direction) +{ + SshState *ssh_state = (SshState *)tx; + + if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && + ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_FINISHED; + } + + if (direction == STREAM_TOSERVER) { + if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_BANNER_DONE; + } + } else { + if (ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_BANNER_DONE; + } + } + + return SSH_STATE_IN_PROGRESS; +} + static int SSHRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH, @@ -532,6 +619,22 @@ void RegisterSSHParsers(void) AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_SSH, STREAM_TOSERVER|STREAM_TOCLIENT); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SSH, SSHStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateHasTxDetectState, + SSHGetTxDetectState, SSHSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SSH, SSHGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SSH, SSHGetAlstateProgress); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxLogged, SSHSetTxLogged); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SSH, + SSHGetAlstateProgressCompletionStatus); } else { // SCLogInfo("Parsed disabled for %s protocol. Protocol detection" // "still on.", proto_name); diff --git a/src/app-layer-ssh.h b/src/app-layer-ssh.h index 4fd59aa9e1..bf8d50b94c 100644 --- a/src/app-layer-ssh.h +++ b/src/app-layer-ssh.h @@ -32,8 +32,6 @@ * must be ciphered, so the parsing finish here */ #define SSH_FLAG_PARSER_DONE 0x02 -#define SSH_FLAG_STATE_LOGGED 0x04 - #define SSH_FLAG_STATE_LOGGED_LUA 0x08 /* MSG_CODE */ @@ -56,6 +54,7 @@ typedef struct SshHeader_ { uint32_t pkt_len; uint8_t padding_len; uint8_t msg_code; + uint16_t banner_len; uint8_t buf[6]; uint8_t buf_offset; uint8_t flags; @@ -63,13 +62,23 @@ typedef struct SshHeader_ { uint8_t *proto_version; uint8_t *software_version; uint8_t *banner_buffer; - uint16_t banner_len; } SshHeader; +enum { + SSH_STATE_IN_PROGRESS, + SSH_STATE_BANNER_DONE, + SSH_STATE_FINISHED, +}; + /** structure to store the SSH state values */ typedef struct SshState_ { SshHeader srv_hdr; SshHeader cli_hdr; + + /* specifies which loggers are done logging */ + uint32_t logged; + + DetectEngineState *de_state; } SshState; void RegisterSSHParsers(void); diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 322a9137fb..96b8c40ec5 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -360,6 +360,7 @@ static int DetectSshVersionTestDetect01(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -477,6 +478,7 @@ static int DetectSshVersionTestDetect02(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -592,6 +594,7 @@ static int DetectSshVersionTestDetect03(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index a9eb19267d..3032b0e6bf 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -332,6 +332,7 @@ static int DetectSshSoftwareVersionTestDetect01(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -449,6 +450,7 @@ static int DetectSshSoftwareVersionTestDetect02(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -565,6 +567,7 @@ static int DetectSshSoftwareVersionTestDetect03(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 627b2b6f59..6d356a0024 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -89,36 +89,29 @@ void JsonSshLogJSON(json_t *tjs, SshState *ssh_state) } -static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *txptr, uint64_t tx_id) { JsonSshLogThread *aft = (JsonSshLogThread *)thread_data; OutputSshCtx *ssh_ctx = aft->sshlog_ctx; - if (unlikely(p->flow == NULL)) { - return 0; - } - - /* check if we have SSH state or not */ - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto end; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); + SshState *ssh_state = (SshState *)state; if (unlikely(ssh_state == NULL)) { - goto end; + return 0; } - if (ssh_state->cli_hdr.software_version == NULL || ssh_state->srv_hdr.software_version == NULL) - goto end; + if (ssh_state->cli_hdr.software_version == NULL || + ssh_state->srv_hdr.software_version == NULL) + return 0; json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO if (unlikely(js == NULL)) - goto end; + return 0; json_t *tjs = json_object(); if (tjs == NULL) { free(js); - goto end; + return 0; } /* reset */ @@ -132,9 +125,6 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) json_object_clear(js); json_decref(js); - /* we only log the state once */ - ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED; -end: return 0; } @@ -230,6 +220,7 @@ OutputCtx *OutputSshLogInit(ConfNode *conf) output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinit; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); return output_ctx; } @@ -267,58 +258,24 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinitSub; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); return output_ctx; } -/** \internal - * \brief Condition function for SSH logger - * \retval bool true or false -- log now? - */ -static int JsonSshCondition(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto dontlog; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); - if (ssh_state == NULL) { - SCLogDebug("no ssh state, so no logging"); - goto dontlog; - } - - /* we only log the state once */ - if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED) - goto dontlog; - - if (ssh_state->cli_hdr.software_version == NULL || - ssh_state->srv_hdr.software_version == NULL) - goto dontlog; - - /* todo: logic to log once */ - - return TRUE; -dontlog: - return FALSE; -} - void JsonSshLogRegister (void) { /* register as separate module */ - OutputRegisterPacketModule(LOGGER_JSON_SSH, "JsonSshLog", "ssh-json-log", - OutputSshLogInit, JsonSshLogger, JsonSshCondition, JsonSshLogThreadInit, - JsonSshLogThreadDeinit, NULL); + OutputRegisterTxModuleWithProgress(LOGGER_JSON_SSH, + "JsonSshLog", "ssh-json-log", + OutputSshLogInit, ALPROTO_SSH, JsonSshLogger, + SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE, + JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterPacketSubModule(LOGGER_JSON_SSH, "eve-log", "JsonSshLog", - "eve-log.ssh", OutputSshLogInitSub, JsonSshLogger, JsonSshCondition, + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_SSH, + "eve-log", "JsonSshLog", "eve-log.ssh", + OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger, + SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE, JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); }