Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decouple stream bypass from TLS encrypted bypass v4 #11831

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions doc/userguide/configuration/suricata-yaml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1732,21 +1732,26 @@ Encrypted traffic

There is no decryption of encrypted traffic, so once the handshake is complete
continued tracking of the session is of limited use. The ``encryption-handling``
option controls the behavior after the handshake.
option in ``app-layer.protocols.tls`` and ``app-layer.protocols.ssh`` controls
the behavior after the handshake.

If ``encryption-handling`` is set to ``default`` (or if the option is not set),
Suricata will continue to track the SSL/TLS session. Inspection will be limited,
as raw ``content`` inspection will still be disabled. There is no point in doing
pattern matching on traffic known to be encrypted. Inspection for (encrypted)
Heartbleed and other protocol anomalies still happens.
If ``encryption-handling`` in TLS protocol is set to ``default``
(or if the option is not set), Suricata will continue to track the SSL/TLS
session. Inspection will be limited, as raw ``content`` inspection will still
be disabled. There is no point in doing pattern matching on traffic known to
be encrypted. Inspection for (encrypted) Heartbleed and other protocol
anomalies still happens.

When ``encryption-handling`` is set to ``bypass``, all processing of this session is
stopped. No further parsing and inspection happens. If ``stream.bypass`` is enabled
this will lead to the flow being bypassed, either inside Suricata or by the
capture method if it supports it and is configured for it.
.. note:: The ``encryption-handling: default`` option is only available for
SSL/TLS and not for SSH protocol.

Finally, if ``encryption-handling`` is set to ``full``, Suricata will process the
flow as normal, without inspection limitations or bypass.
When ``encryption-handling`` is set to ``bypass``, all processing of this
session is stopped. No further parsing and inspection happens. This will also
lead to the flow being bypassed, either inside Suricata or by the capture method
if it supports it and is configured for it.

Finally, if ``encryption-handling`` is set to ``full``, Suricata will process
the flow as normal, without inspection limitations or bypass.

The option has replaced the ``no-reassemble`` option. If ``no-reassemble`` is
present, and ``encryption-handling`` is not, ``false`` is interpreted as
Expand Down Expand Up @@ -2074,12 +2079,12 @@ are typically provided through the command line, are contained in the node
parameters. There are two ways to specify arguments: lengthy and short.
Dashes are omitted when describing the arguments. This setup node can be
used to set up the memory configuration, accessible NICs, and other EAL-related
parameters, among other things. The node `dpdk.eal-params` also supports
multiple arguments of the same type. This can be useful for EAL arguments
such as `--vdev`, `--allow`, or `--block`. Values for these EAL arguments
are specified as a comma-separated list.
An example of such usage can be found in the example above where the `allow`
argument only makes `0000:3b:00.0` and `0000:3b:00.1` accessible to Suricata.
parameters, among other things. The node `dpdk.eal-params` also supports
multiple arguments of the same type. This can be useful for EAL arguments
such as `--vdev`, `--allow`, or `--block`. Values for these EAL arguments
are specified as a comma-separated list.
An example of such usage can be found in the example above where the `allow`
argument only makes `0000:3b:00.0` and `0000:3b:00.1` accessible to Suricata.
arguments with list node. such as --vdev, --allow, --block eal options.
The definition of lcore affinity as an EAL
parameter is a standard practice. However, lcore parameters like `-l`, `-c`,
Expand Down
12 changes: 8 additions & 4 deletions doc/userguide/performance/ignoring-traffic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,14 @@ Example::
encrypted traffic
-----------------

The TLS app layer parser has the ability to stop processing encrypted traffic
after the initial handshake. By setting the `app-layer.protocols.tls.encryption-handling`
option to `bypass` the rest of this flow is ignored. If flow bypass is enabled,
the bypass is done in the kernel or in hardware.
The TLS and SSH app layer parsers have the ability to stop processing
encrypted traffic after the initial handshake. By setting the
`app-layer.protocols.tls.encryption-handling` and
`app-layer.protocols.tls.encryption-handling` options to `bypass` Suricata
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`app-layer.protocols.tls.encryption-handling` options to `bypass` Suricata
`app-layer.protocols.ssh.encryption-handling` options to `bypass` Suricata

bypasses flows once the handshake is completed and encrypted traffic is
detected. The rest of these flow is ignored.
The bypass is done in the kernel or in hardware, similar to how flow bypass
is done.

.. _bypass:

Expand Down
28 changes: 25 additions & 3 deletions rust/src/ssh/ssh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ use crate::frames::Frame;

