mirror of https://github.com/OISF/suricata
ssh: expose the parse failure reason and state in the eve ssh log
A flow that hit an unrecoverable ssh parse error (invalid banner or invalid record) was never visible in the eve ssh output: the log condition only admitted a successful handshake (both directions at kex or session), and the tx logger is one-shot, so the successful-handshake log fired before a later failure could be reported and the failure was then silent - the reason was only visible through the app-layer events. The log condition is now failure-only: the failure latches, so the object is emitted exactly once - at the failure, carrying the error field (invalid_banner / invalid_record) and the state field (the state the failure occurred in - banner, kex, or session if a later record fails after NewKeys) - and successful flows are logged at the flow-end flush, where the engine logs unconditionally. Logging on the success condition mid-flow would consume the one-shot tx log and drop a later failure, so it is not done. The state field is emitted only alongside the error. The object may be error + state only, when no banner was parsed. A unit test pins the condition for a failed, a banner-only and a both-at-kex flow (the failure admits the log on the failing delivery); the user guide and eve reference doc commits that follow carry the field docs. That flow-end flush is skipped for flows that end without a further app-layer update, though: in IPS/firewall mode a drop disables the app layer (StreamTcpCheckFlowDrops -> StreamTcpDisableAppLayer), after which no app-layer update reaches the tx loggers, and a bypassed flow gets no flow-end packet either. A successful ssh record - e.g. one that only saw the banners - was therefore never emitted for those flows. The hook is the app-layer end: on the transition to app-layer EOF, StreamTcpDisableAppLayer raises FLOW_APP_LAYER_FLUSH_PENDING, and FlowUpdateState raises it on the transition to a bypassed state; OutputTxLog runs the tx loggers once for the next packet, also when that packet itself has no app-layer update and is not marked established (the disabling packet returns from the stream engine before that), and flow-worker clears the flag when it frees the app layer of a bypassed flow. The flush is deliberately not a flow-end flush: when the flush is the only reason to run the loggers, eof is not forced, so each logger's condition decides and no other parser starts logging records it suppressed; a disabling packet that does carry an app-layer update keeps the existing EOF behaviour. SSHTxLogCondition admits an IPS drop or a bypass, so the pending record is emitted there; an IDS drop does not end the app layer, so the condition stays failure-only - a later failure still wins, and the success record is emitted by the flow-end flush, which the flow timeout path now also runs for IDS-dropped flows. The unrelated schema-sort ordering of the new state keys is fixed up as well. Ticket: #9046.pull/16368/head
parent
8e15c145fc
commit
6792375d62
Loading…
Reference in New Issue