static mut ALPROTO_SSH: AppProto = ALPROTO_UNKNOWN;
static HASSH_ENABLED: AtomicBool = AtomicBool::new(false);
static BYPASS_ENABLED: AtomicBool = AtomicBool::new(false);

fn hassh_is_enabled() -> bool {
HASSH_ENABLED.load(Ordering::Relaxed)
}

fn enc_bypass_is_enabled() -> bool {
BYPASS_ENABLED.load(Ordering::Relaxed)
}

#[derive(AppLayerFrameType)]
pub enum SshFrameType {
RecordHdr,
Expand Down Expand Up @@ -197,11 +202,18 @@ impl SSHState {
unsafe {
AppLayerParserStateSetFlag(
pstate,
APP_LAYER_PARSER_NO_INSPECTION
| APP_LAYER_PARSER_NO_REASSEMBLY
| APP_LAYER_PARSER_BYPASS_READY,
APP_LAYER_PARSER_NO_INSPECTION,
);
}
if enc_bypass_is_enabled() {
unsafe {
AppLayerParserStateSetFlag(
pstate,
APP_LAYER_PARSER_NO_REASSEMBLY
| APP_LAYER_PARSER_BYPASS_READY,
);
}
}
}
}
_ => {}
Expand Down Expand Up @@ -549,6 +561,16 @@ pub extern "C" fn rs_ssh_hassh_is_enabled() -> bool {
hassh_is_enabled()
}

#[no_mangle]
pub extern "C" fn rs_ssh_enable_bypass() {
BYPASS_ENABLED.store(true, Ordering::Relaxed)
}

#[no_mangle]
pub extern "C" fn rs_ssh_enc_bypass_is_enabled() -> bool {
enc_bypass_is_enabled()
}

#[no_mangle]
pub unsafe extern "C" fn rs_ssh_tx_get_log_condition( tx: *mut std::os::raw::c_void) -> bool {
let tx = cast_pointer!(tx, SSHTransaction);
Expand Down
19 changes: 19 additions & 0 deletions src/app-layer-ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@

/* HASSH fingerprints are disabled by default */
#define SSH_CONFIG_DEFAULT_HASSH false
/* Bypassing the encrypted part of the connections */
#define SSH_CONFIG_DEFAULT_BYPASS true

static int SSHRegisterPatternsForProtocolDetection(void)
{
Expand Down Expand Up @@ -103,6 +105,23 @@ void RegisterSSHParsers(void)
if (RunmodeIsUnittests() || enable_hassh) {
rs_ssh_enable_hassh();
}

bool enc_bypass = SSH_CONFIG_DEFAULT_BYPASS;
ConfNode *enc_handle = ConfGetNode("app-layer.protocols.ssh.encryption-handling");
if (enc_handle != NULL && enc_handle->val != NULL) {
if (strcmp(enc_handle->val, "full") == 0) {
enc_bypass = false;
} else if (strcmp(enc_handle->val, "bypass") == 0) {
enc_bypass = true;
} else {
enc_bypass = SSH_CONFIG_DEFAULT_BYPASS;
}
}

if (enc_bypass) {
SCLogConfig("ssh: bypass on the start of encryption enabled");
rs_ssh_enable_bypass();
}
}

SCLogDebug("Registering Rust SSH parser.");
Expand Down
8 changes: 2 additions & 6 deletions src/stream-tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5651,17 +5651,13 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
}

if (ssn->flags & STREAMTCP_FLAG_BYPASS) {
/* we can call bypass callback, if enabled */
if (StreamTcpBypassEnabled()) {
PacketBypassCallback(p);
}

/* if stream is dead and we have no detect engine at all, bypass. */
PacketBypassCallback(p);
} else if (g_detect_disabled &&
(ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
(ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
StreamTcpBypassEnabled())
{
/* if stream is dead and we have no detect engine at all, bypass. */
SCLogDebug("bypass as stream is dead and we have no rules");
PacketBypassCallback(p);
}
Expand Down
9 changes: 8 additions & 1 deletion suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,14 @@ app-layer:
#enabled: yes
ssh:
enabled: yes
#hassh: yes
# hassh: no

# What to do when the encrypted communications start:
# - bypass: stop processing this flow as much as possible.
# Offload flow bypass to kernel or hardware if possible.
# - full: keep tracking and inspection as normal
#
# encryption-handling: bypass
Comment on lines +936 to +941
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we indicate here what is the default?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the behavior here the same as we have for tls, or is there a difference?

doh2:
enabled: yes
http2:
Expand Down
Loading