From 1bf439cd58a05d724529cbab81bb862861711e54 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 11 Jul 2024 13:20:24 -0700 Subject: [PATCH 01/41] Updating CHANGES and VERSION. --- CHANGES | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 55d064321b..49beb0badc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +7.0.0-rc1 | 2024-07-11 12:21:02 -0700 + + * Updating submodule(s) [nomail] (Tim Wojtulewicz, Corelight) + 7.0.0-dev.467 | 2024-07-11 12:14:52 -0700 * Update the scripts.base.frameworks.telemetry.internal-metrics test (Christian Kreibich, Corelight) diff --git a/VERSION b/VERSION index 14530a2cf8..8a72a34280 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-dev.467 +7.0.0-rc1 From 92a685df500c51bb4e3bd16e130833583387cdbd Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 11 Jul 2024 14:20:47 -0700 Subject: [PATCH 02/41] Fix a typo in the 7.0 NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e526919b09..e115d2be07 100644 --- a/NEWS +++ b/NEWS @@ -20,7 +20,7 @@ Breaking Changes All of the metrics-related script-level options, type, and methods have been moved to the Telemetry framework: - * Option ``Broker::metrics_port` is now ``Telemetry::metrics_port`` + * Option ``Broker::metrics_port`` is now ``Telemetry::metrics_port`` * Option ``Broker::metrics_export_endpoint_name`` is now ``Telemetry::metrics_endpoint_name`` The following options have been removed: From 962b03a431ff6e66fab8aef3668a131a8006b8b3 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 09:46:34 -0700 Subject: [PATCH 03/41] Merge remote-tracking branch 'origin/topic/timw/grealpath-make-dist-warning' * origin/topic/timw/grealpath-make-dist-warning: Fix warning about grealpath when running 'make dist' on Linux (cherry picked from commit e4716b6c912f86cf6b2afd6979c38667c45add95) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5c0f8a4b97..394a77ab8e 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ BUILD=build REPO=$$(cd $(CURDIR) && basename $$(git config --get remote.origin.url | sed 's/^[^:]*://g')) VERSION_FULL=$(REPO)-$$(cd $(CURDIR) && cat VERSION) GITDIR=$$(test -f .git && echo $$(cut -d" " -f2 .git) || echo .git) -REALPATH=$$($$(realpath --relative-to=$(pwd) . >/dev/null 2>&1) && echo 'realpath' || echo 'grealpath') +REALPATH=$$($$(realpath --relative-to=$(shell pwd) . >/dev/null 2>&1) && echo 'realpath' || echo 'grealpath') all: configured $(MAKE) -C $(BUILD) $@ From ac9548438280820801845cb26705a6b7cb636890 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 09:47:59 -0700 Subject: [PATCH 04/41] Merge remote-tracking branch 'origin/topic/bbannier/lib-spicy-hooks' * origin/topic/bbannier/lib-spicy-hooks: Do not emit hook files for builtin modules (cherry picked from commit 7a38cee81fd6b4d29f744bb095359d986ebedb95) --- src/spicy/spicyz/driver.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/spicy/spicyz/driver.cc b/src/spicy/spicyz/driver.cc index 8a4eee216a..8e4854c298 100644 --- a/src/spicy/spicyz/driver.cc +++ b/src/spicy/spicyz/driver.cc @@ -4,10 +4,8 @@ #include -#include #include #include -#include #include #include @@ -37,12 +35,15 @@ struct VisitorTypes : public spicy::visitor::PreOrder { : driver(driver), glue(glue), is_resolved(is_resolved) {} void operator()(hilti::declaration::Module* n) final { - if ( n->uid().in_memory ) { - // Ignore modules built by us in memory. + // Ignore modules built by us in memory, or builtin modules which + // never contain implementations of hooks for user types. + if ( n->uid().in_memory || + (module == "hilti" || module == "spicy" || module == "spicy_rt" || module == "zeek_rt") ) { module = {}; return; } + module = n->scopeID(); path = n->uid().path; From 5f6df68463e40d5eb9257d78de0c6779f86c4984 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 09:51:39 -0700 Subject: [PATCH 05/41] Merge remote-tracking branch 'origin/topic/bbannier/lib-spicy-hooks' * origin/topic/bbannier/lib-spicy-hooks: Do not emit hook files for builtin modules (cherry picked from commit b935d2f59aea00fdf79216a1b4dfa287136b1b6d) --- src/spicy/spicyz/driver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicy/spicyz/driver.cc b/src/spicy/spicyz/driver.cc index 8e4854c298..82759fbf5e 100644 --- a/src/spicy/spicyz/driver.cc +++ b/src/spicy/spicyz/driver.cc @@ -47,7 +47,7 @@ struct VisitorTypes : public spicy::visitor::PreOrder { module = n->scopeID(); path = n->uid().path; - if ( is_resolved ) + if ( is_resolved && ! n->skipImplementation() ) glue->addSpicyModule(module, path); } From a8c56c1f25d786fc5bfb35ff27f8e0e96b71f9ed Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 10:00:13 -0700 Subject: [PATCH 06/41] Fix a broken merge I merged an old version of the branch on accident and then merged the right one over top of it, but git ended up including both versions. This fixes that mistake. (cherry picked from commit f3bcf1a55d13986ef7d6146ca26095de32c0176b) --- src/spicy/spicyz/driver.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/spicy/spicyz/driver.cc b/src/spicy/spicyz/driver.cc index 82759fbf5e..75ffd1f6fa 100644 --- a/src/spicy/spicyz/driver.cc +++ b/src/spicy/spicyz/driver.cc @@ -35,15 +35,11 @@ struct VisitorTypes : public spicy::visitor::PreOrder { : driver(driver), glue(glue), is_resolved(is_resolved) {} void operator()(hilti::declaration::Module* n) final { - // Ignore modules built by us in memory, or builtin modules which - // never contain implementations of hooks for user types. - if ( n->uid().in_memory || - (module == "hilti" || module == "spicy" || module == "spicy_rt" || module == "zeek_rt") ) { + if ( n->uid().in_memory ) { + // Ignore modules built by us in memory. module = {}; return; } - - module = n->scopeID(); path = n->uid().path; From 91b23a6e2ec53194ed96b85856c5233d61ede61f Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 16:13:04 -0700 Subject: [PATCH 07/41] Update broker and cmake submodules [nomail] --- auxil/broker | 2 +- cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auxil/broker b/auxil/broker index fada26ae50..4679ab3a8c 160000 --- a/auxil/broker +++ b/auxil/broker @@ -1 +1 @@ -Subproject commit fada26ae504981f7f5524bf2a5c82ae49acd556d +Subproject commit 4679ab3a8cc6beadaa65436b47fd79dfbd571a3f diff --git a/cmake b/cmake index 690483f76c..2d42baf8e6 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 690483f76c149ffa8e035b612b406b0964f9886f +Subproject commit 2d42baf8e63a7494224aa9d02afa2cb43ddb96b8 From b8d11f4688c2869daf8e01086fca52315735b89b Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 13:56:11 -0700 Subject: [PATCH 08/41] CI: Set FETCH_CONTENT_FULLY_DISCONNECTED flag for configure --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1323ce8e95..b96146f230 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,7 +10,7 @@ btest_jobs: &BTEST_JOBS 4 btest_retries: &BTEST_RETRIES 2 memory: &MEMORY 16GB -config: &CONFIG --build-type=release --disable-broker-tests --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror +config: &CONFIG --build-type=release --disable-broker-tests --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror -D FETCHCONTENT_FULLY_DISCONNECTED:BOOL=ON no_spicy_config: &NO_SPICY_CONFIG --build-type=release --disable-broker-tests --disable-spicy --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror static_config: &STATIC_CONFIG --build-type=release --disable-broker-tests --enable-static-broker --enable-static-binpac --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror binary_config: &BINARY_CONFIG --prefix=$CIRRUS_WORKING_DIR/install --libdir=$CIRRUS_WORKING_DIR/install/lib --binary-package --enable-static-broker --enable-static-binpac --disable-broker-tests --build-type=Release --ccache --enable-werror From 5cdddd92d55e301fdae474ad6dc85418c170d287 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 16 Jul 2024 10:16:02 -0700 Subject: [PATCH 09/41] Merge remote-tracking branch 'origin/topic/bbannier/bump-spicy' * origin/topic/bbannier/bump-spicy: Bump auxil/spicy to latest development snapshot (cherry picked from commit 9ba7c2ddafd73dd2d00ab301d9aa8f501d819f4f) --- auxil/spicy | 2 +- src/analyzer/protocol/finger/finger.spicy | 2 +- src/analyzer/protocol/syslog/syslog.spicy | 2 +- src/spicy/spicyz/glue-compiler.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/auxil/spicy b/auxil/spicy index 6581b1855a..4a1b43ef07 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit 6581b1855a5ea8cc102c66b4ac6a431fc67484a0 +Subproject commit 4a1b43ef07d1305a7e88a4f0866068dc49de9d06 diff --git a/src/analyzer/protocol/finger/finger.spicy b/src/analyzer/protocol/finger/finger.spicy index dd07dbb7c3..0d6a8da54e 100644 --- a/src/analyzer/protocol/finger/finger.spicy +++ b/src/analyzer/protocol/finger/finger.spicy @@ -15,7 +15,7 @@ public type Request = unit { switch { -> : /\/W/ { self.whois = True; } - -> void; + -> : void; }; : OptionalWhiteSpace; diff --git a/src/analyzer/protocol/syslog/syslog.spicy b/src/analyzer/protocol/syslog/syslog.spicy index fd4c845870..ba8c8a77aa 100644 --- a/src/analyzer/protocol/syslog/syslog.spicy +++ b/src/analyzer/protocol/syslog/syslog.spicy @@ -7,7 +7,7 @@ import spicy; public type Message = unit { switch { -> prio: Priority; - -> void; + -> : void; }; msg: bytes &eod; diff --git a/src/spicy/spicyz/glue-compiler.cc b/src/spicy/spicyz/glue-compiler.cc index cc17312343..e9240ed245 100644 --- a/src/spicy/spicyz/glue-compiler.cc +++ b/src/spicy/spicyz/glue-compiler.cc @@ -1375,7 +1375,7 @@ bool GlueCompiler::CreateSpicyHook(glue::Event* ev) { auto attrs = builder()->attributeSet({builder()->attribute("&priority", builder()->integer(ev->priority))}); auto parameters = hilti::util::transform(ev->parameters, [](const auto& p) { return p.get(); }); - auto unit_hook = builder()->declarationHook(parameters, body.block(), ::spicy::Engine::All, attrs, meta); + auto unit_hook = builder()->declarationHook(parameters, body.block(), attrs, meta); auto hook_decl = builder()->declarationUnitHook(ev->hook, unit_hook, meta); ev->spicy_module->spicy_module->add(context(), hook_decl); From d17a1f9822b9ea651e27e7ae5047a2693e86fc94 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Mon, 15 Jul 2024 17:50:09 -0700 Subject: [PATCH 10/41] Bump zeek-testing-cluster to pull in tee SIGPIPE fix (cherry picked from commit b51a46f94d4012119fd27d5e46328c70af7270a2) --- testing/external/commit-hash.zeek-testing-cluster | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/external/commit-hash.zeek-testing-cluster b/testing/external/commit-hash.zeek-testing-cluster index 8b8bfdc2e4..5d84d38106 100644 --- a/testing/external/commit-hash.zeek-testing-cluster +++ b/testing/external/commit-hash.zeek-testing-cluster @@ -1 +1 @@ -45582671c6715e719d91c8afde7ffb480c602441 +ded009fb7a0cdee6f36d5b40a6394788b760fa06 From b13dfa3b16f78897847f1d47729a1989632f2960 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 18 Jul 2024 14:31:49 -0700 Subject: [PATCH 11/41] Update docs submodule [nomail] --- doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc b/doc index f65820ff0f..316ad305b6 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit f65820ff0faf2887799fe691a443b5db39eeed54 +Subproject commit 316ad305b69456fcd424ffaf99d1326822ad9d60 From 5a56ff92d2c9e6d7028f851520b7ece064a22e4f Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 18 Jul 2024 14:54:47 -0700 Subject: [PATCH 12/41] Updating CHANGES and VERSION. --- CHANGES | 14 ++++++++++++++ VERSION | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 49beb0badc..396fae1710 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,17 @@ +7.0.0-rc2 | 2024-07-18 14:31:49 -0700 + + * Bump zeek-testing-cluster to pull in tee SIGPIPE fix (Christian Kreibich, Corelight) + + (cherry picked from commit b51a46f94d4012119fd27d5e46328c70af7270a2) + + * CI: Set FETCH_CONTENT_FULLY_DISCONNECTED flag for configure (Tim Wojtulewicz, Corelight) + + * Update broker and cmake submodules [nomail] (Tim Wojtulewicz, Corelight) + + * Fix warning about grealpath when running 'make dist' on Linux (Tim Wojtulewicz, Corelight) + + (cherry picked from commit e4716b6c912f86cf6b2afd6979c38667c45add95) + 7.0.0-rc1 | 2024-07-11 12:21:02 -0700 * Updating submodule(s) [nomail] (Tim Wojtulewicz, Corelight) diff --git a/VERSION b/VERSION index 8a72a34280..8e0c129daf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-rc1 +7.0.0-rc2 From d9dc121e9ad41bc3e7324edb157b7bc206144dca Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Mon, 22 Jul 2024 15:00:22 -0700 Subject: [PATCH 13/41] Update broker submodule [nomail] --- auxil/broker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxil/broker b/auxil/broker index 4679ab3a8c..5b3ed87a93 160000 --- a/auxil/broker +++ b/auxil/broker @@ -1 +1 @@ -Subproject commit 4679ab3a8cc6beadaa65436b47fd79dfbd571a3f +Subproject commit 5b3ed87a93b2ded1f3c95ff1a3b99e2c6ab84ef4 From 8014c4b8c37cce4f7e3c5df9dd1d3b097485b7fe Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Sun, 21 Jul 2024 17:34:34 +0200 Subject: [PATCH 14/41] telemetry: Deprecate prometheus.zeek policy script With Cluster::Node$metrics_port being optional, there's not really a need for the extra script. New rule, if a metrics_port is set, the node will attempt to listen on it. Users can still redef Telemetry::metrics_port *after* base/frameworks/telemetry was loaded to change the port defined in cluster-layout.zeek. (cherry picked from commit bf9704f3398229c860aca92dd45df1b2fd26f68e) --- NEWS | 5 +++++ .../base/frameworks/telemetry/__load__.zeek | 2 -- scripts/base/frameworks/telemetry/main.zeek | 18 ++++++++++++++++ .../frameworks/telemetry/prometheus.zeek | 21 ++----------------- scripts/site/local.zeek | 4 ---- testing/btest/coverage/bare-mode-errors.test | 2 +- .../coverage/test-all-policy-cluster.test | 2 +- .../frameworks/telemetry/prometheus.zeek | 1 - 8 files changed, 27 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index e115d2be07..2f7422c195 100644 --- a/NEWS +++ b/NEWS @@ -167,6 +167,11 @@ Deprecated Functionality - The ``--disable-archiver`` configure flag no longer does anything and will be removed in 7.1. zeek-archiver has moved into the zeek-aux repository. +- The policy/frameworks/telemetry/prometheus.zeek script has been deprecated + and will be removed with Zeek 7.1. Setting the ``metrics_port`` field on a + ``Cluster::Node`` implies listening on that port and exposing telemetry + in Prometheus format. + Zeek 6.2.0 ========== diff --git a/scripts/base/frameworks/telemetry/__load__.zeek b/scripts/base/frameworks/telemetry/__load__.zeek index 88b6dbf672..a10fe855df 100644 --- a/scripts/base/frameworks/telemetry/__load__.zeek +++ b/scripts/base/frameworks/telemetry/__load__.zeek @@ -1,3 +1 @@ @load ./main - -@load base/frameworks/cluster diff --git a/scripts/base/frameworks/telemetry/main.zeek b/scripts/base/frameworks/telemetry/main.zeek index d71a7d9783..0e5ce1b1f5 100644 --- a/scripts/base/frameworks/telemetry/main.zeek +++ b/scripts/base/frameworks/telemetry/main.zeek @@ -5,10 +5,28 @@ ##! enabled by setting :zeek:see:`Telemetry::metrics_port`. @load base/misc/version +@load base/frameworks/cluster + @load base/frameworks/telemetry/options module Telemetry; +# In a cluster configuration, open the port number for metrics +# from the cluster node configuration for exporting data to +# Prometheus. +# +# The manager node will also provide a ``/services.json`` endpoint +# for the HTTP Service Discovery system in Prometheus to use for +# configuration. This endpoint will include information for all of +# the other nodes in the cluster. +@if ( Cluster::is_enabled() ) +redef Telemetry::metrics_endpoint_name = Cluster::node; + +@if ( Cluster::local_node_metrics_port() != 0/unknown ) +redef Telemetry::metrics_port = Cluster::local_node_metrics_port(); +@endif +@endif + export { ## Alias for a vector of label values. type labels_vector: vector of string; diff --git a/scripts/policy/frameworks/telemetry/prometheus.zeek b/scripts/policy/frameworks/telemetry/prometheus.zeek index 2b2ac4d255..a7d0226d73 100644 --- a/scripts/policy/frameworks/telemetry/prometheus.zeek +++ b/scripts/policy/frameworks/telemetry/prometheus.zeek @@ -1,19 +1,2 @@ -##! In a cluster configuration, open the port number for metrics -##! from the cluster node configuration for exporting data to -##! Prometheus. -##! -##! The manager node will also provide a ``/services.json`` endpoint -##! for the HTTP Service Discovery system in Prometheus to use for -##! configuration. This endpoint will include information for all of -##! the other nodes in the cluster. -@load base/frameworks/cluster - -@if ( Cluster::is_enabled() ) - -redef Telemetry::metrics_endpoint_name = Cluster::node; - -@if ( Cluster::local_node_metrics_port() != 0/unknown ) -redef Telemetry::metrics_port = Cluster::local_node_metrics_port(); -@endif - -@endif +@deprecated "Remove in v7.1: Cluster nodes now implicitly listen on metrics port if set in cluster-layout." +@load base/frameworks/telemetry diff --git a/scripts/site/local.zeek b/scripts/site/local.zeek index 71251c0cb1..d92ccdd5a6 100644 --- a/scripts/site/local.zeek +++ b/scripts/site/local.zeek @@ -94,10 +94,6 @@ redef digest_salt = "Please change this value."; # telemetry_histogram.log. @load frameworks/telemetry/log -# Enable Prometheus metrics scraping in the cluster: each Zeek node will listen -# on the metrics port defined in its Cluster::nodes entry. -# @load frameworks/telemetry/prometheus - # Uncomment the following line to enable detection of the heartbleed attack. Enabling # this might impact performance a bit. # @load policy/protocols/ssl/heartbleed diff --git a/testing/btest/coverage/bare-mode-errors.test b/testing/btest/coverage/bare-mode-errors.test index e477140083..be243bcdc0 100644 --- a/testing/btest/coverage/bare-mode-errors.test +++ b/testing/btest/coverage/bare-mode-errors.test @@ -9,4 +9,4 @@ # # @TEST-EXEC: test -d $DIST/scripts # @TEST-EXEC: for script in `find $DIST/scripts/ -name \*\.zeek`; do zeek -b --parse-only $script >>errors 2>&1; done -# @TEST-EXEC: TEST_DIFF_CANONIFIER="grep -v -e 'load-balancing.zeek.*deprecated script loaded' | $SCRIPTS/diff-remove-abspath | $SCRIPTS/diff-sort" btest-diff errors +# @TEST-EXEC: TEST_DIFF_CANONIFIER="grep -v -e 'load-balancing.zeek.*deprecated script loaded' | grep -v -e 'prometheus.zeek.*deprecated script loaded' | $SCRIPTS/diff-remove-abspath | $SCRIPTS/diff-sort" btest-diff errors diff --git a/testing/btest/coverage/test-all-policy-cluster.test b/testing/btest/coverage/test-all-policy-cluster.test index b213b1ac26..9d88868063 100644 --- a/testing/btest/coverage/test-all-policy-cluster.test +++ b/testing/btest/coverage/test-all-policy-cluster.test @@ -9,7 +9,7 @@ # @TEST-EXEC: CLUSTER_NODE=logger-1 zeek %INPUT # @TEST-EXEC: CLUSTER_NODE=proxy-1 zeek %INPUT # @TEST-EXEC: CLUSTER_NODE=worker-1 zeek %INPUT -# @TEST-EXEC: TEST_DIFF_CANONIFIER='grep -v "load-balancing.zeek.*deprecated script" | $SCRIPTS/diff-remove-abspath' btest-diff .stderr +# @TEST-EXEC: TEST_DIFF_CANONIFIER='grep -v "load-balancing.zeek.*deprecated script" | grep -v "prometheus.zeek.*deprecated script" | $SCRIPTS/diff-remove-abspath' btest-diff .stderr @load base/frameworks/cluster @load misc/loaded-scripts diff --git a/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek b/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek index 0d6e7794b0..50a6fd8d2c 100644 --- a/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek +++ b/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek @@ -55,7 +55,6 @@ done @TEST-END-FILE @load policy/frameworks/cluster/experimental -@load policy/frameworks/telemetry/prometheus @load base/frameworks/telemetry # So the cluster nodes don't terminate right away. From a65a339aa8c556410f87b88144bd770720f8ca74 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 23 Jul 2024 08:51:11 -0700 Subject: [PATCH 15/41] Merge remote-tracking branch 'origin/topic/bbannier/bump-spicy' * origin/topic/bbannier/bump-spicy: Bump auxil/spicy to latest development snapshot (cherry picked from commit da7c3d91385195a7a4ba957e46743bc52a9d4ecb) --- auxil/spicy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxil/spicy b/auxil/spicy index 4a1b43ef07..04c5ed3c27 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit 4a1b43ef07d1305a7e88a4f0866068dc49de9d06 +Subproject commit 04c5ed3c27879459de69d12efc417c6915f304b9 From 746ae4d2cc53864a156fb185d78b9e757cdacd22 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 23 Jul 2024 08:54:23 -0700 Subject: [PATCH 16/41] Merge remote-tracking branch 'origin/topic/johanna/update-the-ct-list-and-the-ca-list-again' * origin/topic/johanna/update-the-ct-list-and-the-ca-list-again: Update Mozilla CA list and CT list (cherry picked from commit cb88f6316c7341da7a2af397932a145be3a0cc29) --- scripts/base/protocols/ssl/ct-list.zeek | 21 +++++++++++++++---- .../base/protocols/ssl/mozilla-ca-list.zeek | 5 +++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/scripts/base/protocols/ssl/ct-list.zeek b/scripts/base/protocols/ssl/ct-list.zeek index c7c2a87ec9..036374d946 100644 --- a/scripts/base/protocols/ssl/ct-list.zeek +++ b/scripts/base/protocols/ssl/ct-list.zeek @@ -1,9 +1,9 @@ # # Do not edit this file. This file is automatically generated by gen-ct-list.pl -# File generated at Fri Feb 23 11:37:01 2024 +# File generated at Tue Jul 23 16:04:45 2024 # File generated from https://www.gstatic.com/ct/log_list/v3/log_list.json -# Source file generated at: 2024-02-22T12:56:21Z -# Source file version: 32.9 +# Source file generated at: 2024-07-23T13:06:08Z +# Source file version: 39.1 # @load base/protocols/ssl @@ -12,21 +12,32 @@ redef ct_logs += { ["\xee\xcd\xd0\x64\xd5\xdb\x1a\xce\xc5\x5c\xb7\x9d\xb4\xcd\x13\xa2\x32\x87\x46\x7c\xbc\xec\xde\xc3\x51\x48\x59\x46\x71\x1f\xb5\x9b"] = CTInfo($description="Google 'Argon2024' log", $operator="Google", $url="https://ct.googleapis.com/logs/us1/argon2024/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x1d\xb9\x6c\xa9\xcb\x69\x94\xc5\x5c\xe6\xb6\xa6\x03\xbb\xd2\xb8\xdc\x54\x43\x17\x28\x99\x0c\x06\x01\x50\x1d\x9d\x64\xc0\x59\x46\x2b\xdc\xc8\x03\x1d\x05\xb4\x2d\xa8\x09\xf7\x99\x41\xed\x04\xfb\xe5\x57\xba\x26\x04\xf6\x11\x52\xce\x14\x65\x3b\x2f\x76\x2b\xc0"), ["\x4e\x75\xa3\x27\x5c\x9a\x10\xc3\x38\x5b\x6c\xd4\xdf\x3f\x52\xeb\x1d\xf0\xe0\x8e\x1b\x8d\x69\xc0\xb1\xfa\x64\xb1\x62\x9a\x39\xdf"] = CTInfo($description="Google 'Argon2025h1' log", $operator="Google", $url="https://ct.googleapis.com/logs/us1/argon2025h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x20\x82\xa1\xf9\x67\x68\xa8\xe4\xdb\x94\x98\xe2\xe1\x68\x87\xe4\x09\x6d\x20\x35\x33\x38\x3c\xaf\x14\xaa\xd7\x08\x18\xf0\xfd\x16\x9b\xd3\xff\x7c\x27\x82\xd4\x87\xb7\x4e\x24\x46\x3b\xfb\xae\xbe\xc8\x23\x52\x20\x2b\xaa\x44\x05\xfe\x54\xf9\xd5\xf1\x1d\x45\x9a"), ["\x12\xf1\x4e\x34\xbd\x53\x72\x4c\x84\x06\x19\xc3\x8f\x3f\x7a\x13\xf8\xe7\xb5\x62\x87\x88\x9c\x6d\x30\x05\x84\xeb\xe5\x86\x26\x3a"] = CTInfo($description="Google 'Argon2025h2' log", $operator="Google", $url="https://ct.googleapis.com/logs/us1/argon2025h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xaf\xe4\xf3\x94\x2c\xdf\xa6\x27\xb5\xfe\xb2\x61\x83\x19\xc8\x21\x3a\x23\xa8\xa9\x3d\x54\xaf\xbc\x31\x9a\x1c\xd3\xc1\xe3\xb6\xc2\xf3\x0f\xc7\xb9\xca\x3b\x1d\x79\x65\x61\x22\x25\x82\x56\x4e\x98\xe8\xaa\x26\x29\x36\x1e\x28\x60\x6f\xeb\x15\x6e\xf7\x7c\xd0\xba"), +["\x0e\x57\x94\xbc\xf3\xae\xa9\x3e\x33\x1b\x2c\x99\x07\xb3\xf7\x90\xdf\x9b\xc2\x3d\x71\x32\x25\xdd\x21\xa9\x25\xac\x61\xc5\x4e\x21"] = CTInfo($description="Google 'Argon2026h1' log", $operator="Google", $url="https://ct.googleapis.com/logs/us1/argon2026h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xfc\x1e\xe8\x63\x8e\xff\x1c\x31\x8a\xfc\xb8\x1e\x19\x2b\x60\x50\x00\x3e\x8e\x9e\xda\x77\x37\xe3\xa5\xa8\xda\x8d\x94\xf8\x6b\xe8\x3d\x64\x8f\x27\x3f\x75\xb3\xfc\x6b\x12\xf0\x37\x06\x4f\x64\x58\x75\x14\x5d\x56\x52\xe6\x6a\x2b\x14\x4c\xec\x81\xd1\xea\x3e"), +["\xd7\x6d\x7d\x10\xd1\xa7\xf5\x77\xc2\xc7\xe9\x5f\xd7\x00\xbf\xf9\x82\xc9\x33\x5a\x65\xe1\xd0\xb3\x01\x73\x17\xc0\xc8\xc5\x69\x77"] = CTInfo($description="Google 'Argon2026h2' log", $operator="Google", $url="https://ct.googleapis.com/logs/us1/argon2026h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x2a\x3a\x67\x8b\xfe\xba\x0c\x86\x2b\x4a\x51\x8a\xe9\x17\xfe\x7b\xa1\x76\x73\xfd\xbc\x65\x4b\xc3\x27\xbf\x4d\xf3\x5f\xa0\xca\x29\x80\x11\x20\x32\x78\xd6\x7e\xf9\x34\x60\x8c\x75\xa0\xf5\x35\x50\x9c\xa1\xd3\x49\x4d\x13\xd5\x3b\x6a\x0e\xea\x45\x9d\x24\x13\x22"), ["\x76\xff\x88\x3f\x0a\xb6\xfb\x95\x51\xc2\x61\xcc\xf5\x87\xba\x34\xb4\xa4\xcd\xbb\x29\xdc\x68\x42\x0a\x9f\xe6\x67\x4c\x5a\x3a\x74"] = CTInfo($description="Google 'Xenon2024' log", $operator="Google", $url="https://ct.googleapis.com/logs/eu1/xenon2024/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xb9\x60\xe0\x34\x1e\x35\xe4\x65\x00\x93\x4f\x90\x09\xbd\x5a\xec\x44\xdd\x8c\x0f\xce\xed\x11\x3e\x2a\x59\x46\x9a\x31\xb6\xc7\x99\xf7\xdc\xef\x3d\xcd\x8f\x86\xc2\x35\xa5\x3e\xdc\x29\xba\xbb\xf2\x54\xe2\xa8\x0c\x83\x08\x51\x06\xde\x21\x6d\x36\x50\x8e\x38\x4d"), ["\xcf\x11\x56\xee\xd5\x2e\x7c\xaf\xf3\x87\x5b\xd9\x69\x2e\x9b\xe9\x1a\x71\x67\x4a\xb0\x17\xec\xac\x01\xd2\x5b\x77\xce\xcc\x3b\x08"] = CTInfo($description="Google 'Xenon2025h1' log", $operator="Google", $url="https://ct.googleapis.com/logs/eu1/xenon2025h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x82\xe2\xce\x90\x40\x3f\x81\x0e\xdf\xea\xe1\x20\x2b\x5e\x2e\x30\x54\x46\x81\xb9\x58\xed\xaf\xbd\xff\x36\xa7\x9e\x0b\x5f\x6a\x6b\x91\xa5\xc1\x98\xe1\xf2\xcd\xeb\x17\x20\x70\xca\x2a\x12\xe6\x54\x78\x50\xdc\xff\x6d\xfd\x1c\xa7\xb6\x3a\x1f\xf9\x26\xa9\x1b\xbd"), ["\xdd\xdc\xca\x34\x95\xd7\xe1\x16\x05\xe7\x95\x32\xfa\xc7\x9f\xf8\x3d\x1c\x50\xdf\xdb\x00\x3a\x14\x12\x76\x0a\x2c\xac\xbb\xc8\x2a"] = CTInfo($description="Google 'Xenon2025h2' log", $operator="Google", $url="https://ct.googleapis.com/logs/eu1/xenon2025h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x6b\xe0\xaf\xed\x06\x7c\x3d\xef\xd9\x0e\xe4\x58\x4b\x04\xd8\x2a\x47\x99\x90\x89\x7a\xb9\x36\xa5\x75\xc8\x04\xb8\xcb\xe2\xaa\x2b\xb5\x68\x9d\x88\x29\xa2\xa5\xcf\xce\x2b\x9a\x15\x9b\xa0\x3e\x9d\x94\x1c\xb2\xb7\x4a\xf2\x51\xec\x40\xed\x62\x47\xa4\x03\x49\x86"), +["\x96\x97\x64\xbf\x55\x58\x97\xad\xf7\x43\x87\x68\x37\x08\x42\x77\xe9\xf0\x3a\xd5\xf6\xa4\xf3\x36\x6e\x46\xa4\x3f\x0f\xca\xa9\xc6"] = CTInfo($description="Google 'Xenon2026h1' log", $operator="Google", $url="https://ct.googleapis.com/logs/eu1/xenon2026h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x3a\x1f\xc8\xbb\xce\xd5\x90\x47\x34\xca\xca\x01\x04\x27\x21\x1c\xe2\x29\x3d\x92\xbb\x91\x45\xc7\x5a\x3e\xa5\xd4\xf2\x12\xe6\xe8\xe6\x43\xba\xf3\x7b\xc2\x38\xaf\xfc\x23\x8a\x05\x56\xeb\x03\x0a\x30\xcc\x63\x6c\xd9\x3c\xbe\xf5\x7b\x94\xba\x94\xd3\xbf\x88\x4c"), +["\xd8\x09\x55\x3b\x94\x4f\x7a\xff\xc8\x16\x19\x6f\x94\x4f\x85\xab\xb0\xf8\xfc\x5e\x87\x55\x26\x0f\x15\xd1\x2e\x72\xbb\x45\x4b\x14"] = CTInfo($description="Google 'Xenon2026h2' log", $operator="Google", $url="https://ct.googleapis.com/logs/eu1/xenon2026h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xe5\x77\x78\x95\x71\x28\xb3\x95\xc9\xa5\xcc\x7a\x4c\xe8\x32\x03\x96\x7b\xfc\x2e\x1d\xb9\xa4\xdb\x43\xa0\xbd\x69\x72\xf9\x45\xba\x9a\xc3\xe9\x96\xd5\x70\xe7\x0d\x7e\xc9\x95\x15\x27\x8a\x72\x30\x65\x86\x43\x53\xdc\x11\x44\x18\x49\x98\x25\x68\xa7\x3c\x05\xbf"), ["\xda\xb6\xbf\x6b\x3f\xb5\xb6\x22\x9f\x9b\xc2\xbb\x5c\x6b\xe8\x70\x91\x71\x6c\xbb\x51\x84\x85\x34\xbd\xa4\x3d\x30\x48\xd7\xfb\xab"] = CTInfo($description="Cloudflare 'Nimbus2024' Log", $operator="Cloudflare", $url="https://ct.cloudflare.com/logs/nimbus2024/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x77\xb1\x9b\x7b\x8f\xe6\x8b\x35\xfe\x3a\x92\x29\x2d\xac\x8a\x8d\x51\x8a\x25\xfc\x93\xb6\xd7\xa0\x8b\x29\x37\x71\x1d\x33\xca\xcc\x33\xea\x28\xb9\x1f\xe2\xac\xc3\xa9\x5d\xdd\x97\xbe\xf6\x9e\x94\x25\xdd\x36\x81\xd1\xeb\x5d\x29\xc3\x2b\x44\xf1\x5b\xca\x15\x48"), ["\xcc\xfb\x0f\x6a\x85\x71\x09\x65\xfe\x95\x9b\x53\xce\xe9\xb2\x7c\x22\xe9\x85\x5c\x0d\x97\x8d\xb6\xa9\x7e\x54\xc0\xfe\x4c\x0d\xb0"] = CTInfo($description="Cloudflare 'Nimbus2025'", $operator="Cloudflare", $url="https://ct.cloudflare.com/logs/nimbus2025/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x1a\x80\x1a\x15\x19\x19\x23\x79\xb4\xfa\xa0\x79\x8e\x8d\xd5\xc1\xdc\xc2\xb5\x96\x92\x7e\x94\xe0\xc3\x7e\x14\x7c\x0a\x0d\x2d\x46\xa8\x9d\x1b\xb1\x41\x65\x0c\x5f\x98\xc4\x5a\x17\x79\x81\x5b\x4a\x14\x41\xec\xaf\xa9\x5d\x0e\xab\x12\x19\x71\xcd\x43\xef\xbb\x97"), ["\x48\xb0\xe3\x6b\xda\xa6\x47\x34\x0f\xe5\x6a\x02\xfa\x9d\x30\xeb\x1c\x52\x01\xcb\x56\xdd\x2c\x81\xd9\xbb\xbf\xab\x39\xd8\x84\x73"] = CTInfo($description="DigiCert Yeti2024 Log", $operator="DigiCert", $url="https://yeti2024.ct.digicert.com/log/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x57\xb8\xc1\x6f\x30\xa4\x7f\x2e\xe4\xf0\xd0\xd9\x60\x62\x13\x95\xe3\x7a\xe3\x4e\x53\xc3\xb3\xb8\x73\x85\xc1\x18\x0d\x23\x0e\x58\x84\xd2\x78\xef\x9b\xb3\x1e\x2c\x1a\xde\xc1\x8f\x81\x1b\x19\x44\x58\xb7\x00\x77\x60\x20\x1a\x72\xd8\x82\xde\xae\x9e\xb1\xc6\x4b"), ["\x7d\x59\x1e\x12\xe1\x78\x2a\x7b\x1c\x61\x67\x7c\x5e\xfd\xf8\xd0\x87\x5c\x14\xa0\x4e\x95\x9e\xb9\x03\x2f\xd9\x0e\x8c\x2e\x79\xb8"] = CTInfo($description="DigiCert Yeti2025 Log", $operator="DigiCert", $url="https://yeti2025.ct.digicert.com/log/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xdf\x95\x00\x5e\x10\xc1\x01\xf7\x37\xe3\x10\x74\xd1\xff\xb2\xca\x90\xed\x32\x99\x5f\x0c\x39\xfe\xa1\xd1\x13\x11\xac\xd1\xb3\x73\x93\x20\xc2\x13\x3c\x4c\xb5\x7a\x52\x86\x86\x3d\xe3\x95\x24\x7c\xd8\x91\x98\x48\x3b\xf0\xf0\xdf\x21\xf1\xb0\x81\x5a\x59\x25\x43"), ["\x73\xd9\x9e\x89\x1b\x4c\x96\x78\xa0\x20\x7d\x47\x9d\xe6\xb2\xc6\x1c\xd0\x51\x5e\x71\x19\x2a\x8c\x6b\x80\x10\x7a\xc1\x77\x72\xb5"] = CTInfo($description="DigiCert Nessie2024 Log", $operator="DigiCert", $url="https://nessie2024.ct.digicert.com/log/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x2d\xfc\xa2\x7b\x36\xbf\x56\x91\xe9\xfe\x3f\xe8\x3d\xfc\xc3\xa7\xe0\x61\x52\xea\x2c\xe9\x05\xa3\x9f\x27\x17\x81\x05\x70\x6b\x81\x61\x44\x8a\xf8\x3b\x10\x80\x42\xed\x03\x2f\x00\x50\x21\xfc\x41\x54\x84\xa3\x54\xd5\x2e\xb2\x7a\x16\x4b\x2a\x1f\x2b\x66\x04\x2b"), ["\xe6\xd2\x31\x63\x40\x77\x8c\xc1\x10\x41\x06\xd7\x71\xb9\xce\xc1\xd2\x40\xf6\x96\x84\x86\xfb\xba\x87\x32\x1d\xfd\x1e\x37\x8e\x50"] = CTInfo($description="DigiCert Nessie2025 Log", $operator="DigiCert", $url="https://nessie2025.ct.digicert.com/log/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xf2\xf0\xf0\xa7\x8b\x81\x2e\x09\x39\x3b\x9f\x42\xda\x38\x44\x5f\xb4\xcc\xed\x36\xbb\xd8\x43\x7f\x16\x49\x57\x87\x04\x7f\xa5\x01\x34\xf7\xe8\x68\x3f\xb7\x78\x1f\x60\x66\x2d\x67\x9a\x75\x80\xb7\x53\xa7\x85\xd5\xbc\xab\x47\x06\x55\xdb\xb5\xdf\x88\xa1\x6f\x38"), +["\xb6\x9d\xdc\xbc\x3c\x1a\xbd\xef\x6f\x9f\xd6\x0c\x88\xb1\x06\x7b\x77\xf0\x82\x68\x8b\x2d\x78\x65\xd0\x4b\x39\xab\xe9\x27\xa5\x75"] = CTInfo($description="DigiCert 'Wyvern2024h1' Log", $operator="DigiCert", $url="https://wyvern.ct.digicert.com/2024h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x68\xa6\x79\x14\xd1\x58\xe7\xab\xaa\x29\x69\x7f\x60\xed\x68\xe8\x10\xf6\x07\x84\xc0\xfb\x59\x04\x5a\x09\xc9\x1d\xe1\x4b\xfb\xcd\xdc\x03\xf3\xa8\x2a\x46\xb9\x84\x4d\x69\x30\xec\x23\x35\xc1\x8e\xfc\x9f\xb4\x20\x24\xd7\x15\xac\x87\xf7\x1e\xc1\x0b\x3c\x76\x1a"), +["\x0c\x2a\xef\x2c\x4a\x5b\x98\x83\xd4\xdd\xa3\x82\xfe\x50\xfb\x51\x88\xb3\xe9\x73\x33\xa1\xec\x53\xa0\x9d\xc9\xa7\x9d\x0d\x08\x20"] = CTInfo($description="DigiCert 'Wyvern2024h2' Log", $operator="DigiCert", $url="https://wyvern.ct.digicert.com/2024h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa8\x73\x12\x9c\x54\xd0\x7a\x7d\xc5\xb5\x17\x2b\x71\x52\x89\x04\x90\xbb\x42\xf1\x9d\xf8\x1c\xde\x4c\xcf\x82\x3c\xbd\x37\x1b\x74\x4c\x3c\xc7\xa3\x13\x87\x01\x51\x13\x14\xda\xa2\x12\x98\x84\xce\x1c\xbe\xcf\x4f\x7a\xef\x15\xfa\xd0\xee\xed\xed\x07\xad\x71\x6d"), +["\x73\x20\x22\x0f\x08\x16\x8a\xf9\xf3\xc4\xa6\x8b\x0a\xb2\x6a\x9a\x4a\x00\xee\xf5\x77\x85\x8a\x08\x4d\x05\x00\xd4\xa5\x42\x44\x59"] = CTInfo($description="DigiCert 'Wyvern2025h1' Log", $operator="DigiCert", $url="https://wyvern.ct.digicert.com/2025h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa7\xcb\x80\x61\x86\x1b\x1f\xb5\xab\x2b\x20\x76\x59\x83\x66\x0e\xce\xae\xb8\x6f\x3b\x88\x02\xeb\x43\xf4\x87\x90\xcb\x8b\xda\xac\x0e\x19\x50\xe0\xf9\x24\x0e\xab\x26\x93\x8c\x3f\x9e\x0d\x96\x58\x44\x9d\x3b\x8a\x80\xc5\xc8\xbe\xe1\x89\x46\x6b\x48\x4c\xd6\x09"), +["\xed\x3c\x4b\xd6\xe8\x06\xc2\xa4\xa2\x00\x57\xdb\xcb\x24\xe2\x38\x01\xdf\x51\x2f\xed\xc4\x86\xc5\x70\x0f\x20\xdd\xb7\x3e\x3f\xe0"] = CTInfo($description="DigiCert 'Wyvern2025h2' Log", $operator="DigiCert", $url="https://wyvern.ct.digicert.com/2025h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xe0\xdb\x41\xef\xe4\x04\xbd\xcb\x6b\x2e\x4c\xcc\xf1\x6c\xde\x41\x58\x7f\xfe\x94\xf6\x7a\xf6\x60\xed\x8b\x76\x72\xa3\xa2\x1c\x31\x13\x32\x35\xa1\xf2\x08\xd2\x68\xc5\x34\xa7\x56\x08\x1c\x63\xde\x95\xe2\x81\x69\x97\x8d\x1e\xa8\xb7\x66\x51\x25\x75\x4d\x78\x2e"), +["\xdb\x07\x6c\xde\x6a\x8b\x78\xec\x58\xd6\x05\x64\x96\xeb\x6a\x26\xa8\xc5\x9e\x72\x12\x93\xe8\xac\x03\x27\xdd\xde\x89\xdb\x5a\x2a"] = CTInfo($description="DigiCert 'Sphinx2024h1' Log", $operator="DigiCert", $url="https://sphinx.ct.digicert.com/2024h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xc6\xe4\x29\x69\x98\xfe\x28\x92\x57\x12\x4d\x9e\xed\x0e\xe7\x32\xa2\xe6\x9c\x27\x78\xa4\x29\x7c\x99\xd5\xdb\xfa\x22\xc1\xdd\x5e\xa7\xf4\xd8\xea\xc8\xd7\x44\x8d\xe0\xf1\x8c\x0a\x01\x1d\xd8\x22\xa8\xd3\xeb\xc9\x22\x8e\x36\xfb\x4a\xb1\x70\x9c\x5d\xc1\xe8\x33"), +["\xdc\xc9\x5e\x6f\xa2\x99\xb9\xb0\xfd\xbd\x6c\xa6\xa3\x6e\x1d\x72\xc4\x21\x2f\xdd\x1e\x0f\x47\x55\x3a\x36\xd6\xcf\x1a\xd1\x1d\x8d"] = CTInfo($description="DigiCert 'Sphinx2024h2' Log", $operator="DigiCert", $url="https://sphinx.ct.digicert.com/2024h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xdb\x09\x41\x84\xe7\xd1\xf1\x5b\x25\x09\x7b\xe8\xc6\x98\x51\x5e\x29\x85\xfd\x81\xde\x89\xd7\xd0\x86\xa4\xb0\xe5\x15\xec\x5d\x7b\x17\x55\x5f\xc9\x79\x8d\xe4\x22\x36\xe7\xe9\xbf\x38\x3f\xd1\xe9\xd4\x09\x84\x81\xbe\xb6\xc1\xed\x1b\x17\xea\x26\x97\xba\xe9\x9a"), +["\xde\x85\x81\xd7\x50\x24\x7c\x6b\xcd\xcb\xaf\x56\x37\xc5\xe7\x81\xc6\x4c\xe4\x6e\xd6\x17\x63\x9f\x8f\x34\xa7\x26\xc9\xe2\xbd\x37"] = CTInfo($description="DigiCert 'Sphinx2025h1' Log", $operator="DigiCert", $url="https://sphinx.ct.digicert.com/2025h1/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xe3\x2f\x1f\x4d\x89\x05\x75\x29\x78\xbb\x22\x3d\x07\x62\x51\x14\x70\x94\xe7\x3c\xea\xf5\xee\xae\xa6\x48\x9a\x86\x52\x4e\x9e\x5c\xe3\x95\x97\x28\xbb\x52\x4b\x2a\xfd\xc8\xc9\x89\x4e\x45\x31\x17\xd3\x8d\xf2\xe7\xce\x18\x11\x58\x98\x2c\x60\x6f\x58\x20\x36\x6e"), +["\xa4\x42\xc5\x06\x49\x60\x61\x54\x8f\x0f\xd4\xea\x9c\xfb\x7a\x2d\x26\x45\x4d\x87\xa9\x7f\x2f\xdf\x45\x59\xf6\x27\x4f\x3a\x84\x54"] = CTInfo($description="DigiCert 'Sphinx2025h2' Log", $operator="DigiCert", $url="https://sphinx.ct.digicert.com/2025h2/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x41\x8c\x50\x13\x54\xb1\x19\x05\xb7\x7f\x4a\x20\x6e\xa3\x75\x63\xca\x34\xf4\xcc\x74\xea\x32\x3b\xb6\x8b\x03\x14\xa8\x52\x7f\x32\x87\x5e\x59\x9e\x0f\xab\x18\x9e\x29\x6c\xb5\x72\x77\x1a\x27\x54\x85\x5d\xc1\x7b\x24\xa8\x34\xe3\xcd\x88\xce\xd4\x50\x1b\xbe\x69"), ["\x55\x81\xd4\xc2\x16\x90\x36\x01\x4a\xea\x0b\x9b\x57\x3c\x53\xf0\xc0\xe4\x38\x78\x70\x25\x08\x17\x2f\xa3\xaa\x1d\x07\x13\xd3\x0c"] = CTInfo($description="Sectigo 'Sabre' CT log", $operator="Sectigo", $url="https://sabre.ct.comodo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xf2\x6f\xd2\x89\x0f\x3f\xc5\xf8\x87\x1e\xab\x65\xb3\xd9\xbb\x17\x23\x8c\x06\x0e\x09\x55\x96\x3d\x0a\x08\xa2\xc5\x71\xb3\xd1\xa9\x2f\x28\x3e\x83\x10\xbf\x12\xd0\x44\x66\x15\xef\x54\xe1\x98\x80\xd0\xce\x24\x6d\x3e\x67\x9a\xe9\x37\x23\xce\x52\x93\x86\xda\x80"), ["\xa2\xe2\xbf\xd6\x1e\xde\x2f\x2f\x07\xa0\xd6\x4e\x6d\x37\xa7\xdc\x65\x43\xb0\xc6\xb5\x2e\xa2\xda\xb7\x8a\xf8\x9a\x6d\xf5\x17\xd8"] = CTInfo($description="Sectigo 'Sabre2024h1'", $operator="Sectigo", $url="https://sabre2024h1.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x2c\x01\xf6\xce\x31\xbc\xaa\x14\x61\x51\xfe\x6b\x7a\x87\xae\xa6\xd3\x9b\xc7\x87\x2d\x0a\x5a\xc8\x4f\xb5\x54\xdc\xc9\x93\xa0\x00\xee\xca\x1c\xb9\xa7\xb6\x7b\x47\x3b\xe5\x4f\xaa\x6c\x16\x1c\x70\x2e\xc8\xec\x53\x5a\x4c\x21\x4c\x7e\x27\x0b\x13\x14\x5e\xfc\x85"), ["\x19\x98\x10\x71\x09\xf0\xd6\x52\x2e\x30\x80\xd2\x9e\x3f\x64\xbb\x83\x6e\x28\xcc\xf9\x0f\x52\x8e\xee\xdf\xce\x4a\x3f\x16\xb4\xca"] = CTInfo($description="Sectigo 'Sabre2024h2'", $operator="Sectigo", $url="https://sabre2024h2.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x7a\x10\x4c\x8a\xe7\x22\x7b\x6d\x2a\xba\x8e\xfa\x6b\x4a\x81\xd5\x85\xae\x03\xef\xff\x4b\xfc\x4d\x53\x3d\xb7\x8c\xbb\x75\x09\xc9\xea\x16\x7e\xc1\x77\x16\xd2\xc2\x45\x74\x6d\x8d\xc4\xe1\x88\x37\xdf\xd4\xf3\x60\x65\xfc\xa0\x75\xf0\x20\x66\x8e\x4a\xcc\x19\xda"), ["\xe0\x92\xb3\xfc\x0c\x1d\xc8\xe7\x68\x36\x1f\xde\x61\xb9\x96\x4d\x0a\x52\x78\x19\x8a\x72\xd6\x72\xc4\xb0\x4d\xa5\x6d\x6f\x54\x04"] = CTInfo($description="Sectigo 'Sabre2025h1'", $operator="Sectigo", $url="https://sabre2025h1.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x7e\x2f\x39\xf1\xe8\x23\x8e\xb3\x32\x04\xaf\x4d\x57\xf6\xdb\xc5\x74\xa4\x7a\x6d\x3b\x07\x51\x0c\x5a\xfb\x80\x30\x05\xc6\x5a\x0c\xc4\x76\xd6\x06\xa8\x57\x4d\xfb\xdf\xe4\x82\x90\xc2\x41\xae\x70\xb3\x31\xa2\xe3\xfa\x3d\x5f\x2c\x5d\x04\xcd\xb4\x9d\x55\xab\x41"), ["\x1a\x04\xff\x49\xd0\x54\x1d\x40\xaf\xf6\xa0\xc3\xbf\xf1\xd8\xc4\x67\x2f\x4e\xec\xee\x23\x40\x68\x98\x6b\x17\x40\x2e\xdc\x89\x7d"] = CTInfo($description="Sectigo 'Sabre2025h2'", $operator="Sectigo", $url="https://sabre2025h2.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x85\x13\x11\x2d\x7b\xf3\x93\x81\xe4\xb9\x7c\xd9\x64\x3b\xe7\xb5\x83\x99\x66\x79\x59\x47\x6a\x42\x5e\xd6\xbd\x63\x2e\xb7\x91\x4b\xae\xbc\x56\xc4\xc5\x6e\x09\xa0\xd7\x64\x1a\xc8\xc1\xaf\x89\x8b\xf5\x58\xd8\xba\xeb\x7b\x83\x52\xe9\xf4\xe0\xa5\xcd\xcd\x92\xcc"), -["\x6f\x53\x76\xac\x31\xf0\x31\x19\xd8\x99\x00\xa4\x51\x15\xff\x77\x15\x1c\x11\xd9\x02\xc1\x00\x29\x06\x8d\xb2\x08\x9a\x37\xd9\x13"] = CTInfo($description="Sectigo 'Mammoth' CT log", $operator="Sectigo", $url="https://mammoth.ct.comodo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xef\xe4\x7d\x74\x2e\x15\x15\xb6\xe9\xbb\x23\x8b\xfb\x2c\xb5\xe1\xc7\x80\x98\x47\xfb\x40\x69\x68\xfc\x49\xad\x61\x4e\x83\x47\x3c\x1a\xb7\x8d\xdf\xff\x7b\x30\xb4\xba\xff\x2f\xcb\xa0\x14\xe3\xad\xd5\x85\x3f\x44\x59\x8c\x8c\x60\x8b\xd7\xb8\xb1\xbf\xae\x8c\x67"), ["\x29\xd0\x3a\x1b\xb6\x74\xaa\x71\x1c\xd3\x03\x5b\x65\x57\xc1\x4f\x8a\xa7\x8b\x4f\xe8\x38\x94\x49\xec\xa4\x53\xf9\x44\xbd\x24\x68"] = CTInfo($description="Sectigo 'Mammoth2024h1'", $operator="Sectigo", $url="https://mammoth2024h1.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa4\x59\x90\xf3\x71\x24\x24\xf7\xc3\x55\x27\x56\x9c\xa3\x59\x1e\xf7\xb7\x9f\xce\xab\x4e\x19\x66\x4d\xd0\x8a\xfa\x9d\x62\xa4\x24\xf0\x3b\x20\xe4\x1d\x14\x67\xc8\xfc\xe4\x37\xf2\x4b\x38\x54\x5a\xcf\x9f\x6b\x07\x90\xd0\x0e\x7e\x3d\x4c\x87\xb2\xe8\x3f\x07\xcc"), ["\x50\x85\x01\x58\xdc\xb6\x05\x95\xc0\x0e\x92\xa8\x11\x02\xec\xcd\xfe\x3f\x6b\x78\x58\x42\x9f\x57\x98\x35\x38\xc9\xda\x52\x50\x63"] = CTInfo($description="Sectigo 'Mammoth2024h1b'", $operator="Sectigo", $url="https://mammoth2024h1b.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa3\xd5\x07\x28\x7a\x04\x34\xae\xca\xbe\x80\x79\x4f\x3e\xf6\x41\xf4\x24\x04\xe1\xd6\x36\x5a\x1a\x09\xf2\xd1\xba\x84\x17\xae\x1e\xa1\x7c\x00\x1d\x54\x73\x90\x75\x21\xa8\xd1\xda\x5e\x10\xe1\x8c\xec\xb2\x8a\x8c\xc8\xe7\xdd\xcd\xe2\x07\xf0\x4e\x16\x02\x57\x37"), ["\xdf\xe1\x56\xeb\xaa\x05\xaf\xb5\x9c\x0f\x86\x71\x8d\xa8\xc0\x32\x4e\xae\x56\xd9\x6e\xa7\xf5\xa5\x6a\x01\xd1\xc1\x3b\xbe\x52\x5c"] = CTInfo($description="Sectigo 'Mammoth2024h2'", $operator="Sectigo", $url="https://mammoth2024h2.ct.sectigo.com/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x85\x66\x22\x24\x6e\xbe\x52\x62\x0a\xa0\xaf\xc3\x25\x1a\x36\x2e\xa7\x60\x89\xa2\x65\xbf\xa4\x5f\xbd\x85\x6a\x94\x05\x81\x35\x90\x54\x31\x95\xe7\x11\x9e\xa3\x2e\x0f\x85\xef\xa7\x88\x57\x8b\x63\x1a\x81\xc1\x41\x9d\x7d\xec\x01\x3a\xdb\xb9\xc1\x27\xf4\x65\x1e"), @@ -39,4 +50,6 @@ redef ct_logs += { ["\x87\x4f\xb5\x0d\xc0\x29\xd9\x93\x1d\xe5\x73\xe9\xf2\x89\x9e\x8e\x45\x33\xb3\x92\xd3\x8b\x0a\x46\x25\x74\xbf\x0f\xee\xb2\xfc\x1e"] = CTInfo($description="Trust Asia Log2024-2", $operator="TrustAsia", $url="https://ct2024.trustasia.com/log2024/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa7\x64\xe2\x79\x81\x3f\x61\xd7\xec\xc6\xf8\x65\x28\x1d\xa0\xb4\x66\x33\xc3\x25\xd5\x0a\x95\x78\x9c\x8f\xfe\xa4\x2a\xd8\x8f\x7e\x72\xe0\xfe\xa8\x7f\xf8\xb1\x2d\x85\xc0\x8e\x12\x74\x0d\x2f\x8c\xab\xd7\x7f\x7a\x1e\xd9\x84\x33\x39\xe8\xfd\x89\x5f\x96\x48\x08"), ["\x28\xe2\x81\x38\xfd\x83\x21\x45\xe9\xa9\xd6\xaa\x75\x37\x6d\x83\x77\xa8\x85\x12\xb3\xc0\x7f\x72\x41\x48\x21\xdc\xbd\xe9\x8c\x66"] = CTInfo($description="TrustAsia Log2025a", $operator="TrustAsia", $url="https://ct2025-a.trustasia.com/log2025a/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x70\xe5\xb1\xa4\x09\x79\x2b\x9d\xf8\xa3\xa0\xdf\x18\xef\x95\x5d\x03\x6c\x7b\xa1\x91\xa9\xb8\x80\x7d\xec\x5c\x02\x08\xe2\x6e\x2f\x7c\x32\x70\xbd\x96\x84\x5f\xa6\x62\xe9\x65\xb5\x7c\x90\x58\xba\x22\xd5\xf9\xf5\x69\x54\xb7\xa8\x94\x4e\x32\x09\xae\x26\x11\x4d"), ["\x28\x2c\x8b\xdd\x81\x0f\xf9\x09\x12\x0a\xce\x16\xd6\xe0\xec\x20\x1b\xea\x82\xa3\xa4\xaf\x19\xd9\xef\xfb\x59\xe8\x3f\xdc\x42\x68"] = CTInfo($description="TrustAsia Log2025b", $operator="TrustAsia", $url="https://ct2025-b.trustasia.com/log2025b/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xaa\xa0\x8b\xdb\x67\x14\x5d\x97\x89\x1d\x08\x8d\x06\xd7\xc1\x94\x8e\xb0\xfa\x4c\x46\xd5\x53\x08\x78\x2b\x04\x53\x6c\xf3\xde\xb1\xd1\x53\x40\xda\x90\x57\xe6\x1a\x9e\x3c\xc7\x03\xb8\xbd\x2f\xa9\xcf\xe8\x7b\x5e\xe1\x4b\x60\xe5\x38\x43\x60\x97\xc1\x5b\x2f\x65"), +["\x74\xdb\x9d\x58\xf7\xd4\x7e\x9d\xfd\x78\x7a\x16\x2a\x99\x1c\x18\xcf\x69\x8d\xa7\xc7\x29\x91\x8c\x9a\x18\xb0\x45\x0d\xba\x44\xbc"] = CTInfo($description="TrustAsia 'log2026a'", $operator="TrustAsia", $url="https://ct2026-a.trustasia.com/log2026a/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa7\x4e\x7a\xc9\xa6\x07\xf9\xff\x74\xec\x98\xcb\x49\xe1\x00\x24\xb3\x59\x2e\x83\xfd\xc0\x70\x35\x33\x4c\x63\xca\x74\x83\xc0\x3c\x5b\x53\x40\x7c\x31\x1f\x35\xa4\x5f\x0f\xe4\xee\x4f\x89\x17\xe8\x5b\x2e\xc5\xac\x00\x05\xc9\x76\x37\x45\x97\x03\x15\xff\x60\x59"), +["\x25\xb7\xef\xde\xa1\x13\x01\x93\xed\x93\x07\x97\x70\xaa\x32\x2a\x26\x62\x0d\xe3\x5a\xc8\xaa\x7c\x75\x19\x7d\xe0\xb1\xa9\xe0\x65"] = CTInfo($description="TrustAsia 'log2026b'", $operator="TrustAsia", $url="https://ct2026-b.trustasia.com/log2026b/", $maximum_merge_delay=86400, $key="\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x0f\x12\x8c\xa9\xe6\xe3\xec\x62\xee\xdf\x58\xc8\x50\xe6\x26\x70\x76\x10\xb7\x04\x39\xb3\xa7\xf8\x4c\x73\x3b\xc3\x38\x5a\x12\x00\x4c\xe0\xda\x0e\x16\x8a\x45\x32\x0a\x31\xaa\x22\xc7\x9d\x7d\x05\x53\xc7\x9e\x94\xea\x9b\x57\x46\xbf\x4f\xa4\x7e\xfb\xdf\xfa\x85"), }; diff --git a/scripts/base/protocols/ssl/mozilla-ca-list.zeek b/scripts/base/protocols/ssl/mozilla-ca-list.zeek index 1206908a10..e308f1fb75 100644 --- a/scripts/base/protocols/ssl/mozilla-ca-list.zeek +++ b/scripts/base/protocols/ssl/mozilla-ca-list.zeek @@ -1,6 +1,6 @@ # Don't edit! This file is automatically generated. -# Generated at: 2024-02-23 11:28:07 +0000 -# Generated from: NSS 3.98 +# Generated at: 2024-07-23 16:04:06 +0100 +# Generated from: NSS 3.102 # # The original source file comes with this licensing statement: # @@ -158,4 +158,5 @@ redef root_certs += { ["CN=CommScope Public Trust RSA Root-02,O=CommScope,C=US"] = "\x30\x82\x05\x6C\x30\x82\x03\x54\xA0\x03\x02\x01\x02\x02\x14\x54\x16\xBF\x3B\x7E\x39\x95\x71\x8D\xD1\xAA\x00\xA5\x86\x0D\x2B\x8F\x7A\x05\x4E\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x30\x4E\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x12\x30\x10\x06\x03\x55\x04\x0A\x0C\x09\x43\x6F\x6D\x6D\x53\x63\x6F\x70\x65\x31\x2B\x30\x29\x06\x03\x55\x04\x03\x0C\x22\x43\x6F\x6D\x6D\x53\x63\x6F\x70\x65\x20\x50\x75\x62\x6C\x69\x63\x20\x54\x72\x75\x73\x74\x20\x52\x53\x41\x20\x52\x6F\x6F\x74\x2D\x30\x32\x30\x1E\x17\x0D\x32\x31\x30\x34\x32\x38\x31\x37\x31\x36\x34\x33\x5A\x17\x0D\x34\x36\x30\x34\x32\x38\x31\x37\x31\x36\x34\x32\x5A\x30\x4E\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x12\x30\x10\x06\x03\x55\x04\x0A\x0C\x09\x43\x6F\x6D\x6D\x53\x63\x6F\x70\x65\x31\x2B\x30\x29\x06\x03\x55\x04\x03\x0C\x22\x43\x6F\x6D\x6D\x53\x63\x6F\x70\x65\x20\x50\x75\x62\x6C\x69\x63\x20\x54\x72\x75\x73\x74\x20\x52\x53\x41\x20\x52\x6F\x6F\x74\x2D\x30\x32\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xE1\xFA\x0E\xFB\x68\x00\x12\xC8\x4D\xD5\xAC\x22\xC4\x35\x01\x3B\xC5\x54\xE5\x59\x76\x63\xA5\x7F\xEB\xC1\xC4\x6A\x98\xBD\x32\x8D\x17\x80\xEB\x5D\xBA\xD1\x62\x3D\x25\x23\x19\x35\x14\xE9\x7F\x89\xA7\x1B\x62\x3C\xD6\x50\xE7\x34\x95\x03\x32\xB1\xB4\x93\x22\x3D\xA7\xE2\xB1\xED\xE6\x7B\x4E\x2E\x87\x9B\x0D\x33\x75\x0A\xDE\xAA\x35\xE7\x7E\xE5\x36\x98\xA2\xAE\x25\x9E\x95\xB3\x32\x96\xA4\x2B\x58\x1E\xEF\x3F\xFE\x62\x34\x48\x51\xD1\xB4\x8D\x42\xAD\x60\xDA\x49\x6A\x95\x70\xDD\xD2\x00\xE2\xCC\x57\x63\x02\x7B\x96\xDD\x49\x97\x5B\x92\x4E\x95\xD3\xF9\xCB\x29\x1F\x18\x4A\xF8\x01\x2A\xD2\x63\x09\x6E\x24\xE9\x89\xD2\xE5\xC7\x22\x4C\xDC\x73\x86\x47\x00\xAA\x0D\x88\x8E\xAE\x85\x7D\x4A\xE9\xBB\x33\x4F\x0E\x52\x70\x9D\x95\xE3\x7C\x6D\x96\x5B\x2D\x3D\x5F\xA1\x83\x46\x5D\xB6\xE3\x25\xB8\x7C\xA7\x19\x80\x1C\xEA\x65\x43\xDC\x91\x79\x36\x2C\x74\x7C\xF2\x67\x06\xC9\x89\xC9\xDB\xBF\xDA\x68\xBF\x23\xED\xDC\x6B\xAD\x28\x83\x79\x2F\xEC\x38\xA5\x0D\x37\x01\x67\x27\x9A\xE9\x33\xD9\x33\x5F\x37\xA1\xC5\xF0\xAB\x3D\xFA\x78\xB0\xE7\x2C\x9F\xF6\x3E\x9F\x60\xE0\xEF\x48\xE9\x90\x45\x1E\x05\x51\x78\x1A\x2C\x12\x2C\x5C\x28\xAC\x0D\xA2\x23\x9E\x34\x8F\x05\xE6\xA2\x33\xCE\x11\x77\x13\xD4\x0E\xA4\x1E\x42\x1F\x86\xCD\x70\xFE\xD9\x2E\x15\x3D\x1D\xBB\xB8\xF2\x53\x57\xDB\xCC\xC6\x74\x29\x9C\x18\xB3\x36\x75\x38\x2E\x0F\x54\xA1\xF8\x92\x1F\x89\x96\x4F\xBB\xD4\xEE\x9D\xE9\x3B\x36\x42\xB5\x0A\x3B\x2A\xD4\x64\x79\x36\x10\xE1\xF9\x91\x03\x2B\x7B\x20\x54\xCD\x0D\x19\x1A\xC8\x41\x32\x34\xD1\xB0\x99\xE1\x90\x1E\x01\x40\x36\xB5\xB7\xFA\xA9\xE5\x77\x75\xA4\x22\x81\x5D\xB0\x8B\xE4\x27\x12\x0F\x54\x88\xC6\xDB\x85\x74\xE6\xB7\xC0\xD7\xA6\x29\xFA\xDB\xDE\xF3\x93\x97\x27\x04\x55\x2F\x0A\x6F\x37\xC5\x3D\x13\xAF\x0A\x00\xA9\x2C\x8B\x1C\x81\x28\xD7\xEF\x86\x31\xA9\xAE\xF2\x6E\xB8\xCA\x6A\x2C\x54\x47\xD8\x2A\x88\x2E\xAF\xC1\x07\x10\x78\xAC\x11\xA2\x2F\x42\xF0\x37\xC5\xF2\xB8\x56\xDD\x0E\x62\x2D\xCE\x2D\x56\x7E\x55\xF2\xA7\x44\xF6\x2B\x32\xF4\x23\xA8\x47\xE8\xD4\x2A\x01\x78\xCF\x6A\xC3\x37\xA8\x9E\x65\xD2\x2C\xE5\xFA\xBA\x33\xC1\x06\x44\xF6\xE6\xCF\xA5\x0D\xA7\x66\x08\x34\x8A\x2C\xF3\x02\x03\x01\x00\x01\xA3\x42\x30\x40\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x47\xD0\xE7\xB1\x22\xFF\x9D\x2C\xF5\xD9\x57\x60\xB3\xB1\xB1\x70\x95\xEF\x61\x7A\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B\x05\x00\x03\x82\x02\x01\x00\x86\x69\xB1\x4D\x2F\xE9\x9F\x4F\x22\x93\x68\x8E\xE4\x21\x99\xA3\xCE\x45\x53\x1B\x73\x44\x53\x00\x81\x61\xCD\x31\xE3\x08\xBA\x81\x28\x28\x7A\x92\xB9\xB6\xA8\xC8\x43\x9E\xC7\x13\x26\x4D\xC2\xD8\xE5\x55\x9C\x92\x5D\x50\xD8\xC2\x2B\xDB\xFE\xE6\xA8\x97\xCF\x52\x3A\x24\xC3\x65\x64\x5C\x47\x31\xA3\x65\x35\x13\xC3\x93\xB9\xF7\xF9\x51\x97\xBB\xA4\xF0\x62\x87\xC5\xD6\x06\xD3\x97\x83\x20\xA9\x7E\xBB\xB6\x21\xC2\xA5\x0D\x84\x00\xE1\xF2\x27\x10\x83\xBA\xDD\x03\x81\xD5\xDD\x68\xC3\x66\x10\xC8\xD1\x76\xB4\xB3\x6F\x29\x9E\x00\xF9\xC2\x29\xF5\xB1\x93\x19\x52\x69\x1A\x2C\x4C\xA0\x8B\xE0\x15\x9A\x31\x2F\xD3\x88\x95\x59\x6E\xE5\xC4\xB3\x50\xC8\x14\x08\x4A\x9B\x8B\x13\x83\xB1\xA4\x72\xB2\x3B\x76\x33\x41\xDC\xDC\xAA\xA6\x07\x6F\x1D\x24\x12\x9F\xC8\x76\xBD\x2F\xD9\x8E\xF4\x2C\xEE\xB7\xD2\x38\x10\x24\x36\x51\x2F\xE3\x5C\x5D\x81\x21\xA7\xDA\xBB\x4E\xFF\xE6\x07\xA8\xFE\xB9\x0D\x27\x6C\xBB\x70\x5A\x55\x7A\x13\xE9\xF1\x2A\x49\x69\xC7\x5F\x87\x57\x4C\x43\x79\x6D\x3A\x65\xE9\x30\x5C\x41\xEE\xEB\x77\xA5\x73\x12\x88\xE8\xBF\x7D\xAE\xE5\xC4\xA8\x1F\x0D\x8E\x1C\x6D\x50\x02\x4F\x26\x18\x43\xDE\x8F\x55\x85\xB1\x0B\x37\x05\x60\xC9\x55\x39\x12\x04\xA1\x2A\xCF\x71\x16\x9F\x36\x51\x49\xBF\x70\x3B\x9E\x67\x9C\xFB\x7B\x79\xC9\x39\x1C\x78\xAC\x77\x91\x54\x9A\xB8\x75\x0A\x81\x52\x97\xE3\x66\x61\x6B\xED\x3E\x38\x1E\x96\x61\x55\xE1\x91\x54\x8C\xED\x8C\x24\x1F\x81\xC9\x10\x9A\x73\x99\x2B\x16\x4E\x72\x00\x3F\x54\x1B\xF8\x8D\xBA\x8B\xE7\x14\xD6\xB6\x45\x4F\x60\xEC\x96\xAE\xC3\x2F\x02\x4E\x5D\x9D\x96\x49\x72\x00\xB2\xAB\x75\x5C\x0F\x68\x5B\x1D\x65\xC2\x5F\x33\x0F\x1E\x0F\xF0\x3B\x86\xF5\xB0\x4E\xBB\x9C\xF7\xEA\x25\x05\xDC\xAD\xA2\x9B\x4B\x17\x01\xBE\x42\xDF\x35\x21\x1D\xAD\xAB\xAE\xF4\xBF\xAE\x1F\x1B\xD3\xE2\x3B\xFC\xB3\x72\x73\x1C\x9B\x28\x90\x89\x13\x3D\x1D\xC1\x00\x47\x09\x96\x9A\x38\x1B\xDD\xB1\xCF\x0D\xC2\xB4\x44\xF3\x96\x95\xCE\x32\x3A\x8F\x34\x9C\xE0\x17\xC7\x5E\xCE\xAE\x0D\xDB\x87\x38\xE5\x3F\x5B\xFD\x9B\x19\xE1\x31\x41\x7A\x70\xAA\x23\x6B\x01\xE1\x45\x4C\xCD\x94\xCE\x3B\x9E\x2D\xE7\x88\x02\x22\xF4\x6E\xE8\xC8\xEC\xD6\x3C\xF3\xB9\xB2\xD7\x77\x7A\xAC\x7B", ["CN=Telekom Security TLS ECC Root 2020,O=Deutsche Telekom Security GmbH,C=DE"] = "\x30\x82\x02\x42\x30\x82\x01\xC9\xA0\x03\x02\x01\x02\x02\x10\x36\x3A\x96\x8C\xC9\x5C\xB2\x58\xCD\xD0\x01\x5D\xC5\xE5\x57\x00\x30\x0A\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x03\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x0C\x1E\x44\x65\x75\x74\x73\x63\x68\x65\x20\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x47\x6D\x62\x48\x31\x2B\x30\x29\x06\x03\x55\x04\x03\x0C\x22\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x54\x4C\x53\x20\x45\x43\x43\x20\x52\x6F\x6F\x74\x20\x32\x30\x32\x30\x30\x1E\x17\x0D\x32\x30\x30\x38\x32\x35\x30\x37\x34\x38\x32\x30\x5A\x17\x0D\x34\x35\x30\x38\x32\x35\x32\x33\x35\x39\x35\x39\x5A\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x0C\x1E\x44\x65\x75\x74\x73\x63\x68\x65\x20\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x47\x6D\x62\x48\x31\x2B\x30\x29\x06\x03\x55\x04\x03\x0C\x22\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x54\x4C\x53\x20\x45\x43\x43\x20\x52\x6F\x6F\x74\x20\x32\x30\x32\x30\x30\x76\x30\x10\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01\x06\x05\x2B\x81\x04\x00\x22\x03\x62\x00\x04\xCE\xBF\xFE\x57\xA8\xBF\xD5\xAA\xF7\x10\x9A\xCD\xBC\xD1\x11\xA2\xBD\x67\x42\xCC\x90\xEB\x15\x18\x90\xD9\xA2\xCD\x0C\x2A\x25\xEB\x3E\x4F\xCE\xB5\xD2\x8F\x0F\xF3\x35\xDA\x43\x8B\x02\x80\xBE\x6F\x51\x24\x1D\x0F\x6B\x2B\xCA\x9F\xC2\x6F\x50\x32\xE5\x37\x20\xB6\x20\xFF\x88\x0D\x0F\x6D\x49\xBB\xDB\x06\xA4\x87\x90\x92\x94\xF4\x09\xD0\xCF\x7F\xC8\x80\x0B\xC1\x97\xB3\xBB\x35\x27\xC9\xC2\x1B\xA3\x42\x30\x40\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xE3\x72\xCC\x6E\x95\x99\x47\xB1\xE6\xB3\x61\x4C\xD1\xCB\xAB\xE3\xBA\xCD\xDE\x9F\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0A\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x03\x03\x67\x00\x30\x64\x02\x30\x75\x52\x8B\xB7\xA4\x10\x4F\xAE\x4A\x10\x8B\xB2\x84\x5B\x42\xE1\xE6\x2A\x36\x02\xDA\xA0\x6E\x19\x3F\x25\xBF\xDA\x59\x32\x8E\xE4\xFB\x90\xDC\x93\x64\xCE\xAD\xB4\x41\x47\x60\xE2\xCF\xA7\xCB\x1E\x02\x30\x37\x41\x8C\x66\xDF\x41\x6B\xD6\x83\x00\x41\xFD\x2F\x5A\xF7\x50\xB4\x67\xD1\x2C\xA8\x71\xD7\x43\xCA\x9C\x27\x24\x91\x83\x48\x0D\xCF\xCD\xF7\x54\x81\xAF\xEC\x7F\xE4\x67\xDB\xB8\x90\xEE\xDD\x25", ["CN=Telekom Security TLS RSA Root 2023,O=Deutsche Telekom Security GmbH,C=DE"] = "\x30\x82\x05\xB3\x30\x82\x03\x9B\xA0\x03\x02\x01\x02\x02\x10\x21\x9C\x54\x2D\xE8\xF6\xEC\x71\x77\xFA\x4E\xE8\xC3\x70\x57\x97\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C\x05\x00\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x0C\x1E\x44\x65\x75\x74\x73\x63\x68\x65\x20\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x47\x6D\x62\x48\x31\x2B\x30\x29\x06\x03\x55\x04\x03\x0C\x22\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x54\x4C\x53\x20\x52\x53\x41\x20\x52\x6F\x6F\x74\x20\x32\x30\x32\x33\x30\x1E\x17\x0D\x32\x33\x30\x33\x32\x38\x31\x32\x31\x36\x34\x35\x5A\x17\x0D\x34\x38\x30\x33\x32\x37\x32\x33\x35\x39\x35\x39\x5A\x30\x63\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x27\x30\x25\x06\x03\x55\x04\x0A\x0C\x1E\x44\x65\x75\x74\x73\x63\x68\x65\x20\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x47\x6D\x62\x48\x31\x2B\x30\x29\x06\x03\x55\x04\x03\x0C\x22\x54\x65\x6C\x65\x6B\x6F\x6D\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x54\x4C\x53\x20\x52\x53\x41\x20\x52\x6F\x6F\x74\x20\x32\x30\x32\x33\x30\x82\x02\x22\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x82\x02\x0F\x00\x30\x82\x02\x0A\x02\x82\x02\x01\x00\xED\x35\xA1\x81\x80\xF3\xCB\x4A\x69\x5B\xC2\xFB\x51\x83\xAE\x26\xFD\xE1\x6E\xF3\x81\x12\x7D\x71\x40\xFF\x87\x75\x42\x29\x21\xED\x81\x52\x2C\xDF\x12\xC1\x19\x84\x89\xC1\xBD\xC5\x28\xD5\xD5\x4B\x6C\x44\xD6\x4C\xDB\x07\x96\x4A\x55\x7A\xCA\x36\x82\x04\x36\xA8\xA5\xFC\x27\xF6\x49\xF1\xD5\x72\x9E\x91\xF9\x23\xD6\x70\x7B\xBB\xF5\x9B\xC1\xEC\x93\xCF\x19\xEA\x65\x7E\x88\x70\xA0\x73\xFC\xF6\xFF\xB5\x56\x62\xE1\x73\x6A\x34\x98\x3E\x82\xB8\xAC\x95\x53\xF4\x01\xA0\x27\x07\x72\xA3\x00\x53\xA0\xE4\xB2\xAB\x83\x38\x57\x33\x25\x94\x9F\xBE\x48\x1D\x98\xE1\xA3\xBA\x9E\x5C\xCD\x04\x71\x51\x7D\x75\x78\xAB\xF3\x59\xAA\xC4\xE0\x60\xBE\x8F\x83\x52\xB8\x75\x1A\x41\x35\xED\xBC\xF3\x3A\x63\xE9\xA9\x14\x45\xD7\xE6\x52\xD1\x6E\xD2\xDE\xBC\xE3\xF5\x0B\x3B\xE6\xE0\xC4\xBD\x43\x64\x13\xA6\xCE\xF4\x98\x37\x6C\x8A\x95\xA8\x97\xC8\x47\x0F\xF0\x5E\x10\x8B\xE7\x1D\x1C\xFE\xB1\x3B\xA0\x05\x33\x68\x05\x41\x82\xC1\x03\x2B\x01\xC8\xE7\x8F\x4D\xAB\xE8\xB5\xF6\xCD\x6B\x44\xB5\xE7\xDD\x8B\xEC\xEA\x25\xB4\x00\x22\x57\x4D\xB0\xB1\xB2\x31\xC1\x16\xCE\xFF\xFD\x14\x84\xB7\x47\xFA\xB2\xF1\x70\xDE\xDB\x8B\x6C\x36\x58\xA4\x7C\xB3\x11\xD1\xC3\x77\x7F\x5F\xB6\x25\xE0\x0D\xC5\xD2\xB3\xF9\xB8\xB8\x77\xDB\x37\x71\x71\x47\xE3\x60\x18\x4F\x24\xB6\x75\x37\x78\xB9\xA3\x62\xAF\xBD\xC9\x72\x8E\x2F\xCC\xBB\xAE\xDB\xE4\x15\x52\x19\x07\x33\xFB\x6A\xB7\x2D\x4B\x90\x28\x82\x73\xFE\x18\x8B\x35\x8D\xDB\xA7\x04\x6A\xBE\xEA\xC1\x4D\x36\x3B\x16\x36\x91\x32\xEF\xB6\x40\x89\x91\x43\xE0\xF2\xA2\xAB\x04\x2E\xE6\xF2\x4C\x0E\x16\x34\x20\xAC\x87\xC1\x2D\x7E\xC9\x66\x47\x17\x14\x11\xA4\xF3\xF7\xA1\x24\x89\xAB\xD8\x1A\xC8\xA1\x5C\xB1\xA3\xF7\x8C\x6D\xC8\x01\xC9\x4F\xC9\xEC\xC4\xFC\xAC\x51\x33\xD1\xC8\x83\xD1\xC9\x9F\x1D\xD4\x47\x34\x29\x3E\xCB\xB0\x0E\xFA\x83\x0B\x28\x58\xE5\x29\xDC\x3F\x7C\xA8\x9F\xC9\xB6\x0A\xBB\xA6\xE8\x46\x16\x0F\x96\xE5\x7B\xE4\x6A\x7A\x48\x6D\x76\x98\x05\xA5\xDC\x6D\x1E\x42\x1E\x42\xDA\x1A\xE0\x52\xF7\xB5\x83\xC0\x1A\x7B\x78\x35\x2C\x38\xF5\x1F\xFD\x49\xA3\x2E\xD2\x59\x63\xBF\x80\xB0\x8C\x93\x73\xCB\x35\xA6\x99\x95\x22\x61\x65\x03\x60\xFB\x2F\x93\x4B\xFA\x9A\x9C\x80\x3B\x02\x03\x01\x00\x01\xA3\x63\x30\x61\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\xB6\xA7\x97\x82\x3D\x74\x85\x9B\xF7\x3C\x9F\x93\x9A\x95\x79\x75\x52\x8C\x6D\x47\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\xB6\xA7\x97\x82\x3D\x74\x85\x9B\xF7\x3C\x9F\x93\x9A\x95\x79\x75\x52\x8C\x6D\x47\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C\x05\x00\x03\x82\x02\x01\x00\xA8\xCC\x61\xA6\xBE\x75\x9E\x15\x50\xA4\x6B\xFB\xA8\x70\x45\x7C\xBA\x7E\xB1\x5A\xFC\x5B\x23\xFA\x0A\x77\xF8\x98\x71\x82\x0C\x6D\xE0\x5E\x46\xAA\x93\xF4\x1E\xA0\xC3\xE1\x93\xDB\x4B\xAD\xB2\xA6\x5D\xAB\xB0\xD4\x62\xCB\x5E\xBB\x66\xF5\x2D\xEE\x97\x40\x3C\x62\xEB\x5E\xD6\x14\xD6\x8C\xE2\x96\x8B\x41\x69\x93\x35\xE6\xB9\x99\x6B\x62\xB4\xA1\x17\x66\x34\xA6\x6B\x63\xC6\xB9\x4E\xF2\x22\xE9\x58\x0D\x56\x41\xD1\xFA\x0C\x4A\xF0\x33\xCD\x3B\xBB\x6D\x21\x3A\xAE\x8E\x72\xB5\xC3\x4A\xFB\xE9\x7D\xE5\xB1\x9B\x86\xEE\xE2\xE0\x7D\xB4\xF7\x32\xFD\x22\x84\xF1\x85\xC9\x37\x79\xE9\xB5\x3F\xBF\x5C\xE4\x74\xB2\x8F\x11\x62\x00\xDD\x18\x66\xA1\xD9\x7B\x23\x5F\xF1\x8E\xD5\x67\xE8\x54\xDA\x5B\x3A\x6B\x36\x6F\xF9\x81\xB1\x33\x47\x33\x77\x40\xF9\x52\xAA\xDD\xD4\x83\xCF\x85\x78\x99\x9A\x93\xB9\x73\x67\x42\x46\x11\x21\xEA\xFE\x0A\xA9\x1B\x1A\x65\x69\xB3\x8F\xAE\x16\xB6\xF6\x4B\x56\xB2\x2D\xF9\xA5\xC8\xEC\x3B\x62\xA3\xED\x6B\xD0\x4E\xD5\x40\x09\xA4\x1F\x98\xD7\x3A\xA5\x92\x59\x20\xE4\xB0\x7D\xCD\x5B\x73\x68\xBD\x6D\xC4\xA2\x13\x0E\x67\x19\xB8\x8D\x42\x7E\x6C\x0C\x9A\x6E\xA0\x24\x2D\xD5\x45\x1B\xDC\xC4\x02\x14\xFE\x85\x5B\x65\x97\xCA\x4E\x90\x50\x08\x7A\x42\x35\xF9\xEA\xC2\x66\xD4\xF8\x01\xAE\x1E\xB4\xBE\xC3\xA8\xEF\xFE\x76\x9A\xA2\xA6\x1F\x46\xF6\x84\xED\xFC\xDB\xCE\xC4\x02\xCE\x77\x48\x2C\x8C\xB2\xEC\xC3\x00\xA3\xEC\x2C\x55\x18\xC1\x7E\x19\xEE\xE1\x2F\xF2\xAD\x83\x9B\x9E\xAB\x19\xDF\xC6\x8A\x2F\x8C\x77\xE5\xB7\x05\xEC\x3B\xC1\xEC\xBE\x86\xB3\x86\xBC\xC0\xF7\xDC\xE7\xEA\x5B\xAE\xB2\xCC\xB5\x35\x86\x4B\xD0\xE2\x3F\xB6\xD8\xF8\x0E\x00\xEE\x5D\xE3\xF7\x8D\x58\xFF\xCF\x8B\x37\xE9\x63\x5F\x6E\xF7\x09\x71\x36\xC2\x12\x5D\x57\xF2\xC8\xB4\xCD\xF3\xEE\x02\xDF\x11\xDC\x6A\xB9\x57\x84\x1D\x59\x4D\x8C\xCE\xC8\x0E\x23\xC2\xB7\x26\x9A\x10\x14\x71\xFE\x93\xB2\x8A\xB8\x80\xF0\x0E\x10\x9E\xD3\xA8\x50\x0C\x37\x82\x2F\xEA\xE0\x8A\x9D\xE1\x2C\x39\xFF\xB5\xB4\x73\x00\xE4\xF7\x48\xA6\x73\xAC\xBF\xB2\xDE\x77\x04\x87\xB4\xA3\xCD\x9B\x35\x24\x37\xFA\x90\x93\x13\x81\x42\xC6\x98\x26\x75\x37\x66\x41\x10\xAC\xBB\xF5\x94\xE3\xC2\x31\x2B\xAD\xE7\x23\x56\xCC\x35\x25\x92\xB3\x50", + ["CN=FIRMAPROFESIONAL CA ROOT-A WEB,organizationIdentifier=VATES-A62634068,O=Firmaprofesional SA,C=ES"] = "\x30\x82\x02\x7A\x30\x82\x02\x00\xA0\x03\x02\x01\x02\x02\x10\x31\x97\x21\xED\xAF\x89\x42\x7F\x35\x41\x87\xA1\x67\x56\x4C\x6D\x30\x0A\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x03\x30\x6E\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x53\x31\x1C\x30\x1A\x06\x03\x55\x04\x0A\x0C\x13\x46\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x20\x53\x41\x31\x18\x30\x16\x06\x03\x55\x04\x61\x0C\x0F\x56\x41\x54\x45\x53\x2D\x41\x36\x32\x36\x33\x34\x30\x36\x38\x31\x27\x30\x25\x06\x03\x55\x04\x03\x0C\x1E\x46\x49\x52\x4D\x41\x50\x52\x4F\x46\x45\x53\x49\x4F\x4E\x41\x4C\x20\x43\x41\x20\x52\x4F\x4F\x54\x2D\x41\x20\x57\x45\x42\x30\x1E\x17\x0D\x32\x32\x30\x34\x30\x36\x30\x39\x30\x31\x33\x36\x5A\x17\x0D\x34\x37\x30\x33\x33\x31\x30\x39\x30\x31\x33\x36\x5A\x30\x6E\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x45\x53\x31\x1C\x30\x1A\x06\x03\x55\x04\x0A\x0C\x13\x46\x69\x72\x6D\x61\x70\x72\x6F\x66\x65\x73\x69\x6F\x6E\x61\x6C\x20\x53\x41\x31\x18\x30\x16\x06\x03\x55\x04\x61\x0C\x0F\x56\x41\x54\x45\x53\x2D\x41\x36\x32\x36\x33\x34\x30\x36\x38\x31\x27\x30\x25\x06\x03\x55\x04\x03\x0C\x1E\x46\x49\x52\x4D\x41\x50\x52\x4F\x46\x45\x53\x49\x4F\x4E\x41\x4C\x20\x43\x41\x20\x52\x4F\x4F\x54\x2D\x41\x20\x57\x45\x42\x30\x76\x30\x10\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01\x06\x05\x2B\x81\x04\x00\x22\x03\x62\x00\x04\x47\x53\xEA\x2C\x11\xA4\x77\xC7\x2A\xEA\xF3\xD6\x5F\x7B\xD3\x04\x91\x5C\xFA\x88\xC6\x22\xB9\x83\x10\x62\x77\x84\x33\x2D\xE9\x03\x88\xD4\xE0\x33\xF7\xED\x77\x2C\x4A\x60\xEA\xE4\x6F\xAD\x6D\xB4\xF8\x4C\x8A\xA4\xE4\x1F\xCA\xEA\x4F\x38\x4A\x2E\x82\x73\x2B\xC7\x66\x9B\x0A\x8C\x40\x9C\x7C\x8A\xF6\xF2\x39\x60\xB2\xDE\xCB\xEC\xB8\xE4\x6F\xEA\x9B\x5D\xB7\x53\x90\x18\x32\x55\xC5\x20\xB7\x94\xA3\x63\x30\x61\x30\x0F\x06\x03\x55\x1D\x13\x01\x01\xFF\x04\x05\x30\x03\x01\x01\xFF\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x93\xE1\x43\x63\x5C\x3C\x9D\xD6\x27\xF3\x52\xEC\x17\xB2\xA9\xAF\x2C\xF7\x76\xF8\x30\x1D\x06\x03\x55\x1D\x0E\x04\x16\x04\x14\x93\xE1\x43\x63\x5C\x3C\x9D\xD6\x27\xF3\x52\xEC\x17\xB2\xA9\xAF\x2C\xF7\x76\xF8\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x01\x06\x30\x0A\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x03\x03\x68\x00\x30\x65\x02\x30\x1D\x7C\xA4\x7B\xC3\x89\x75\x33\xE1\x3B\xA9\x45\xBF\x46\xE9\xE9\xA1\xDD\xC9\x22\x16\xB7\x47\x11\x0B\xD8\x9A\xBA\xF1\xC8\x0B\x70\x50\x53\x02\x91\x70\x85\x59\xA9\x1E\xA4\xE6\xEA\x23\x31\xA0\x00\x02\x31\x00\xFD\xE2\xF8\xB3\xAF\x16\xB9\x1E\x73\xC4\x96\xE3\xC1\x30\x19\xD8\x7E\xE6\xC3\x97\xDE\x1C\x4F\xB8\x89\x2F\x33\xEB\x48\x0F\x19\xF7\x87\x46\x5D\x26\x90\xA5\x85\xC5\xB9\x7A\x94\x3E\x87\xA8\xBD\x00", }; From a4b746e5e843ab8792cbd3070c0ae7b637270193 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Wed, 24 Jul 2024 13:25:52 -0700 Subject: [PATCH 17/41] Merge remote-tracking branch 'origin/topic/timw/smb2-ioctl-errors' * origin/topic/timw/smb2-ioctl-errors: Update 7.0 NEWS with blurb about multi-PDU parsing causing increased load [nomail] [skip ci] Fix handling of zero-length SMB2 error responses (cherry picked from commit bd208f4c54f66074315479071c810d792e69f96b) --- NEWS | 3 ++- src/analyzer/protocol/smb/smb2-protocol.pac | 2 +- .../out | 13 +++++++++++++ .../Traces/smb/smb2-zero-byte-error-ioctl.pcap | Bin 0 -> 29460 bytes .../smb/smb2-zero-byte-error-ioctl.test | 16 ++++++++++++++++ 5 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.smb.smb2-zero-byte-error-ioctl/out create mode 100644 testing/btest/Traces/smb/smb2-zero-byte-error-ioctl.pcap create mode 100644 testing/btest/scripts/base/protocols/smb/smb2-zero-byte-error-ioctl.test diff --git a/NEWS b/NEWS index 2f7422c195..13c25977f9 100644 --- a/NEWS +++ b/NEWS @@ -85,7 +85,8 @@ New Functionality environment variable configures the addition. - SMB2 packets containing multiple PDUs now correctly parse all of the headers, - instead of just the first one and ignoring the rest. + instead of just the first one and ignoring the rest. This may cause increased + CPU load on SMB2-heavy networks. - The new built-in function ``lookup_connection_analyzer_id()`` retrieves the numeric identifier of an analyzer associated with a connection. This enables diff --git a/src/analyzer/protocol/smb/smb2-protocol.pac b/src/analyzer/protocol/smb/smb2-protocol.pac index b922c62f2b..5e7bf673b1 100644 --- a/src/analyzer/protocol/smb/smb2-protocol.pac +++ b/src/analyzer/protocol/smb/smb2-protocol.pac @@ -413,7 +413,7 @@ type SMB2_error_response(header: SMB2_Header) = record { byte_count : uint32; # This is implemented incorrectly and is disabled for now. #error_data : SMB2_error_data(header, byte_count); - stuff : bytestring &restofdata &transient; + stuff : bytestring &length=byte_count &transient; } &byteorder = littleendian; type SMB2_logoff_request(header: SMB2_Header) = record { diff --git a/testing/btest/Baseline/scripts.base.protocols.smb.smb2-zero-byte-error-ioctl/out b/testing/btest/Baseline/scripts.base.protocols.smb.smb2-zero-byte-error-ioctl/out new file mode 100644 index 0000000000..f803db64f2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.smb.smb2-zero-byte-error-ioctl/out @@ -0,0 +1,13 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +smb2_close_request, [credit_charge=1, status=0, command=6, credits=256, flags=0, message_id=8, process_id=65279, tree_id=3905704575, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00] +smb2_close_response, [credit_charge=1, status=0, command=6, credits=256, flags=1, message_id=8, process_id=65279, tree_id=3905704575, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00], [alloc_size=0, eof=0, times=[modified=0.0, modified_raw=116444736000000000, accessed=0.0, accessed_raw=116444736000000000, created=0.0, created_raw=116444736000000000, changed=0.0, changed_raw=116444736000000000], attrs=[read_only=F, hidden=F, system=F, directory=F, archive=F, normal=F, temporary=F, sparse_file=F, reparse_point=F, compressed=F, offline=F, not_content_indexed=F, encrypted=F, integrity_stream=F, no_scrub_data=F]] +smb2_close_request, [credit_charge=1, status=0, command=6, credits=256, flags=0, message_id=21, process_id=65279, tree_id=900627714, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00] +smb2_close_response, [credit_charge=1, status=0, command=6, credits=256, flags=1, message_id=21, process_id=65279, tree_id=900627714, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00], [alloc_size=0, eof=0, times=[modified=0.0, modified_raw=116444736000000000, accessed=0.0, accessed_raw=116444736000000000, created=0.0, created_raw=116444736000000000, changed=0.0, changed_raw=116444736000000000], attrs=[read_only=F, hidden=F, system=F, directory=F, archive=F, normal=F, temporary=F, sparse_file=F, reparse_point=F, compressed=F, offline=F, not_content_indexed=F, encrypted=F, integrity_stream=F, no_scrub_data=F]] +smb2_close_request, [credit_charge=1, status=0, command=6, credits=256, flags=4, message_id=25, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00] +smb2_close_response, [credit_charge=1, status=0, command=6, credits=768, flags=5, message_id=25, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00], [alloc_size=0, eof=0, times=[modified=0.0, modified_raw=116444736000000000, accessed=0.0, accessed_raw=116444736000000000, created=0.0, created_raw=116444736000000000, changed=0.0, changed_raw=116444736000000000], attrs=[read_only=F, hidden=F, system=F, directory=F, archive=F, normal=F, temporary=F, sparse_file=F, reparse_point=F, compressed=F, offline=F, not_content_indexed=F, encrypted=F, integrity_stream=F, no_scrub_data=F]] +smb2_close_request, [credit_charge=1, status=0, command=6, credits=256, flags=4, message_id=28, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00] +smb2_close_response, [credit_charge=1, status=0, command=6, credits=768, flags=5, message_id=28, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00], [alloc_size=0, eof=0, times=[modified=0.0, modified_raw=116444736000000000, accessed=0.0, accessed_raw=116444736000000000, created=0.0, created_raw=116444736000000000, changed=0.0, changed_raw=116444736000000000], attrs=[read_only=F, hidden=F, system=F, directory=F, archive=F, normal=F, temporary=F, sparse_file=F, reparse_point=F, compressed=F, offline=F, not_content_indexed=F, encrypted=F, integrity_stream=F, no_scrub_data=F]] +smb2_close_request, [credit_charge=1, status=0, command=6, credits=256, flags=4, message_id=31, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00] +smb2_close_response, [credit_charge=1, status=0, command=6, credits=768, flags=5, message_id=31, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00], [alloc_size=0, eof=0, times=[modified=0.0, modified_raw=116444736000000000, accessed=0.0, accessed_raw=116444736000000000, created=0.0, created_raw=116444736000000000, changed=0.0, changed_raw=116444736000000000], attrs=[read_only=F, hidden=F, system=F, directory=F, archive=F, normal=F, temporary=F, sparse_file=F, reparse_point=F, compressed=F, offline=F, not_content_indexed=F, encrypted=F, integrity_stream=F, no_scrub_data=F]] +smb2_close_request, [credit_charge=1, status=0, command=6, credits=256, flags=4, message_id=34, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00] +smb2_close_response, [credit_charge=1, status=0, command=6, credits=768, flags=5, message_id=34, process_id=65279, tree_id=1248644238, session_id=66137014, signature=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00], [alloc_size=0, eof=0, times=[modified=0.0, modified_raw=116444736000000000, accessed=0.0, accessed_raw=116444736000000000, created=0.0, created_raw=116444736000000000, changed=0.0, changed_raw=116444736000000000], attrs=[read_only=F, hidden=F, system=F, directory=F, archive=F, normal=F, temporary=F, sparse_file=F, reparse_point=F, compressed=F, offline=F, not_content_indexed=F, encrypted=F, integrity_stream=F, no_scrub_data=F]] diff --git a/testing/btest/Traces/smb/smb2-zero-byte-error-ioctl.pcap b/testing/btest/Traces/smb/smb2-zero-byte-error-ioctl.pcap new file mode 100644 index 0000000000000000000000000000000000000000..3ffab0867ad80a375de55e06141ffe9dc358dc1e GIT binary patch literal 29460 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 >out +# @TEST-EXEC: ! test -f analyzer.log +# @TEST-EXEC: btest-diff out + +@load base/protocols/smb + +event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) +{ + print "smb2_close_request", hdr; +} + +event smb2_close_response(c: connection, hdr: SMB2::Header, response: SMB2::CloseResponse) +{ + print "smb2_close_response", hdr, response; +} From b46aeefbabd514e8863e908170e99930a5ebd01d Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Wed, 24 Jul 2024 16:48:06 -0700 Subject: [PATCH 18/41] Add contributors to 7.0.0 NEWS entry [skip ci] --- NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 13c25977f9..57a02b61a0 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,13 @@ release. For an exhaustive list of changes, see the ``CHANGES`` file Zeek 7.0.0 ========== +We would like to thank the following people for their contributions to this +release: Christopher Knill (cknill), Jan Grashöfer (J-Gras), Martin van +Hensbergen (mvhensbergen), Matti Bispham (mbispham), Mike Dopheide +(dopheide-esnet), Oleksandr Pastushkov (opastushkov), Peter Cullen (pbcullen), +Steve Smoot (stevesmoot), Tanner Kvarfordt (Kardbord), Victor Dvornikov +(lydiym). + Breaking Changes ---------------- From 3a44bda957280e6c3eda0557a32adabc2b4fd60f Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Tue, 23 Jul 2024 16:58:52 -0700 Subject: [PATCH 19/41] Bump zeek-testing-cluster to reflect deprecation of prometheus.zeek (cherry picked from commit 146cf99ff62d729705c155b44199a674911ade09) --- testing/external/commit-hash.zeek-testing-cluster | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/external/commit-hash.zeek-testing-cluster b/testing/external/commit-hash.zeek-testing-cluster index 5d84d38106..b8df5d15d0 100644 --- a/testing/external/commit-hash.zeek-testing-cluster +++ b/testing/external/commit-hash.zeek-testing-cluster @@ -1 +1 @@ -ded009fb7a0cdee6f36d5b40a6394788b760fa06 +9f875d86000602661fbfc9bb471d1c598917ebc9 From 5974613cae0d097fbfae9622b346a6cc6441405d Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 25 Jul 2024 10:52:29 -0700 Subject: [PATCH 20/41] Generate docs for 7.0.0-rc3 --- doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc b/doc index 316ad305b6..2329974428 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 316ad305b69456fcd424ffaf99d1326822ad9d60 +Subproject commit 2329974428148b8bf2122745bb7b58494b394efa From b9e4669632b8bf0a1351d2dd4ab5942eb2d849b4 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 25 Jul 2024 11:06:51 -0700 Subject: [PATCH 21/41] Updating CHANGES and VERSION. --- CHANGES | 24 ++++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 859b7f0d30..bbc39852e1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,27 @@ +7.0.0-rc3 | 2024-07-25 10:52:29 -0700 + + * Generate docs for 7.0.0-rc3 (Tim Wojtulewicz) + + * Bump zeek-testing-cluster to reflect deprecation of prometheus.zeek (Christian Kreibich, Corelight) + + (cherry picked from commit 146cf99ff62d729705c155b44199a674911ade09) + + * Update 7.0 NEWS with blurb about multi-PDU parsing causing increased load [nomail] [skip ci] (Tim Wojtulewicz, Corelight) + + (cherry picked from commit bd208f4c54f66074315479071c810d792e69f96b) + + * Fix handling of zero-length SMB2 error responses (Tim Wojtulewicz, Corelight) + + (cherry picked from commit bd208f4c54f66074315479071c810d792e69f96b) + + * Update Mozilla CA list and CT list (Johanna Amann, Corelight) + + (cherry picked from commit cb88f6316c7341da7a2af397932a145be3a0cc29) + + * Bump auxil/spicy to latest development snapshot (Benjamin Bannier, Corelight) + + (cherry picked from commit da7c3d91385195a7a4ba957e46743bc52a9d4ecb) + 7.0.0-rc2.7 | 2024-07-24 17:00:51 -0700 * Add contributors to 7.0.0 NEWS entry (Christian Kreibich, Corelight) diff --git a/VERSION b/VERSION index 625920dc5e..0761c39a86 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-rc2.7 +7.0.0-rc3 From b76096a9eef6aa039e30b8dbef8df1f4870e2408 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 26 Jul 2024 10:09:48 -0700 Subject: [PATCH 22/41] Merge remote-tracking branch 'origin/topic/bbannier/bump-spicy' * origin/topic/bbannier/bump-spicy: Bump auxil/spicy to latest development snapshot (cherry picked from commit 4c0c7581c835b4dcd5339a4b34c2b82fcfc40dc3) --- CHANGES | 8 ++++++++ VERSION | 2 +- auxil/spicy | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index bbc39852e1..4f14dba6d2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +7.0.0-rc4 | 2024-07-26 10:12:34 -0700 + + * Bump auxil/spicy to latest development snapshot (Benjamin Bannier, Corelight) + + This in particular pulls in a fix for zeek/spicy#1808. + + (cherry picked from commit 4c0c7581c835b4dcd5339a4b34c2b82fcfc40dc3) + 7.0.0-rc3 | 2024-07-25 10:52:29 -0700 * Generate docs for 7.0.0-rc3 (Tim Wojtulewicz) diff --git a/VERSION b/VERSION index 0761c39a86..12751eb9a9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-rc3 +7.0.0-rc4 diff --git a/auxil/spicy b/auxil/spicy index 04c5ed3c27..4c5c26bf34 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit 04c5ed3c27879459de69d12efc417c6915f304b9 +Subproject commit 4c5c26bf34c2cf2cedf56270e84f1271fcf94465 From 72ff343f175f35e9373d1fb412d534453b8459cf Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Mon, 29 Jul 2024 11:40:28 -0700 Subject: [PATCH 23/41] Update docs submodule [nomail] [skip ci] --- doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc b/doc index 2329974428..3cd0dd2315 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 2329974428148b8bf2122745bb7b58494b394efa +Subproject commit 3cd0dd2315663b0dcb38ac30b874492fd5071e6b From f8fbeca504f6b32b67ee9d02320eb22e11a3c31b Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Wed, 31 Jul 2024 14:57:53 +0200 Subject: [PATCH 24/41] Bump Spicy to latest release --- auxil/spicy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxil/spicy b/auxil/spicy index 4c5c26bf34..7ddf6ce441 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit 4c5c26bf34c2cf2cedf56270e84f1271fcf94465 +Subproject commit 7ddf6ce441d63aa5894dd11d9a5047ddc761de9a From 55d36fc2cdbada347478f771231cca6bcdf4028a Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Wed, 31 Jul 2024 15:06:47 +0200 Subject: [PATCH 25/41] Allowlist a name for typos check --- .typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.typos.toml b/.typos.toml index dfa60bd504..d162b1d842 100644 --- a/.typos.toml +++ b/.typos.toml @@ -30,6 +30,7 @@ extend-ignore-re = [ "\"BaR\"", "\"xFoObar\"", "\"FoO\"", + "Steve Smoot", ] extend-ignore-identifiers-re = [ From d1f6e91988c0eacf2c7a75ef7817f6c128be8445 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 1 Aug 2024 10:42:25 -0700 Subject: [PATCH 26/41] Updating CHANGES and VERSION. --- CHANGES | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 34feb74a85..bcfa60229b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +7.0.0 | 2024-07-31 09:37:03 -0700 + + * Release 7.0.0. + 7.0.0-rc4.4 | 2024-07-31 09:36:51 -0700 * Allowlist a name for typos check (Benjamin Bannier, Corelight) diff --git a/VERSION b/VERSION index a0664e5d3d..66ce77b7ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-rc4.4 +7.0.0 From f6b88645847235b9cf7fa92edd3a75df99bb5d29 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Mon, 12 Aug 2024 17:54:52 -0700 Subject: [PATCH 27/41] Update docs submodule [nomail] [skip ci] --- doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc b/doc index 3cd0dd2315..4e2413e2fb 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 3cd0dd2315663b0dcb38ac30b874492fd5071e6b +Subproject commit 4e2413e2fb2f98298430b3e2cb384fc5f18cbde4 From 056bbe04ea48d311201e62a5578d1d18682bb5e3 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Thu, 1 Aug 2024 11:14:46 +0200 Subject: [PATCH 28/41] Merge remote-tracking branch 'origin/topic/timw/use-more-memory-for-freebsd-builds' * origin/topic/timw/use-more-memory-for-freebsd-builds: CI: Use 16GB of memory for FreeBSD builds (cherry picked from commit 9d9cc51e9dd93668cd332aa1aef283c9dc23a677) --- .cirrus.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index b96146f230..88ffb16c76 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -35,8 +35,7 @@ macos_environment: &MACOS_ENVIRONMENT freebsd_resources_template: &FREEBSD_RESOURCES_TEMPLATE cpu: 8 - # Not allowed to request less than 8GB for an 8 CPU FreeBSD VM. - memory: 8GB + memory: *MEMORY # For greediness, see https://medium.com/cirruslabs/introducing-greedy-container-instances-29aad06dc2b4 greedy: true From dd4597865a0b6c640fcccd1482de70b6af8df37f Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 2 Aug 2024 15:49:40 -0700 Subject: [PATCH 29/41] Merge remote-tracking branch 'origin/topic/timw/telemetry-threading' * origin/topic/timw/telemetry-threading: Process metric callbacks from the main-loop thread (cherry picked from commit 3c3853dc7da9aad94a9b2d5a143cc7bd9476ea7a) --- auxil/prometheus-cpp | 2 +- scripts/base/init-bare.zeek | 7 ++ src/telemetry/CMakeLists.txt | 1 + src/telemetry/Manager.cc | 79 ++++++++++++++++++- src/telemetry/Manager.h | 40 ++++++++-- src/telemetry/consts.bif | 2 + src/zeek-setup.cc | 2 + .../canonified_loaded_scripts.log | 1 + .../canonified_loaded_scripts.log | 1 + testing/btest/Baseline/plugins.hooks/output | 6 ++ 10 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 src/telemetry/consts.bif diff --git a/auxil/prometheus-cpp b/auxil/prometheus-cpp index 2fec7205d1..4649065e2a 160000 --- a/auxil/prometheus-cpp +++ b/auxil/prometheus-cpp @@ -1 +1 @@ -Subproject commit 2fec7205d1a9cb4829b86c943d599696d53de85c +Subproject commit 4649065e2a1dd21c81e41cd6007dce5486b77fc0 diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek index 30b49def26..85a1dc0f20 100644 --- a/scripts/base/init-bare.zeek +++ b/scripts/base/init-bare.zeek @@ -5883,6 +5883,13 @@ export { type MetricVector : vector of Metric; type HistogramMetricVector : vector of HistogramMetric; + + ## Maximum amount of time for CivetWeb HTTP threads to + ## wait for metric callbacks to complete on the IO loop. + const callback_timeout: interval = 5sec &redef; + + ## Number of CivetWeb threads to use. + const civetweb_threads: count = 2 &redef; } module GLOBAL; diff --git a/src/telemetry/CMakeLists.txt b/src/telemetry/CMakeLists.txt index d61cbdb671..a760dcd13c 100644 --- a/src/telemetry/CMakeLists.txt +++ b/src/telemetry/CMakeLists.txt @@ -9,6 +9,7 @@ zeek_add_subdir_library( ProcessStats.cc Utils.cc BIFS + consts.bif telemetry.bif) # We don't need to include the civetweb headers across the whole project, only diff --git a/src/telemetry/Manager.cc b/src/telemetry/Manager.cc index 04c47ba3ef..6ae4e06ec6 100644 --- a/src/telemetry/Manager.cc +++ b/src/telemetry/Manager.cc @@ -6,6 +6,7 @@ // CivetServer is from the civetweb submodule in prometheus-cpp #include +#include #include #include #include @@ -16,19 +17,32 @@ #include "zeek/3rdparty/doctest.h" #include "zeek/ID.h" +#include "zeek/RunState.h" #include "zeek/ZeekString.h" #include "zeek/broker/Manager.h" +#include "zeek/iosource/Manager.h" #include "zeek/telemetry/ProcessStats.h" #include "zeek/telemetry/Timer.h" +#include "zeek/telemetry/consts.bif.h" #include "zeek/telemetry/telemetry.bif.h" #include "zeek/threading/formatters/detail/json.h" namespace zeek::telemetry { -Manager::Manager() { prometheus_registry = std::make_shared(); } +/** + * Prometheus Collectable interface used to insert Zeek callback processing + * before the Prometheus registry's collection of metric data. + */ +class ZeekCollectable : public prometheus::Collectable { +public: + std::vector Collect() const override { + telemetry_mgr->WaitForPrometheusCallbacks(); + return {}; + } +}; + +Manager::Manager() : IOSource(true) { prometheus_registry = std::make_shared(); } -// This can't be defined as =default because of the use of unique_ptr with a forward-declared type -// in Manager.h Manager::~Manager() {} void Manager::InitPostScript() { @@ -75,7 +89,9 @@ void Manager::InitPostScript() { if ( ! getenv("ZEEKCTL_CHECK_CONFIG") ) { try { - prometheus_exposer = std::make_unique(prometheus_url, 2, callbacks); + prometheus_exposer = + std::make_unique(prometheus_url, BifConst::Telemetry::civetweb_threads, + callbacks); // CivetWeb stores a copy of the callbacks, so we're safe to delete the pointer here delete callbacks; @@ -84,6 +100,13 @@ void Manager::InitPostScript() { prometheus_url.c_str()); } + // This has to be inserted before the registry below. The exposer + // processes the collectors in order of insertion. We want to make + // sure that the callbacks get called and the values in the metrics + // are updated before prometheus-cpp scrapes them. + zeek_collectable = std::make_shared(); + prometheus_exposer->RegisterCollectable(zeek_collectable); + prometheus_exposer->RegisterCollectable(prometheus_registry); } } @@ -130,6 +153,21 @@ void Manager::InitPostScript() { return metric; }); #endif + + iosource_mgr->RegisterFd(collector_flare.FD(), this); +} + +void Manager::Terminate() { + // Notify the collector condition so that it doesn't hang waiting for + // a collector request to complete. + collector_cv.notify_all(); + + // Shut down the exposer first of all so we stop getting requests for + // data. This keeps us from getting a request on another thread while + // we're shutting down. + prometheus_exposer.reset(); + + iosource_mgr->UnregisterFd(collector_flare.FD(), this); } // -- collect metric stuff ----------------------------------------------------- @@ -545,6 +583,39 @@ HistogramPtr Manager::HistogramInstance(std::string_view prefix, std::string_vie return HistogramInstance(prefix, name, lbls, bounds_span, helptext, unit); } +void Manager::ProcessFd(int fd, int flags) { + std::unique_lock lk(collector_cv_mtx); + + collector_flare.Extinguish(); + + prometheus_registry->UpdateViaCallbacks(); + collector_response_idx = collector_request_idx; + + lk.unlock(); + collector_cv.notify_all(); +} + +void Manager::WaitForPrometheusCallbacks() { + std::unique_lock lk(collector_cv_mtx); + + ++collector_request_idx; + uint64_t expected_idx = collector_request_idx; + collector_flare.Fire(); + + // It should *not* take 5 seconds to go through all of the callbacks, but + // set this to have a timeout anyways just to avoid a deadlock. + bool res = collector_cv.wait_for(lk, + std::chrono::microseconds( + static_cast(BifConst::Telemetry::callback_timeout * 1000000)), + [expected_idx]() { + return telemetry_mgr->collector_response_idx >= expected_idx || + zeek::run_state::terminating; + }); + + if ( ! res ) + fprintf(stderr, "Timeout waiting for prometheus callbacks\n"); +} + } // namespace zeek::telemetry // -- unit tests --------------------------------------------------------------- diff --git a/src/telemetry/Manager.h b/src/telemetry/Manager.h index c4c2537f1a..d967fe43c0 100644 --- a/src/telemetry/Manager.h +++ b/src/telemetry/Manager.h @@ -9,8 +9,10 @@ #include #include +#include "zeek/Flare.h" #include "zeek/IntrusivePtr.h" #include "zeek/Span.h" +#include "zeek/iosource/IOSource.h" #include "zeek/telemetry/Counter.h" #include "zeek/telemetry/Gauge.h" #include "zeek/telemetry/Histogram.h" @@ -29,15 +31,16 @@ class Registry; namespace zeek::telemetry { +class ZeekCollectable; + /** * Manages a collection of metric families. */ -class Manager final { +class Manager final : public iosource::IOSource { public: Manager(); Manager(const Manager&) = delete; - Manager& operator=(const Manager&) = delete; ~Manager(); @@ -50,6 +53,8 @@ public: */ void InitPostScript(); + void Terminate(); + /** * @return A VectorVal containing all counter and gauge metrics and their values matching prefix and name. * @param prefix The prefix pattern to use for filtering. Supports globbing. @@ -88,8 +93,8 @@ public: * @param labels Values for all label dimensions of the metric. * @param helptext Short explanation of the metric. * @param unit Unit of measurement. - * @param callback Passing a callback method will enable asynchronous mode. The callback method will be called by - * the metrics subsystem whenever data is requested. + * @param callback Passing a callback method will enable asynchronous mode. The callback method will be called + * by the metrics subsystem whenever data is requested. */ CounterPtr CounterInstance(std::string_view prefix, std::string_view name, Span labels, std::string_view helptext, std::string_view unit = "", @@ -124,8 +129,8 @@ public: * @param labels Values for all label dimensions of the metric. * @param helptext Short explanation of the metric. * @param unit Unit of measurement. - * @param callback Passing a callback method will enable asynchronous mode. The callback method will be called by - * the metrics subsystem whenever data is requested. + * @param callback Passing a callback method will enable asynchronous mode. The callback method will be called + * by the metrics subsystem whenever data is requested. */ GaugePtr GaugeInstance(std::string_view prefix, std::string_view name, Span labels, std::string_view helptext, std::string_view unit = "", @@ -212,6 +217,12 @@ public: */ std::shared_ptr GetRegistry() const { return prometheus_registry; } + // IOSource interface + double GetNextTimeout() override { return -1.0; } + void Process() override {} + const char* Tag() override { return "Telemetry::Manager"; } + void ProcessFd(int fd, int flags) override; + protected: template static auto WithLabelNames(Span xs, F continuation) { @@ -231,6 +242,15 @@ protected: } } + friend class ZeekCollectable; + + /** + * Fires the flare for prometheus-cpp callback handling and waits for it to complete. + * This can be called from other threads to ensure the callback handling happens on + * the main thread. + */ + void WaitForPrometheusCallbacks(); + private: RecordValPtr GetMetricOptsRecord(const prometheus::MetricFamily& metric_family); void BuildClusterJson(); @@ -250,6 +270,14 @@ private: std::unique_ptr prometheus_exposer; std::string cluster_json; + + std::shared_ptr zeek_collectable; + zeek::detail::Flare collector_flare; + std::condition_variable collector_cv; + std::mutex collector_cv_mtx; + // Only modified under collector_cv_mtx! + uint64_t collector_request_idx = 0; + uint64_t collector_response_idx = 0; }; } // namespace zeek::telemetry diff --git a/src/telemetry/consts.bif b/src/telemetry/consts.bif new file mode 100644 index 0000000000..76c256dfa1 --- /dev/null +++ b/src/telemetry/consts.bif @@ -0,0 +1,2 @@ +const Telemetry::callback_timeout: interval; +const Telemetry::civetweb_threads: count; diff --git a/src/zeek-setup.cc b/src/zeek-setup.cc index b05af74f20..3f5549b78a 100644 --- a/src/zeek-setup.cc +++ b/src/zeek-setup.cc @@ -376,6 +376,7 @@ static void terminate_zeek() { input_mgr->Terminate(); thread_mgr->Terminate(); broker_mgr->Terminate(); + telemetry_mgr->Terminate(); event_mgr.Drain(); @@ -716,6 +717,7 @@ SetupResult setup(int argc, char** argv, Options* zopts) { // when that variable is defined. auto early_shutdown = [] { broker_mgr->Terminate(); + telemetry_mgr->Terminate(); delete iosource_mgr; delete telemetry_mgr; }; diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index aee483157a..5466f0ea13 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -146,6 +146,7 @@ scripts/base/init-frameworks-and-bifs.zeek scripts/base/frameworks/files/magic/__load__.zeek scripts/base/frameworks/telemetry/options.zeek build/scripts/base/bif/__load__.zeek + build/scripts/base/bif/consts.bif.zeek build/scripts/base/bif/telemetry.bif.zeek build/scripts/base/bif/zeekygen.bif.zeek build/scripts/base/bif/pcap.bif.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 40a1c5b84c..07dc32da6d 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -146,6 +146,7 @@ scripts/base/init-frameworks-and-bifs.zeek scripts/base/frameworks/files/magic/__load__.zeek scripts/base/frameworks/telemetry/options.zeek build/scripts/base/bif/__load__.zeek + build/scripts/base/bif/consts.bif.zeek build/scripts/base/bif/telemetry.bif.zeek build/scripts/base/bif/zeekygen.bif.zeek build/scripts/base/bif/pcap.bif.zeek diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index c3b551dc84..2514d98015 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -464,6 +464,7 @@ 0.000000 MetaHookPost LoadFile(0, ./comm.bif.zeek, <...>/comm.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./communityid.bif.zeek, <...>/communityid.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./const.bif.zeek, <...>/const.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, ./consts.bif.zeek, <...>/consts.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./contents, <...>/contents.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./control, <...>/control.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./data.bif.zeek, <...>/data.bif.zeek) -> -1 @@ -758,6 +759,7 @@ 0.000000 MetaHookPost LoadFileExtended(0, ./comm.bif.zeek, <...>/comm.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./communityid.bif.zeek, <...>/communityid.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./const.bif.zeek, <...>/const.bif.zeek) -> (-1, ) +0.000000 MetaHookPost LoadFileExtended(0, ./consts.bif.zeek, <...>/consts.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./contents, <...>/contents.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./control, <...>/control.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./data.bif.zeek, <...>/data.bif.zeek) -> (-1, ) @@ -1384,6 +1386,7 @@ 0.000000 MetaHookPre LoadFile(0, ./comm.bif.zeek, <...>/comm.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./communityid.bif.zeek, <...>/communityid.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./const.bif.zeek, <...>/const.bif.zeek) +0.000000 MetaHookPre LoadFile(0, ./consts.bif.zeek, <...>/consts.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./contents, <...>/contents.zeek) 0.000000 MetaHookPre LoadFile(0, ./control, <...>/control.zeek) 0.000000 MetaHookPre LoadFile(0, ./data.bif.zeek, <...>/data.bif.zeek) @@ -1678,6 +1681,7 @@ 0.000000 MetaHookPre LoadFileExtended(0, ./comm.bif.zeek, <...>/comm.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./communityid.bif.zeek, <...>/communityid.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./const.bif.zeek, <...>/const.bif.zeek) +0.000000 MetaHookPre LoadFileExtended(0, ./consts.bif.zeek, <...>/consts.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./contents, <...>/contents.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./control, <...>/control.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./data.bif.zeek, <...>/data.bif.zeek) @@ -2305,6 +2309,7 @@ 0.000000 | HookLoadFile ./comm.bif.zeek <...>/comm.bif.zeek 0.000000 | HookLoadFile ./communityid.bif.zeek <...>/communityid.bif.zeek 0.000000 | HookLoadFile ./const.bif.zeek <...>/const.bif.zeek +0.000000 | HookLoadFile ./consts.bif.zeek <...>/consts.bif.zeek 0.000000 | HookLoadFile ./contents <...>/contents.zeek 0.000000 | HookLoadFile ./control <...>/control.zeek 0.000000 | HookLoadFile ./data.bif.zeek <...>/data.bif.zeek @@ -2599,6 +2604,7 @@ 0.000000 | HookLoadFileExtended ./comm.bif.zeek <...>/comm.bif.zeek 0.000000 | HookLoadFileExtended ./communityid.bif.zeek <...>/communityid.bif.zeek 0.000000 | HookLoadFileExtended ./const.bif.zeek <...>/const.bif.zeek +0.000000 | HookLoadFileExtended ./consts.bif.zeek <...>/consts.bif.zeek 0.000000 | HookLoadFileExtended ./contents <...>/contents.zeek 0.000000 | HookLoadFileExtended ./control <...>/control.zeek 0.000000 | HookLoadFileExtended ./data.bif.zeek <...>/data.bif.zeek From 8a92b150a581bfd58261bd489045ac8f6cf5089f Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Fri, 23 Aug 2024 09:40:53 +0200 Subject: [PATCH 30/41] Merge remote-tracking branch 'origin/topic/awelzel/tcp-reassembler-undelivered-data-match-bool-bool-bool-confusion' * origin/topic/awelzel/tcp-reassembler-undelivered-data-match-bool-bool-bool-confusion: TCP_Reassembler: Fix IsOrig() position in Match() call (cherry picked from commit 4a4cbf25765f387f0aa20277afd133918292b9c4) --- src/analyzer/protocol/tcp/TCP_Reassembler.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/analyzer/protocol/tcp/TCP_Reassembler.cc b/src/analyzer/protocol/tcp/TCP_Reassembler.cc index e9c2a1f2f6..9a63962db2 100644 --- a/src/analyzer/protocol/tcp/TCP_Reassembler.cc +++ b/src/analyzer/protocol/tcp/TCP_Reassembler.cc @@ -273,7 +273,12 @@ void TCP_Reassembler::MatchUndelivered(uint64_t up_to_seq, bool use_last_upper) if ( b.upper > last_reassem_seq ) break; - tcp_analyzer->Conn()->Match(zeek::detail::Rule::PAYLOAD, b.block, b.Size(), false, false, IsOrig(), false); + // Note: Even though this passes bol=false, at the point where + // this code runs, the matcher is re-initialized resulting in + // undelivered data implicitly being bol-anchored. It's unclear + // if that was intended, but there's hardly a right way here, + // so that seems ok. + tcp_analyzer->Conn()->Match(zeek::detail::Rule::PAYLOAD, b.block, b.Size(), IsOrig(), false, false, false); } } From e7ab18b343e115207af95caaa35bf09333f1b1bf Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Fri, 23 Aug 2024 14:18:35 +0200 Subject: [PATCH 31/41] Merge remote-tracking branch 'origin/topic/awelzel/no-child-analyzer-on-finished-connections' * origin/topic/awelzel/no-child-analyzer-on-finished-connections: Analyzer: Do not add child analyzers when finished (cherry picked from commit 45b33bf5c17d5e8cf6c777a9bd57e4a803dfad19) --- src/Conn.h | 3 +++ src/analyzer/Analyzer.cc | 38 +++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/Conn.h b/src/Conn.h index f6ec77e59a..269f432409 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -201,6 +201,9 @@ public: bool PermitWeird(const char* name, uint64_t threshold, uint64_t rate, double duration); + // Returns true once Done() is called. + bool IsFinished() { return finished; } + private: friend class session::detail::Timer; diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index e8f2b65d28..5db65b44a2 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -113,19 +113,7 @@ void Analyzer::CtorInit(const zeek::Tag& arg_tag, Connection* arg_conn) { Analyzer::~Analyzer() { assert(finished); - - // Make sure any late entries into the analyzer tree are handled (e.g. - // from some Done() implementation). - LOOP_OVER_GIVEN_CHILDREN(i, new_children) { - if ( ! (*i)->finished ) - (*i)->Done(); - } - - // Deletion of new_children done in separate loop in case a Done() - // implementation tries to inspect analyzer tree w/ assumption that - // all analyzers are still valid. - LOOP_OVER_GIVEN_CHILDREN(i, new_children) - delete *i; + assert(new_children.empty()); LOOP_OVER_CHILDREN(i) delete *i; @@ -330,6 +318,30 @@ void Analyzer::ForwardEndOfData(bool orig) { bool Analyzer::AddChildAnalyzer(Analyzer* analyzer, bool init) { auto t = analyzer->GetAnalyzerTag(); + // Prevent attaching child analyzers to analyzer subtrees where + // either the parent has finished or is being removed. Further, + // don't attach analyzers when the connection has finished or is + // currently being finished (executing Done()). + // + // Scenarios in which analyzers have been observed that late in + // analyzer / connection lifetime are: + // + // * A DPD signature match on undelivered TCP data that is flushed + // during Connection::Done(). The PIA analyzer activates a new + // analyzer adding it to the TCP analyzer. + // + // * Analyzers flushing buffered state during Done(), resulting + // in new analyzers being created. + // + // Analyzers added during Done() are problematic as calling Done() + // within the parent's destructor isn't safe, so we prevent these + // situations. + if ( Removing() || IsFinished() || Conn()->IsFinished() ) { + analyzer->Done(); + delete analyzer; + return false; + } + if ( HasChildAnalyzer(t) || IsPreventedChildAnalyzer(t) ) { analyzer->Done(); delete analyzer; From 0fd6672ddeef497dcf04456bf43f97b90ee8a215 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Fri, 30 Aug 2024 18:56:24 +0200 Subject: [PATCH 32/41] Merge branch 'fix-http-password-capture' of https://github.com/p-l-/zeek * 'fix-http-password-capture' of https://github.com/p-l-/zeek: http: fix password capture when enabled (cherry picked from commit c27e18631c5d9c6f04c230bd421c9750a1f02342) --- scripts/base/protocols/http/main.zeek | 4 ++-- .../http.log | 11 +++++++++++ .../Traces/http/basic-auth-with-colon.trace | Bin 0 -> 1840 bytes .../protocols/http/http-basic-auth-colon.zeek | 8 ++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.http.http-basic-auth-colon/http.log create mode 100644 testing/btest/Traces/http/basic-auth-with-colon.trace create mode 100644 testing/btest/scripts/base/protocols/http/http-basic-auth-colon.zeek diff --git a/scripts/base/protocols/http/main.zeek b/scripts/base/protocols/http/main.zeek index 0f65c6b984..e334a83253 100644 --- a/scripts/base/protocols/http/main.zeek +++ b/scripts/base/protocols/http/main.zeek @@ -338,8 +338,8 @@ event http_header(c: connection, is_orig: bool, name: string, value: string) &pr if ( /^[bB][aA][sS][iI][cC] / in value ) { local userpass = decode_base64_conn(c$id, sub(value, /[bB][aA][sS][iI][cC][[:blank:]]+/, "")); - local up = split_string(userpass, /:/); - if ( |up| >= 2 ) + local up = split_string1(userpass, /:/); + if ( |up| == 2 ) { c$http$username = up[0]; if ( c$http$capture_password ) diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-basic-auth-colon/http.log b/testing/btest/Baseline/scripts.base.protocols.http.http-basic-auth-colon/http.log new file mode 100644 index 0000000000..e386f15fb5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-basic-auth-colon/http.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path http +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer version user_agent origin request_body_len response_body_len status_code status_msg info_code info_msg tags username password proxied orig_fuids orig_filenames orig_mime_types resp_fuids resp_filenames resp_mime_types +#types time string addr port addr port count string string string string string string string count count count string count string set[enum] string string set[string] vector[string] vector[string] vector[string] vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.24.133.205 43090 172.24.133.205 8000 1 GET 172.24.133.205:8000 / - 1.0 python-requests/2.31.0 - 0 643 200 OK - - (empty) test 1:34 - - - - FM4Ls72L4REzbA61lg - text/html +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/http/basic-auth-with-colon.trace b/testing/btest/Traces/http/basic-auth-with-colon.trace new file mode 100644 index 0000000000000000000000000000000000000000..c1b03b6ecbad02a99d58e70d607337d0279a05fd GIT binary patch literal 1840 zcmZ{lO>Epm6vroSC}hP-El3dH(7^|Us;tNR(WG&lRnmBsLb6GeZ27twdv@2vv5h^O zbfZ0l11EYxLgiX+Edo&?RTXDcI8;q8g(6X@2M`=URga|~THcJ;X}#^PG&|#+H$VU9 zKkv<6|MB~;Bs7eYPq&NEpYV|TZMVMk(g@OF%v%LI}8#@qSTBQxmI zXTS5c=cMk9A6`UA8t&d0mY&Phf8Nyi??VR;Jj+=>^|27*tY7aWtRpk$SFZ%)-vRID zxfi-uZ~dEQabCh2eR%|xfXy4|DjEL?UEPG$({&Sg7k3Ux=->s=F%)a!9InR(#%);7 z8!&Dg_XNXuDq~ba|J+J5<|{Q!@X1*THRaMPq zPDM1#%{Hh90YRHJeJ>Z%k6Sci5h*CeyaF+^mPG@Wt9X`gJ6=P>jcq3w!#1tECZox` zhL4h?+02~pdDLQ#?`e3Q(jaHL&L$6P0X%fJ&3NjB895fl_WV2Bw&9;%{-_Es%4YcP z$41i*b{6>VKlnD;eeX0bqDyDa?i?EGK659%d(QX-7<=FzZ{XlwXHhT?Ka~LvJ`Z`) zJB2BJ3O(;sTu@cKypYYT(QuQ78eVfY0+)(uRT;-C!ZK1+^6-?+7~qG7tG+je3*-3h zmIvz#MVwc)V?_-}^VOPgh=JcZ)(#+;(bJ4H*@ioXt)>}9lufr-J$L+3+#>ZFtf}Gg zQZcdUk3Nfx`yxReCfkdX?9ACK!Nh{FXf3t9DQ*#YWdvQ8kZ2VoUG7vlQdyF*++-}! z2-(`&QnreUA2vvBRqVY)A{IIpQ*36-<&4h#;2kw>=r$-bF<+a5%yc%VWymq%U=19U zu@yf}%Y&@sMCLG;mJKI_-1NgXcAbbpF5|i%Vxp6HI-`@`D?jw@HW!c|yaeVTAcU_L z*XlZD9aM(2J}oN^hY`6fI-QthoxtpqAx^{dLmJ1$;{m~z+lm;}sZ9gdZz~(%(Gx!n zSXysc>q=mmfn44n4hRiQYu#*65T1+%1-h+<=MEEP5CcSeJNmCZL#TSsqsr&YUD1`?}8b2z9$z3Rgd(toIH0Gu7cORp(ByNkZ z6GmJLle?l64ogV7w$ISvwh-m?*QDU7uU-JKse#ZY7z(KtL literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/http/http-basic-auth-colon.zeek b/testing/btest/scripts/base/protocols/http/http-basic-auth-colon.zeek new file mode 100644 index 0000000000..6cef93eba7 --- /dev/null +++ b/testing/btest/scripts/base/protocols/http/http-basic-auth-colon.zeek @@ -0,0 +1,8 @@ +# Authorization: Basic password has a colon in its value +# +# @TEST-EXEC: zeek -b -r $TRACES/http/basic-auth-with-colon.trace %INPUT +# @TEST-EXEC: btest-diff http.log + +@load base/protocols/http + +redef HTTP::default_capture_password = T; From cfe47f40a4b01a75f38a4578600c4e8ce3eb3cb9 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Wed, 17 Jul 2024 16:45:13 +0200 Subject: [PATCH 33/41] Merge remote-tracking branch 'origin/topic/awelzel/spicy-ldap-krb-wrap-tokens' * origin/topic/awelzel/spicy-ldap-krb-wrap-tokens: ldap: Remove MessageWrapper with magic 0x30 searching ldap: Harden parsing a bit ldap: Handle integrity-only KRB wrap tokens (cherry picked from commit 2ea3a651bd83b0dfa15924417e4667241531b57b) --- src/analyzer/protocol/ldap/ldap.spicy | 313 ++++++++++++------ .../scripts.base.protocols.ldap.add/conn.log | 11 + .../scripts.base.protocols.ldap.add/ldap.log | 14 + .../conn.log | 11 + .../ldap.log | 12 + .../ldap_search.log | 14 + .../conn.log | 13 + .../ldap.log | 15 + .../ldap_search.log | 27 ++ testing/btest/Traces/ldap/ldap-add.pcap | Bin 0 -> 2012 bytes .../ldap/missing_krbtgt_ldap_request.pcapng | Bin 0 -> 101144 bytes .../Traces/ldap/missing_ldap_logs.pcapng | Bin 0 -> 443684 bytes .../scripts/base/protocols/ldap/add.zeek | 11 + .../protocols/ldap/sasl-signed-clear-2.zeek | 11 + .../protocols/ldap/sasl-signed-clear.zeek | 11 + 15 files changed, 357 insertions(+), 106 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log create mode 100644 testing/btest/Traces/ldap/ldap-add.pcap create mode 100644 testing/btest/Traces/ldap/missing_krbtgt_ldap_request.pcapng create mode 100644 testing/btest/Traces/ldap/missing_ldap_logs.pcapng create mode 100644 testing/btest/scripts/base/protocols/ldap/add.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek diff --git a/src/analyzer/protocol/ldap/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy index 8d74b85237..2d4f821d78 100644 --- a/src/analyzer/protocol/ldap/ldap.spicy +++ b/src/analyzer/protocol/ldap/ldap.spicy @@ -126,125 +126,126 @@ public type Result = unit { # https://tools.ietf.org/html/rfc4511#section-4.1.10 }; +# 1.2.840.48018.1.2.2 (MS KRB5 - Microsoft Kerberos 5) +const GSSAPI_MECH_MS_KRB5 = "1.2.840.48018.1.2.2"; + +# Supported SASL stripping modes. +type SaslStripping = enum { + MS_KRB5 = 1, # Payload starts with a 4 byte length followed by a wrap token that may or may not be sealed. +}; + +type Ctx = struct { + saslStripping: SaslStripping; # Which mode of SASL stripping to use. +}; + #----------------------------------------------------------------------------- public type Messages = unit { - : MessageWrapper[]; + %context = Ctx; + : SASLStrip(self.context())[]; }; #----------------------------------------------------------------------------- -type SASLLayer = unit { - # For the time being (before we support parsing the SASL layer) this unit - # is used by MessageWrapper below to strip it (SASL) so that the parser - # can attempt to resume parsing afterward. It also sets the success flag - # if '\x30' is found, otherwise backtracks so that we can deal with encrypted - # SASL payloads without raising a parse error. - var success: bool = False; - : bytes &until=b"\x30" { - self.success = True; +public type SASLStrip = unit(ctx: Ctx&) { + switch( ctx.saslStripping ) { + SaslStripping::Undef -> : Message(ctx); + SaslStripping::MS_KRB5 -> : SaslMsKrb5Stripper(ctx); + }; +}; + + +type KrbWrapToken = unit { + # https://datatracker.ietf.org/doc/html/rfc4121#section-4.2.6.2 + + # Number of bytes to expect *after* the payload. + var trailer_ec: uint64; + var header_ec: uint64; + + ctx_flags: bitfield(8) { + send_by_acceptor: 0; + sealed: 1; + acceptor_subkey: 2; + }; + filler: skip b"\xff"; + ec: uint16; # extra count + rrc: uint16 { # right rotation count + # Handle rrc == ec or rrc == 0. + if ( self.rrc == self.ec ) { + self.header_ec = self.ec; + } else if ( self.rrc == 0 ) { + self.trailer_ec = self.ec; + } else { + throw "Unhandled rc %s and ec %s" % (self.ec, self.rrc); + } } - on %error { - self.backtrack(); - } + snd_seq: uint64; + header_e: skip bytes &size=self.header_ec; }; #----------------------------------------------------------------------------- -public type MessageWrapper = unit { - # A wrapper around 'Message'. First, we try to parse a Message unit. - # There are two possible outcomes: - # (1) Success -> We consumed all bytes and successfully parsed a Message unit - # (2) No success -> self.backtrack() is called in the Message unit, - # so effectively we didn't consume any bytes yet. - # The outcome can be determined by checking the `success` variable of the Message unit +type SaslMsKrb5Stripper = unit(ctx: Ctx&) { + # This is based on Wireshark output and example traffic we have. There's always + # a 4 byte length field followed by the krb5_tok_id field in messages after + # MS_KRB5 was selected. I haven't read enough specs to understand if it's + # just this one case that works, or others could use the same stripping. + var switch_size: uint64; - # This success variable is different, because this keeps track of the status for the MessageWrapper object - var success: bool = False; - var message: Message; + len: uint32; + krb5_tok_id: uint16; - # Here, we try to parse the message... - : Message &try { + switch ( self.krb5_tok_id ) { + 0x0504 -> krb_wrap_token: KrbWrapToken; + * -> : void; + }; - # ... and only if the Message unit successfully parsed, we can set - # the status of this MessageWrapper's success to 'True' - if ( $$.success == True ) { - self.success = True; - self.message = $$; - } + : skip bytes &size=0 { + self.switch_size = self.len - (self.offset() - 4); + if ( self?.krb_wrap_token ) + self.switch_size -= self.krb_wrap_token.trailer_ec; } - # If we failed to parse the message, then we're going to scan the remaining bytes for the '\x30' - # start byte and try to parse a Message starting from that byte. This effectively - # strips the SASL layer if SASL Signing was enabled. Until now, I haven't found A - # better way to scan / determine the exact SASL header length yet, so we'll stick with this - # for the time being. If the entire LDAP packet was encrypted with SASL, then we skip parsing for - # now (in the long run we need to be parsing SASL/GSSAPI instead, in which case encrypted payloads - # are just another message type). + switch ( self?.krb_wrap_token && ! self.krb_wrap_token.ctx_flags.sealed ) { + True -> : Message(ctx)[] &eod; + * -> : skip bytes &eod; + } &size=self.switch_size; - # SASLLayer (see unit above) just consumes bytes &until=b"\x30" or backtracks if it isn't found - # and sets a success flag we can use later to decide if those bytes contain a parsable message. - var sasl_success: bool = False; - : SASLLayer &try if ( self.success == False ) { - if ( $$.success == True ) { - self.sasl_success = True; - } - } - var remainder: bytes; - - # SASLLayer consumes the delimiter ('\x30'), and because this is the first byte of a valid LDAP message - # we should re-add it to the remainder if the delimiter was found. If the delimiter was not found, we - # leave the remainder empty, but note that the bytes must be consumed either way to avoid stalling the - # parser and causing an infinite loop error. - : bytes &eod if ( self.success == False ) { - if ( self.sasl_success == True ) { - self.remainder = b"\x30" + $$; - } - } - - # Again, try to parse a Message unit. Be aware that in this will sometimes fail if the '\x30' byte is - # also present in the SASL header. - - # Also, we could try to do this recursively or try a few iterations, but for now I would suggest - # to try this extra parsing once to get the best cost/benefit tradeoff. - : Message &try &parse-from=self.remainder if ( self.success == False && self.sasl_success == True ) { - if ( $$.success == True ) { - self.success = True; - self.message = $$; - } - } - - # If we still didn't manage to parse a message (so the &try resulted in another backtrack()) then - # this is probably an encrypted LDAP message, so skip it - -} &convert=self.message; + # Consume the wrap token trailer, if any. + trailer_e: skip bytes &size=self.krb_wrap_token.trailer_ec if (self?.krb_wrap_token); +}; #----------------------------------------------------------------------------- -public type Message = unit { +public type Message = unit(ctx: Ctx&) { var messageID: int64; var opcode: ProtocolOpcode = ProtocolOpcode::Undef; - var applicationBytes: bytes; var unsetResultDefault: Result; var result_: Result& = self.unsetResultDefault; var obj: string = ""; var arg: string = ""; - var success: bool = False; + var seqHeaderLen: uint64; + var msgLen: uint64; - : ASN1::ASN1Message(True) { - if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && - ($$.body?.seq) && - (|$$.body.seq.submessages| >= 2)) { - if ($$.body.seq.submessages[0].body?.num_value) { - self.messageID = $$.body.seq.submessages[0].body.num_value; - } - if ($$.body.seq.submessages[1]?.application_id) { - self.opcode = cast(cast($$.body.seq.submessages[1].application_id)); - self.applicationBytes = $$.body.seq.submessages[1].application_data; - } - } + seqHeader: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::Sequence) { + self.msgLen = $$.len.len; + } + + # Use offset() to determine how many bytes the seqHeader took. This + # needs to be done after the seqHeader field hook. + : void { + self.seqHeaderLen = self.offset(); + } + + messageID_header: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::Integer); + : ASN1::ASN1Body(self.messageID_header, False) { + self.messageID = $$.num_value; + } + + protocolOp: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Application) { + self.opcode = cast(cast($$.tag.type_)); } switch ( self.opcode ) { ProtocolOpcode::BIND_REQUEST -> BIND_REQUEST: BindRequest(self); - ProtocolOpcode::BIND_RESPONSE -> BIND_RESPONSE: BindResponse(self); + ProtocolOpcode::BIND_RESPONSE -> BIND_RESPONSE: BindResponse(self, ctx); ProtocolOpcode::UNBIND_REQUEST -> UNBIND_REQUEST: UnbindRequest(self); ProtocolOpcode::SEARCH_REQUEST -> SEARCH_REQUEST: SearchRequest(self); ProtocolOpcode::SEARCH_RESULT_ENTRY -> SEARCH_RESULT_ENTRY: SearchResultEntry(self); @@ -267,17 +268,15 @@ public type Message = unit { ProtocolOpcode::INTERMEDIATE_RESPONSE -> INTERMEDIATE_RESPONSE: NotImplemented(self); ProtocolOpcode::MOD_DN_REQUEST -> MOD_DN_REQUEST: NotImplemented(self); ProtocolOpcode::SEARCH_RESULT_REFERENCE -> SEARCH_RESULT_REFERENCE: NotImplemented(self); - } &parse-from=self.applicationBytes if ( self.opcode ); + } &size=self.protocolOp.len.len; - on %error { - self.backtrack(); - } + # Ensure some invariants hold after parsing the command. + : void &requires=(self.offset() >= self.seqHeaderLen); + : void &requires=(self.msgLen >= (self.offset() - self.seqHeaderLen)); - on %done { - self.success = True; - } - -} &requires=((self?.messageID) && (self?.opcode) && (self.opcode != ProtocolOpcode::Undef)); + # Eat the controls field if it exists. + : skip bytes &size=self.msgLen - (self.offset() - self.seqHeaderLen); +}; #----------------------------------------------------------------------------- # Bind Operation @@ -288,15 +287,99 @@ public type BindAuthType = enum { BIND_AUTH_SASL = 3, }; +type GSS_SPNEGO_negTokenInit = unit { + oidHeader: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::ObjectIdentifier); + oid: ASN1::ASN1ObjectIdentifier(self.oidHeader.len.len) &requires=(self.oid.oidstring == "1.3.6.1.5.5.2"); + + # TODO: Parse the rest of negTokenInit. + : skip bytes &eod; +}; + +# Peak into GSS-SPNEGO payload and ensure it is indeed GSS-SPNEGO. +type GSS_SPNEGO = unit { + # This is the optional octet string in SaslCredentials. + credentialsHeader: ASN1::ASN1Header &requires=($$.tag.type_ == ASN1::ASN1Type::OctetString); + + # Now we either have the initial message as specified in RFC2743 or + # a continuation from RFC4178 + # + # 60 -> APPLICATION [0] https://datatracker.ietf.org/doc/html/rfc2743#page-81) + # a1 -> CHOICE [1] https://www.rfc-editor.org/rfc/rfc4178#section-4.2 + # + gssapiHeader: ASN1::ASN1Header &requires=( + $$.tag.class == ASN1::ASN1Class::Application && $$.tag.type_ == ASN1::ASN1Type(0) + || $$.tag.class == ASN1::ASN1Class::ContextSpecific && $$.tag.type_ == ASN1::ASN1Type(1) + ); + + switch ( self.gssapiHeader.tag.type_ ) { + ASN1::ASN1Type(0) -> initial: GSS_SPNEGO_negTokenInit; + * -> : skip bytes &eod; + } &size=self.gssapiHeader.len.len; +}; + type SaslCredentials = unit() { - mechanism: ASN1::ASN1Message(True) &convert=$$.body.str_value; - # TODO: if we want to parse the (optional) credentials string + mechanism: ASN1::ASN1Message(False) &convert=$$.body.str_value; + + # Peak into GSS-SPNEGO payload if we have any. + switch ( self.mechanism ) { + "GSS-SPNEGO" -> gss_spnego: GSS_SPNEGO; + * -> : skip bytes &eod; + }; +}; + +type NegTokenResp = unit { + var accepted: bool; + var supportedMech: ASN1::ASN1Message; + + # Parse the contained Sequence. + seq: ASN1::ASN1Message(True) { + for ( msg in $$.body.seq.submessages ) { + # https://www.rfc-editor.org/rfc/rfc4178#section-4.2.2 + if ( msg.application_id == 0 ) { + self.accepted = msg.application_data == b"\x0a\x01\x00"; + } else if ( msg.application_id == 1 ) { + self.supportedMech = msg; + } else if ( msg.application_id == 2 ) { + # ignore responseToken + } else if ( msg.application_id == 3 ) { + # ignore mechListMec + } else { + throw "unhandled NegTokenResp id %s" % msg.application_id; + } + } + } + + switch ( self?.supportedMech ) { + True -> supportedMechOid: ASN1::ASN1Message(False) &convert=$$.body.str_value; + * -> : void; + } &parse-from=self.supportedMech.application_data; +}; + +type ServerSaslCreds = unit { + serverSaslCreds: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific && $$.tag.type_ == ASN1::ASN1Type(7)); + + # The PCAP missing_ldap_logs.pcapng has a1 81 b6 here for the GSS-SPNEGO response. + # + # This is context-specific ID 1, constructed, and a length of 182 as + # specified by in 4.2 of RFC4178. + # + # https://www.rfc-editor.org/rfc/rfc4178#section-4.2 + # + # TODO: This is only valid for a GSS-SPNEGO negTokenResp. + # If you want to support something else, remove the requires + # and add more to the switch below. + choice: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific); + + switch ( self.choice.tag.type_ ) { + ASN1::ASN1Type(1) -> negTokenResp: NegTokenResp; + # ... + } &size=self.choice.len.len; }; # TODO(fox-ds): A helper unit for requests for which no handling has been implemented. # Eventually all uses of this unit should be replaced with actual parsers so this unit can be removed. type NotImplemented = unit(inout message: Message) { - # Do nothing + : skip bytes &eod; }; type BindRequest = unit(inout message: Message) { @@ -324,14 +407,32 @@ type BindRequest = unit(inout message: Message) { (|self.authData| > 0)) { message.arg = self.saslCreds.mechanism; } -} &requires=((self?.authType) && (self.authType != BindAuthType::Undef)); +} &requires=(self?.authType && (self.authType != BindAuthType::Undef)); -type BindResponse = unit(inout message: Message) { +type BindResponse = unit(inout message: Message, ctx: Ctx&) { : Result { message.result_ = $$; } - # TODO: if we want to parse SASL credentials returned + # Try to parse serverSaslCreds if there's any input remaining. This + # unit is parsed with &size, so &eod here works. + # + # Technically we should be able to tell from the ASN.1 structure + # if the serverSaslCreds field exists or not. But, not sure we can + # check if there's any bytes left at this point outside of passing + # in the length and playing with offset(). + serverSaslCreds: ServerSaslCreds[] &eod { + if ( |self.serverSaslCreds| > 0 ) { + if ( self.serverSaslCreds[0]?.negTokenResp ) { + local token = self.serverSaslCreds[0].negTokenResp; + if ( token.accepted && token?.supportedMechOid ) { + if ( token.supportedMechOid == GSSAPI_MECH_MS_KRB5 ) { + ctx.saslStripping = SaslStripping::MS_KRB5; + } + } + } + } + } }; #----------------------------------------------------------------------------- @@ -899,6 +1000,6 @@ type AbandonRequest = unit(inout message: Message) { # # }; -on LDAP::MessageWrapper::%done { +on LDAP::Message::%done { spicy::accept_input(); } diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log new file mode 100644 index 0000000000..09b5614986 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 tcp ldap_tcp 3.537413 536 42 SF 0 ShADadFf 11 1116 6 362 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log new file mode 100644 index 0000000000..b6de5febd9 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log @@ -0,0 +1,14 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 1 3 bind simple success - cn=admin,dc=example,dc=com REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 2 - add success - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 3 - add success - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 4 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log new file mode 100644 index 0000000000..8b4c3fa573 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 tcp ldap_tcp 0.033404 3046 90400 RSTR 0 ShADdar 14 1733 68 93132 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log new file mode 100644 index 0000000000..cce0806fc6 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 3 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 9 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log new file mode 100644 index 0000000000..0caeba4973 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log @@ -0,0 +1,14 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scope deref_aliases base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port int string string string count string string string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 1 base never - 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 4 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 6 single never CN=Schema,CN=Configuration,DC=matrix,DC=local 424 success - (&(!(isdefunct=TRUE))(|(|(|(|(|(attributeSyntax=2.5.5.17)(attributeSyntax=2.5.5.10))(attributeSyntax=2.5.5.15))(attributeSyntax=2.5.5.1))(attributeSyntax=2.5.5.7))(attributeSyntax=2.5.5.14))) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 8 tree never DC=matrix,DC=local 1 success - (samaccountname=krbtgt) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log new file mode 100644 index 0000000000..d4b1e6e630 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log @@ -0,0 +1,13 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 tcp ldap_tcp 63.273503 3963 400107 OTH 0 Dd 12 2595 282 411387 - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 tcp ldap_tcp 0.007979 2630 3327 OTH 0 Dd 6 990 6 3567 - +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 tcp ldap_tcp 0.001925 2183 3436 OTH 0 Dd 4 463 5 3636 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log new file mode 100644 index 0000000000..6e6fe79fd9 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log @@ -0,0 +1,15 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 3 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 3 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 9 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 12 - unbind - - - - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 13 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log new file mode 100644 index 0000000000..3ef959bcf1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log @@ -0,0 +1,27 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scope deref_aliases base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port int string string string count string string string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 1 base never - 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 4 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 5 base never CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 6 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 7 tree never CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 2 success - (objectCategory=pKIEnrollmentService) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 8 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 9 base never CN=Schema,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=dMD) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 10 base never CN=Schema,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=dMD) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 11 base never CN=Aggregate,CN=Schema,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 1 base never - 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 4 base never CN=WS01,CN=Computers,DC=DMC,DC=local 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 5 base never CN=WS01,CN=Computers,DC=DMC,DC=local 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 6 base never CN=WS01,CN=Computers,DC=DMC,DC=local 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 10 base never - 1 success - (ObjectClass=*) - +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 11 base never CN=62a0ff2e-97b9-4513-943f-0d221bd30080,CN=Device Registration Configuration,CN=services,CN=Configuration,DC=DMC,DC=local 0 no such object 0000208D: NameErr: DSID-0310028B, problem 2001 (NO_OBJECT), data 0, best match of:??'CN=Services,CN=Configuration,DC=DMC,DC=local'?? (ObjectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 12 base never CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 13 tree never CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 38 success - (objectclass=pKICertificateTemplate) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/ldap/ldap-add.pcap b/testing/btest/Traces/ldap/ldap-add.pcap new file mode 100644 index 0000000000000000000000000000000000000000..118a8c42a53f9039231ee0181f5c5e1adcfe2071 GIT binary patch literal 2012 zcmaKsPiz}S7{zCIC$a0e!EFGULQn*15?WJcO`?K|MPdjM1w~d0YPof@p2SP-S+lz) zQAO0mQb7ik3kPW7P&hR=K;cpegs22nPqkVJT2Lv0CU8R)mncQy`^JCpTG4*eNbB|b zH*em1>uVRk{8S~BG-hjy5CuNmzVP96&yNvu7_M=(PMC}l@=WFC2pQ@8;^$NFgHuFN zRx--z*qwj(KpoQ9onwT{$0RQXkEUTxEy0Q%j97}@+dirdxnA{n(h zKoo$&)jE=RymCttzuJ}3p-JbxPVS}{Go_d{| zo|!jXSAT$No?WE7ZD+<1)=9&&Y+>YI6_&@kscM(>Fzu|-*nZlT<*w;iMSMtqi0*mL z7M@`V?(|LDPG8A|3obmz;w~QW!1ZuYB(98P#2<+sfsof1Ad-pAMkGsX)#Y3iBT=nJ zB*;Gk{D4S)mj>Q!GjJUuiDM)moM;;ONGQ3q_7@Plg+@Mt{|Q{JgOMojR{lWZ=kIJw zgh;L)Z4jMVB(kzH32#KMth_`AN>(-nwhNbwL{LCwWPDE27>9i6qEEDChF>2MEo>iAv@YL+LP^=wGJLvj{I^YK* xF@7nCI9`(GzT9SRKbSkVu#0TW5BkhqLgHv3vGS+Xc)d;I7-$@jcJ})<{s*}!1=0Wj literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/ldap/missing_krbtgt_ldap_request.pcapng b/testing/btest/Traces/ldap/missing_krbtgt_ldap_request.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..52c52d7424acb0bc08e375854d1342398cc3885f GIT binary patch literal 101144 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 j`n=HsM{l~f*M961(J7OBN9XYo|QIa4UvySObS zM?%FeuhS#IcswU?RjFt^D8`GY&XE(6+94)7ON!w_r9$!4F8r^<=?HtAo-(gc=@BX_ z%S+%F;m>OLLic>O{x7;(AzW{MmDD8%rTGm_HHR;Cxr9o=`jJ1T2x zT#m}=71i*vFulU-J(7ca9>i5AJETNRN;=_sgW$?V@bA!GJPUjr-wXP^ThWcdpZOz- zxMQAMI_PZp8GUg>OZMOIPWXHB*mnnV)m*^|Yl8=J$H1=)UQ^f&U&@9D3jQ*2+Aamd zC*3)@X>9SR@t<;>^LTjDLkbHDg6Nw@o*P_%{x3xTFD@wHP8_1NEs%oAU_?|^{NcU$ z5o)SU4R%OTF_3DLV#!1|zgHq6;Z#CQ%1X@q-k5}-tg1>Bd0L|CLX}ccYG`zU*hzZ)94L%I!ECh2lxRu9~IJh3o4tKNR8I5=1LT~<^ z-_ZrDztZC@b-CPSW#y%=Qcr26)5(uvyzVNmuy~`w>tg?g*ImYZLvU8IFC_@>3Vh#j z-XKkUvxo8X{SAMbUEMsRw$4%I-y42F!iSke-&Sc0%26XH)TARICnX1(2mC4c0e=S8 zLV6|bUFH8%RlOhm6H$U<1dm#gHK};$VtyC+Xes{OJ}_cfjyOWW-48@B);0Qlb@-R3 znwAIt#nJpodc&pk68O`#ma7c^=AL}fj6lHGRLc*Be;t9QhUyuO{J`o%TB@5He0BWb zs@fUVffh%7RT;Wm!3BnSMk}1GWpuHEBl+#?#l=mE5^3p3NMcCk$DyC4L=bjsm7EB4 z$AZn$!jz=K-W&#RRf$P4oDieUQm~634llqrlH4UtPqnv834T~@OirTrTI8stq>}jZ zAl(=o46v=VYoMQNLlFsmh982)6T?zKULx^3!VlBMWU!-IN~RLAdP!B`Efo)Ra7s#a zSLwT*-vQl=c7OCWbUQ6lG~Ob%MYQW_H>kpS5|EO3gzf6(ShJ+R0>=&fO8Q55Zgg+> zHX4+q+%5<4*+O1N_c~jQG>fsY#E&-o(2@{iD(vGfi65Z}vR;ZRiS9Z%Dku4|fo?S^ zMGY_M0>;xliG2d$xh~=h+tUgqnSP8aiaPlcQLdYMqk zeBI-!V7^{%HLiy}Zkb?ppJmMJmkI3ac&$z#x7*?YDm=^s$mMo>E#C03PbQbg<>to- zrLJ=AyhJBvh1*%`h7;4vk7d8%vba_m0RK?H00aX&qjMkr5G?qK=Q#A0i3R+pv5PSl zd}GFf`(DCWFt)hxmA`SE#p70%2~0s(It8{Eyv_=XH$0UVZ&->N76l7W1gB7L@kTlO zF$8D16`qt^UCPUz0zq(ETuN|S3=X5SZ&z?xJfL8)$ONIxYVb0PG2Bk}dKKJmiwAU< zdGN^tZ(FEI`0yFQ4`U%=6~7V13;*IIz8G+~XH1>J)a&pi_U89QD2`P}gw#D>%)wS2 zH})j=WNM%I!&hcKcF&K~o4e&FBB^54v?`{~Q(~ZkWXKtRqy`KgHEHz`Jb}k&Xw&%q z6+Q|AYiOwo6a(lbL5s#J4%Ie(6ZNQ>q3Ywi@$waLH@S`DgnxI z1Hjba;XiaHqO-AM0Q?1i(Al{Et4jyfz|ZJQ(~z|j66whtw^l-DW2SAh>*2#EJ#-1O zZFX9w>B$2I7Z&t80>&Cp0N?Q3uP7|sr6~RV;FZgZF5;ILod;Jt+wk!M zF1EbrIJo4|m-Z_x=zkgfwf)Kg{rYpo@En&f=N}Z8^Y=NI^LJ@)4;ep*>X|F|aPE#? zExc@kbNqN786e{`G)%0I!c~^S6&9h-?tlguvT`{u^UHZ@`4eCMt?|ZB=l$h{^S_<< z>A;oKzC3>X5o+T#jek1tY}a8IuRrQq_0Hx3)I4}G`beCwDieCLg#<6;j`$X=l4JI zMn}u}|7pEVS#aQ6|98eSH(hY;+zYzI10I{Y^o^sx3!M1v%maSC`>gAB@I1A{pteKz zU-8Q)4~!rG=>;?YapLJ84ru!B?#XAk4>04|lw9rti<|K8*N>rFOY=-@&&Q3ad{V zF}3KP%W6Kl=dcS4|2g`LwHI{{U%!<9;Qm*X@1B{z%V^ItSA6AO)?Uj!_0hg7rVn`I z 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 literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/ldap/add.zeek b/testing/btest/scripts/base/protocols/ldap/add.zeek new file mode 100644 index 0000000000..fbe2c9a4ad --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/add.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/ldap-add.pcap %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: The addRequest/addResponse operation is not implemented, yet we process it. diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek new file mode 100644 index 0000000000..12f397a62b --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/missing_krbtgt_ldap_request.pcapng %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ldap_search.log +# @TEST-EXEC: ! test -f dpd.log +# +# @TEST-DOC: Test LDAP analyzer with GSS-API integrity traffic where we can still peak into LDAP wrapped into WRAP tokens. diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek new file mode 100644 index 0000000000..4ae8d4b639 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/missing_ldap_logs.pcapng %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ldap_search.log +# @TEST-EXEC: ! test -f dpd.log +# +# @TEST-DOC: Test LDAP analyzer with GSS-API integrity traffic where we can still peak into LDAP wrapped into WRAP tokens. From 6f65b88f1b3a94c2bb6c3e3c97f64cdb253bde7b Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Tue, 23 Jul 2024 12:38:54 +0200 Subject: [PATCH 34/41] Merge remote-tracking branch 'origin/topic/awelzel/ldap-extended-request-response-starttls' * origin/topic/awelzel/ldap-extended-request-response-starttls: ldap: Add heuristic for wrap tokens ldap: Ignore ec/rrc for sealed wrap tokens ldap: Add LDAP sample with SASL-SRP mechanism ldap: Reintroduce encryption after SASL heuristic ldap: Fix assuming GSS-SPNEGO for all bindResponses ldap: Implement extended request/response and StartTLS support (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) --- scripts/base/protocols/ldap/consts.zeek | 7 + scripts/base/protocols/ldap/main.zeek | 3 + scripts/base/protocols/ldap/spicy-events.zeek | 41 +++ src/analyzer/protocol/ldap/CMakeLists.txt | 4 +- src/analyzer/protocol/ldap/ldap.evt | 15 ++ src/analyzer/protocol/ldap/ldap.spicy | 243 ++++++++++++++---- src/analyzer/protocol/ldap/ldap_zeek.spicy | 12 + .../conn.log | 11 + .../ldap.log | 13 + .../ldap_search.log | 11 + .../conn.log | 11 + .../ldap.log | 13 + .../ldap_search.log | 11 + .../conn.log | 11 + .../ldap.log | 12 + .../conn.log | 11 + .../ldap.log | 11 + .../scripts.base.protocols.ldap.starttls/out | 4 + .../ssl.log | 11 + .../conn.log | 11 + .../ldap.log | 13 + .../scripts.base.protocols.ldap.who-am-i/out | 3 + testing/btest/Traces/ldap/ldap-starttls.pcap | Bin 0 -> 6009 bytes testing/btest/Traces/ldap/ldap-who-am-i.pcap | Bin 0 -> 1248 bytes testing/btest/Traces/ldap/sasl-ntlm.pcap | Bin 0 -> 4052 bytes .../btest/Traces/ldap/sasl-scram-sha-512.pcap | Bin 0 -> 4297 bytes .../btest/Traces/ldap/sasl-srp-who-am-i.pcap | Bin 0 -> 2838 bytes .../base/protocols/ldap/sasl-ntlm.zeek | 12 + .../protocols/ldap/sasl-scram-sha-512.zeek | 12 + .../protocols/ldap/sasl-srp-who-am-i.zeek | 11 + .../scripts/base/protocols/ldap/starttls.zeek | 25 ++ .../scripts/base/protocols/ldap/who-am-i.zeek | 20 ++ 32 files changed, 506 insertions(+), 56 deletions(-) create mode 100644 src/analyzer/protocol/ldap/ldap_zeek.spicy create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap_search.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap_search.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.starttls/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.starttls/out create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ssl.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/out create mode 100644 testing/btest/Traces/ldap/ldap-starttls.pcap create mode 100644 testing/btest/Traces/ldap/ldap-who-am-i.pcap create mode 100644 testing/btest/Traces/ldap/sasl-ntlm.pcap create mode 100644 testing/btest/Traces/ldap/sasl-scram-sha-512.pcap create mode 100644 testing/btest/Traces/ldap/sasl-srp-who-am-i.pcap create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-ntlm.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-scram-sha-512.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-srp-who-am-i.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/starttls.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/who-am-i.zeek diff --git a/scripts/base/protocols/ldap/consts.zeek b/scripts/base/protocols/ldap/consts.zeek index bbd378c7e8..5b29fd22e4 100644 --- a/scripts/base/protocols/ldap/consts.zeek +++ b/scripts/base/protocols/ldap/consts.zeek @@ -120,4 +120,11 @@ export { "searching", [ LDAP::SearchDerefAlias_DEREF_FINDING_BASE ] = "finding", [ LDAP::SearchDerefAlias_DEREF_ALWAYS ] = "always", } &default="unknown"; + + const EXTENDED_REQUESTS = { + # StartTLS, https://datatracker.ietf.org/doc/html/rfc4511#section-4.14.1 + [ "1.3.6.1.4.1.1466.20037" ] = "StartTLS", + # whoami, https://datatracker.ietf.org/doc/html/rfc4532#section-2 + [ "1.3.6.1.4.1.4203.1.11.3" ] = "whoami", + } &default="unknown" &redef; } diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index 93c301a65a..da4a21871c 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -258,6 +258,9 @@ event LDAP::message(c: connection, } m$object = object; + + if ( opcode == LDAP::ProtocolOpcode_EXTENDED_REQUEST ) + m$object += fmt(" (%s)", EXTENDED_REQUESTS[object]); } if ( argument != "" ) { diff --git a/scripts/base/protocols/ldap/spicy-events.zeek b/scripts/base/protocols/ldap/spicy-events.zeek index fa670f3456..baa00ba548 100644 --- a/scripts/base/protocols/ldap/spicy-events.zeek +++ b/scripts/base/protocols/ldap/spicy-events.zeek @@ -98,3 +98,44 @@ global LDAP::search_result_entry: event ( message_id: int, object_name: string ); + +## Event generated for each ExtendedRequest in LDAP messages. +## +## c: The connection. +## +## message_id: The messageID element. +## +## request_name: The name of the extended request. +## +## request_value: The value of the extended request (empty if missing). +global LDAP::extended_request: event ( + c: connection, + message_id: int, + request_name: string, + request_value: string +); + +## Event generated for each ExtendedResponse in LDAP messages. +## +## c: The connection. +## +## message_id: The messageID element. +## +## result: The result code of the response. +## +## response_name: The name of the extended response (empty if missing). +## +## response_value: The value of the extended response (empty if missing). +global LDAP::extended_response: event ( + c: connection, + message_id: int, + result: LDAP::ResultCode, + response_name: string, + response_value: string +); + +## Event generated when a plaintext LDAP connection switched to TLS. +## +## c: The connection. +## +global LDAP::starttls: event(c: connection); diff --git a/src/analyzer/protocol/ldap/CMakeLists.txt b/src/analyzer/protocol/ldap/CMakeLists.txt index a687e880ff..3f69e6543d 100644 --- a/src/analyzer/protocol/ldap/CMakeLists.txt +++ b/src/analyzer/protocol/ldap/CMakeLists.txt @@ -1,5 +1,5 @@ spicy_add_analyzer( NAME LDAP PACKAGE_NAME spicy-ldap - SOURCES ldap.spicy ldap.evt asn1.spicy - MODULES LDAP ASN1) + SOURCES ldap.spicy ldap.evt asn1.spicy ldap_zeek.spicy + MODULES LDAP ASN1 LDAP_Zeek) diff --git a/src/analyzer/protocol/ldap/ldap.evt b/src/analyzer/protocol/ldap/ldap.evt index 96baef6f98..77f34fb62e 100644 --- a/src/analyzer/protocol/ldap/ldap.evt +++ b/src/analyzer/protocol/ldap/ldap.evt @@ -41,3 +41,18 @@ on LDAP::SearchRequest -> event LDAP::search_request($conn, on LDAP::SearchResultEntry -> event LDAP::search_result_entry($conn, message.messageID, self.objectName); + +on LDAP::ExtendedRequest -> event LDAP::extended_request($conn, + message.messageID, + self.requestName, + self.requestValue); + +on LDAP::ExtendedResponse -> event LDAP::extended_response($conn, + message.messageID, + message.result_.code, + self.responseName, + self.responseValue); + +# Once switched into MessageMode::TLS, we won't parse messages anymore, +# so this is raised just once. +on LDAP::Message if (ctx.messageMode == LDAP::MessageMode::TLS) -> event LDAP::starttls($conn); diff --git a/src/analyzer/protocol/ldap/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy index 2d4f821d78..96f942d7a3 100644 --- a/src/analyzer/protocol/ldap/ldap.spicy +++ b/src/analyzer/protocol/ldap/ldap.spicy @@ -130,29 +130,104 @@ public type Result = unit { const GSSAPI_MECH_MS_KRB5 = "1.2.840.48018.1.2.2"; # Supported SASL stripping modes. -type SaslStripping = enum { - MS_KRB5 = 1, # Payload starts with a 4 byte length followed by a wrap token that may or may not be sealed. +type MessageMode = enum { + MS_KRB5 = 1, # Payload starts with a 4 byte length followed by a wrap token that may or may not be sealed. + TLS = 2, # Client/server used StartTLS, forward to SSL analyzer. + MAYBE_ENCRYPTED = 3, # Use a heuristic to determine encrypted traffic. + CLEARTEXT = 4, # Assume cleartext. + ENCRYPTED = 5, # Assume encrypted. }; type Ctx = struct { - saslStripping: SaslStripping; # Which mode of SASL stripping to use. + messageMode: MessageMode; # Message dispatching mode + saslMechanism: string; # The SASL mechanism selected by the client. + startTlsRequested: bool; # Did the client use the StartTLS extended request? }; #----------------------------------------------------------------------------- public type Messages = unit { %context = Ctx; - : SASLStrip(self.context())[]; + : MessageDispatch(self.context())[]; }; #----------------------------------------------------------------------------- -public type SASLStrip = unit(ctx: Ctx&) { - switch( ctx.saslStripping ) { - SaslStripping::Undef -> : Message(ctx); - SaslStripping::MS_KRB5 -> : SaslMsKrb5Stripper(ctx); +public type MessageDispatch = unit(ctx: Ctx&) { + switch( ctx.messageMode ) { + MessageMode::Undef -> : Message(ctx); + MessageMode::MS_KRB5 -> : SaslMsKrb5Stripper(ctx); + MessageMode::TLS -> : TlsForward; # never returns + MessageMode::MAYBE_ENCRYPTED -> : MaybeEncrypted(ctx); + MessageMode::CLEARTEXT -> : Message(ctx); + MessageMode::ENCRYPTED -> : EncryptedMessage; }; }; +#----------------------------------------------------------------------------- +type MaybeEncrypted = unit(ctx: Ctx&) { + # A plaintext LDAP message always starts with at least 3 bytes and the first + # byte is 0x30 for the sequence. A SASL encrypted message starts with a 4 byte + # length field. The heuristic here is that if the first byte is a 0x30, + # assume it's unencrypted LDAP. This should be pretty good, if it was an + # encrypted/SASL wrapped message, it would have a size between 0x30000000 and + # 0x30FFFFFF, meaning at least a size of ~768MB, which seems unlikely. + var start: iterator; + var saslLen: uint64; + var mech: bytes; + + on %init { + self.start = self.input(); + # Don't have starts_with() on string, work around that. + # https://github.com/zeek/spicy/issues/1807 + self.mech = ctx.saslMechanism.encode(spicy::Charset::UTF8); + } + + first: uint8 { + if ( $$ == 0x30 ) { + ctx.messageMode = MessageMode::CLEARTEXT; + } else { + ctx.messageMode = MessageMode::ENCRYPTED; + } + } + + # As a further heuristic, if encrypted mode was decided and the client + # requested GSSAPI or GSS-SPNEGO (or we just didn't see it) peak a bit + # into the SASL payload and check if it starts with a 0504 (WRAP_TOKEN). + # If so, switch into KRB mode assuming that's what is being used and + # have a chance seeing some more plaintext LDAP in non-sealed tokens. + rem: uint8[3] if ( ctx.messageMode == MessageMode::ENCRYPTED && (|self.mech| == 0 || self.mech.starts_with(b"GSS")) ) { + self.saslLen = (self.first << 24) + ($$[0] << 16) + ($$[1] << 8) + $$[2]; + } + + : uint16 if ( self.saslLen >= 2 ) { + if ( $$ == 0x0504 ) { + ctx.messageMode = MessageMode::MS_KRB5; + } + } + + # Rewind the input. + : void { + # Prevent MessageDispatch from recursing endlessly. + assert ctx.messageMode != MessageMode::MAYBE_ENCRYPTED; + self.set_input(self.start); + } + + # One recursion to parse with the new ctx.messageMode setting. + : MessageDispatch(ctx); +}; + +#----------------------------------------------------------------------------- +type EncryptedMessage = unit { + len: uint32; + : skip bytes &size=self.len; +}; + +#----------------------------------------------------------------------------- +type TlsForward = unit { + # Just consume everything. This is hooked in ldap_zeek.spicy + chunk: bytes &chunked &eod; +}; + type KrbWrapToken = unit { # https://datatracker.ietf.org/doc/html/rfc4121#section-4.2.6.2 @@ -174,7 +249,10 @@ type KrbWrapToken = unit { } else if ( self.rrc == 0 ) { self.trailer_ec = self.ec; } else { - throw "Unhandled rc %s and ec %s" % (self.ec, self.rrc); + if ( ! self.ctx_flags.sealed ) + # If it's sealed, we'll consume until &eod anyhow + # and ec/rrc shouldn't apply, otherwise, bail. + throw "Unhandled rc %s and ec %s" % (self.ec, self.rrc); } } @@ -223,6 +301,7 @@ public type Message = unit(ctx: Ctx&) { var arg: string = ""; var seqHeaderLen: uint64; var msgLen: uint64; + var opLen: uint64; seqHeader: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::Sequence) { self.msgLen = $$.len.len; @@ -241,10 +320,11 @@ public type Message = unit(ctx: Ctx&) { protocolOp: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Application) { self.opcode = cast(cast($$.tag.type_)); + self.opLen = $$.len.len; } switch ( self.opcode ) { - ProtocolOpcode::BIND_REQUEST -> BIND_REQUEST: BindRequest(self); + ProtocolOpcode::BIND_REQUEST -> BIND_REQUEST: BindRequest(self, ctx); ProtocolOpcode::BIND_RESPONSE -> BIND_RESPONSE: BindResponse(self, ctx); ProtocolOpcode::UNBIND_REQUEST -> UNBIND_REQUEST: UnbindRequest(self); ProtocolOpcode::SEARCH_REQUEST -> SEARCH_REQUEST: SearchRequest(self); @@ -263,12 +343,12 @@ public type Message = unit(ctx: Ctx&) { # just commenting this out, it will stop processing LDAP Messages in this connection ProtocolOpcode::ADD_REQUEST -> ADD_REQUEST: NotImplemented(self); ProtocolOpcode::COMPARE_REQUEST -> COMPARE_REQUEST: NotImplemented(self); - ProtocolOpcode::EXTENDED_REQUEST -> EXTENDED_REQUEST: NotImplemented(self); - ProtocolOpcode::EXTENDED_RESPONSE -> EXTENDED_RESPONSE: NotImplemented(self); + ProtocolOpcode::EXTENDED_REQUEST -> EXTENDED_REQUEST: ExtendedRequest(self, ctx); + ProtocolOpcode::EXTENDED_RESPONSE -> EXTENDED_RESPONSE: ExtendedResponse(self, ctx); ProtocolOpcode::INTERMEDIATE_RESPONSE -> INTERMEDIATE_RESPONSE: NotImplemented(self); ProtocolOpcode::MOD_DN_REQUEST -> MOD_DN_REQUEST: NotImplemented(self); ProtocolOpcode::SEARCH_RESULT_REFERENCE -> SEARCH_RESULT_REFERENCE: NotImplemented(self); - } &size=self.protocolOp.len.len; + } &size=self.opLen; # Ensure some invariants hold after parsing the command. : void &requires=(self.offset() >= self.seqHeaderLen); @@ -296,7 +376,7 @@ type GSS_SPNEGO_negTokenInit = unit { }; # Peak into GSS-SPNEGO payload and ensure it is indeed GSS-SPNEGO. -type GSS_SPNEGO = unit { +type GSS_SPNEGO_Init = unit { # This is the optional octet string in SaslCredentials. credentialsHeader: ASN1::ASN1Header &requires=($$.tag.type_ == ASN1::ASN1Type::OctetString); @@ -322,12 +402,19 @@ type SaslCredentials = unit() { # Peak into GSS-SPNEGO payload if we have any. switch ( self.mechanism ) { - "GSS-SPNEGO" -> gss_spnego: GSS_SPNEGO; + "GSS-SPNEGO" -> gss_spnego: GSS_SPNEGO_Init; * -> : skip bytes &eod; }; }; -type NegTokenResp = unit { +type GSS_SPNEGO_Subsequent = unit { + token: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific); + switch ( self.token.tag.type_ ) { + ASN1::ASN1Type(1) -> negTokenResp: GSS_SPNEGO_negTokenResp; + }; +}; + +type GSS_SPNEGO_negTokenResp = unit { var accepted: bool; var supportedMech: ASN1::ASN1Message; @@ -355,34 +442,13 @@ type NegTokenResp = unit { } &parse-from=self.supportedMech.application_data; }; -type ServerSaslCreds = unit { - serverSaslCreds: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific && $$.tag.type_ == ASN1::ASN1Type(7)); - - # The PCAP missing_ldap_logs.pcapng has a1 81 b6 here for the GSS-SPNEGO response. - # - # This is context-specific ID 1, constructed, and a length of 182 as - # specified by in 4.2 of RFC4178. - # - # https://www.rfc-editor.org/rfc/rfc4178#section-4.2 - # - # TODO: This is only valid for a GSS-SPNEGO negTokenResp. - # If you want to support something else, remove the requires - # and add more to the switch below. - choice: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific); - - switch ( self.choice.tag.type_ ) { - ASN1::ASN1Type(1) -> negTokenResp: NegTokenResp; - # ... - } &size=self.choice.len.len; -}; - # TODO(fox-ds): A helper unit for requests for which no handling has been implemented. # Eventually all uses of this unit should be replaced with actual parsers so this unit can be removed. type NotImplemented = unit(inout message: Message) { : skip bytes &eod; }; -type BindRequest = unit(inout message: Message) { +type BindRequest = unit(inout message: Message, ctx: Ctx&) { version: ASN1::ASN1Message(True) &convert=$$.body.num_value; name: ASN1::ASN1Message(True) &convert=$$.body.str_value { message.obj = self.name; @@ -406,12 +472,32 @@ type BindRequest = unit(inout message: Message) { saslCreds: SaslCredentials() &parse-from=self.authData if ((self.authType == BindAuthType::BIND_AUTH_SASL) && (|self.authData| > 0)) { message.arg = self.saslCreds.mechanism; + ctx.saslMechanism = self.saslCreds.mechanism; } } &requires=(self?.authType && (self.authType != BindAuthType::Undef)); +type ServerSaslCreds = unit { + serverSaslCreds: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific && $$.tag.type_ == ASN1::ASN1Type(7)); + payload: bytes &size=self.serverSaslCreds.len.len; +}; + type BindResponse = unit(inout message: Message, ctx: Ctx&) { : Result { message.result_ = $$; + + # The SASL authentication was successful. We do not actually + # know if the following messages are encrypted or not. This may be + # mechanism and parameter specific. For example SCRAM-SHA512 or NTLM + # will continue to be cleartext, while SRP or GSS-API would be encrypted. + # + # Switch messageMode into trial mode which is explored via MessageDispatch + # and the MaybeEncrypted unit. + # + # Note, messageMode may be changed to something more specific like + # MS_KRB5 below. + if ( |ctx.saslMechanism| > 0 && $$.code == ResultCode::SUCCESS ) { + ctx.messageMode = MessageMode::MAYBE_ENCRYPTED; + } } # Try to parse serverSaslCreds if there's any input remaining. This @@ -421,14 +507,18 @@ type BindResponse = unit(inout message: Message, ctx: Ctx&) { # if the serverSaslCreds field exists or not. But, not sure we can # check if there's any bytes left at this point outside of passing # in the length and playing with offset(). - serverSaslCreds: ServerSaslCreds[] &eod { - if ( |self.serverSaslCreds| > 0 ) { - if ( self.serverSaslCreds[0]?.negTokenResp ) { - local token = self.serverSaslCreds[0].negTokenResp; - if ( token.accepted && token?.supportedMechOid ) { - if ( token.supportedMechOid == GSSAPI_MECH_MS_KRB5 ) { - ctx.saslStripping = SaslStripping::MS_KRB5; - } + serverSaslCreds: ServerSaslCreds[] &eod; + + # If the client requested GSS-SPNEGO, try to parse the server's response + # to switch message mode. + gss_spnego: GSS_SPNEGO_Subsequent &parse-from=self.serverSaslCreds[0].payload + if (ctx.saslMechanism == "GSS-SPNEGO" && |self.serverSaslCreds| > 0) { + + if ( $$?.negTokenResp ) { + local token = $$.negTokenResp; + if ( token.accepted && token?.supportedMechOid ) { + if ( token.supportedMechOid == GSSAPI_MECH_MS_KRB5 ) { + ctx.messageMode = MessageMode::MS_KRB5; } } } @@ -980,16 +1070,61 @@ type AbandonRequest = unit(inout message: Message) { #----------------------------------------------------------------------------- # Extended Operation # https://tools.ietf.org/html/rfc4511#section-4.12 +type ExtendedRequest = unit(inout message: Message, ctx: Ctx&) { + var requestValue: bytes; + header: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific); + requestName: bytes &size=self.header.len.len &convert=$$.decode(spicy::Charset::ASCII) { + message.obj = $$; + } -# TODO: implement ExtendedRequest -# type ExtendedRequest = unit(inout message: Message) { -# -# }; + # If there's more byte to parse, it's the requestValue. + : ASN1::ASN1Message(False) + &requires=($$.head.tag.class == ASN1::ASN1Class::ContextSpecific) + if ( message.opLen > self.offset() ) { -# TODO: implement ExtendedResponse -# type ExtendedResponse = unit(inout message: Message) { -# -# }; + self.requestValue = $$.application_data; + } + + on %done { + # Did the client request StartTLS? + # + # https://datatracker.ietf.org/doc/html/rfc4511#section-4.14.1 + if ( self.requestName == "1.3.6.1.4.1.1466.20037" ) + ctx.startTlsRequested = True; + } +}; + +#----------------------------------------------------------------------------- +type ExtendedResponseEntry = unit(inout r: ExtendedResponse) { + : ASN1::ASN1Message(False) &requires=($$.head.tag.class == ASN1::ASN1Class::ContextSpecific) { + if ( $$.head.tag.type_ == ASN1::ASN1Type(10) ) + r.responseName = $$.application_data; + else if ( $$.head.tag.type_ == ASN1::ASN1Type(11) ) + r.responseValue = $$.application_data; + else + throw "Unhandled extended response tag %s" % $$.head.tag; + } +}; + +#----------------------------------------------------------------------------- +type ExtendedResponse = unit(inout message: Message, ctx: Ctx&) { + var responseName: bytes; + var responseValue: bytes; + : Result { + message.result_ = $$; + } + + # Try to parse two ASN1 entries if there are bytes left in the unit. + # Both are optional and identified by context specific tagging. + : ExtendedResponseEntry(self) if ( message.opLen > self.offset() ); + : ExtendedResponseEntry(self) if ( message.opLen > self.offset() ); + + on %done { + # Client had requested StartTLS and it was successful? Switch to SSL. + if ( ctx.startTlsRequested && message.result_.code == ResultCode::SUCCESS ) + ctx.messageMode = MessageMode::TLS; + } +}; #----------------------------------------------------------------------------- # IntermediateResponse Message diff --git a/src/analyzer/protocol/ldap/ldap_zeek.spicy b/src/analyzer/protocol/ldap/ldap_zeek.spicy new file mode 100644 index 0000000000..3a6784589f --- /dev/null +++ b/src/analyzer/protocol/ldap/ldap_zeek.spicy @@ -0,0 +1,12 @@ +module LDAP_Zeek; + +import LDAP; +import zeek; + +on LDAP::TlsForward::%init { + zeek::protocol_begin("SSL"); +} + +on LDAP::TlsForward::chunk { + zeek::protocol_data_in(zeek::is_orig(), self.chunk); +} diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/conn.log new file mode 100644 index 0000000000..27c56bc33b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60126 127.0.1.1 389 tcp ldap_tcp 2.290081 289 1509 SF 0 ShADadFf 12 921 15 2297 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap.log new file mode 100644 index 0000000000..cd94c49d5b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap.log @@ -0,0 +1,13 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60126 127.0.1.1 389 1 3 bind SASL SASL bind in progress SASL(0): successful result: - NTLM +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60126 127.0.1.1 389 2 3 bind SASL success - - NTLM +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60126 127.0.1.1 389 4 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap_search.log new file mode 100644 index 0000000000..3ff2f3b1a6 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-ntlm/ldap_search.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scope deref_aliases base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port int string string string count string string string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60126 127.0.1.1 389 3 tree never dc=example,dc=com 9 success - (objectclass=*) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/conn.log new file mode 100644 index 0000000000..5fcce64ab8 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 59552 127.0.1.1 389 tcp ldap_tcp 2.231680 353 1772 SF 0 ShADadFf 11 933 15 2560 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap.log new file mode 100644 index 0000000000..7c3478b262 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap.log @@ -0,0 +1,13 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 59552 127.0.1.1 389 1 3 bind SASL SASL bind in progress SASL(0): successful result: user: sasladmin@slapd.ldap property: slapAuthzDN not found in sasldb - SCRAM-SHA-512 +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 59552 127.0.1.1 389 2 3 bind SASL success - - SCRAM-SHA-512 +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 59552 127.0.1.1 389 4 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap_search.log new file mode 100644 index 0000000000..edcf38ced5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-scram-sha-512/ldap_search.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scope deref_aliases base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port int string string string count string string string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 59552 127.0.1.1 389 3 tree never dc=example,dc=com 9 success - (objectclass=*) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/conn.log new file mode 100644 index 0000000000..2638ca3cba --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60648 127.0.1.1 389 tcp ldap_tcp 2.114467 548 1020 SF 0 ShADadFf 9 1024 6 1340 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/ldap.log new file mode 100644 index 0000000000..facaf46bc7 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-srp-who-am-i/ldap.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60648 127.0.1.1 389 1 3 bind SASL SASL bind in progress SASL(0): successful result: user: zeek@ubuntu-01.example.com property: slapAuthzDN not found in sasldb - SRP +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 60648 127.0.1.1 389 2 3 bind SASL success - - SRP +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/conn.log new file mode 100644 index 0000000000..db789c02c1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 45936 127.0.1.1 389 tcp ldap_tcp,ssl 0.016922 683 3002 RSTO 0 ShADadFR 14 1407 14 3738 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ldap.log new file mode 100644 index 0000000000..95a084dab8 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ldap.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 45936 127.0.1.1 389 1 - extended success - 1.3.6.1.4.1.1466.20037 (StartTLS) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/out b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/out new file mode 100644 index 0000000000..08e6ccc9f2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/out @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +CHhAvVGS1DHFjwGM9, extended_request, 1.3.6.1.4.1.1466.20037 (StartTLS), +CHhAvVGS1DHFjwGM9, extended_response, LDAP::ResultCode_SUCCESS, , +CHhAvVGS1DHFjwGM9, LDAP::starttls diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ssl.log new file mode 100644 index 0000000000..19fdd43528 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.starttls/ssl.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert +#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 45936 127.0.1.1 389 TLSv13 TLS_AES_256_GCM_SHA384 secp256r1 ubuntu-01.example.com F - - T CsiI - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/conn.log new file mode 100644 index 0000000000..9914fbe2dc --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 48122 127.0.1.1 389 tcp ldap_tcp 0.001192 83 59 SF 0 ShADadFf 8 507 5 327 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/ldap.log new file mode 100644 index 0000000000..80da834eba --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/ldap.log @@ -0,0 +1,13 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 48122 127.0.1.1 389 1 3 bind simple success - cn=admin,dc=example,dc=com REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 48122 127.0.1.1 389 2 - extended success - 1.3.6.1.4.1.4203.1.11.3 (whoami) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 48122 127.0.1.1 389 3 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/out b/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/out new file mode 100644 index 0000000000..c4dbc10489 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.who-am-i/out @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +CHhAvVGS1DHFjwGM9, extended_request, 1.3.6.1.4.1.4203.1.11.3 (whoami), +CHhAvVGS1DHFjwGM9, extended_response, LDAP::ResultCode_SUCCESS, , dn:cn=admin,dc=example,dc=com diff --git a/testing/btest/Traces/ldap/ldap-starttls.pcap b/testing/btest/Traces/ldap/ldap-starttls.pcap new file mode 100644 index 0000000000000000000000000000000000000000..0cb6035125efd4ca7094ea308e0aec2ef1f37e9f GIT binary patch literal 6009 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 DyIjjT literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/ldap/ldap-who-am-i.pcap b/testing/btest/Traces/ldap/ldap-who-am-i.pcap new file mode 100644 index 0000000000000000000000000000000000000000..75dae01d4e5c84bb150be922d14eef212fba067d GIT binary patch literal 1248 zcmaKr&ui0g7{=dknyq8(U?<`nY)nBBf0V>^Q`;3r!Gn64;8kqaBsjF~ytpzZi?FKL zZHF-sFEWcDDhL)~wmS&w#i0j_?hhEd<=jKpLw(|TbR@e z&Qq^F-cxU-M8uD;0VZ$|YG?60iQ*&^ueBxiLH&JwpSVo9D?K=m7VH*yhGaf9KalUU zf%BZ#6Hi_%xPcwsz`gyvHqrGmIgY*om_)18&SJ;c?F&qtYD>foENr`p%Ah2qnIqO= zH9Q<14Xfb@^*Lo2FDgDG#WE^pQHt7Gtf&=JoRR9uXa`d-S(wqSxGSSg(TrMZ~YZL_5YFA9_4i&|@#3 IpCPx$KS)1C6#xJL literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/ldap/sasl-ntlm.pcap b/testing/btest/Traces/ldap/sasl-ntlm.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ef2fb91ab4e18be7df4fbe120116ef99178c1ce9 GIT binary patch literal 4052 zcmb7{e`phD7{}kczD;YJ^p{oZkJ_kotJB#_twXJ4ZJk&({ef+DbDMg(T+^$`UCbro zWKL6bGOC+Y9Tf$Cfj`Ek(+Q3t_=o;6VGIP(unifLfH>G6f-rTPd!F}_cz2Bf-}KFU zx#Yg@=lMR*``-2T^-CvsLP@$ke@+MoA1+lK?w_XeWF;J9H@8BvjF2UX!4}fukh*rj z1v?1GJ-o;5K0M5wz+WEcw{I;!PY6%*FH^p-=+1-p*W-CEFRuWV>vJj-g33)lpem|! zyC2?rTsyKD)K4C-_&EH}w=a~Pn}=qidRn;!l-pn??B>Rp8xxxt^BNoTNl|LL^*onH$*DR@JA1ty z)Q#^wJ>AUt0^XR#otg|sc<)*ql|diaa@Y%c>{@Au=&g#FbD&r}eb->KZ$LH|9@FidY=(nXe%R^lb?aMVM3nIp@9|K*M( zLM$`Aw#+0T*XLNSy_U?(x(trg{^%fo!MxbbjXCmrLPbU2nXHPC>uW30ivCsTvk*VW zbNt5mDI?qQBdK)9N7C`2`7_p5Q0~_Vev4$5=kP|`w091n5u?2qHfo?^{6C`(Z(DC)YvVyn63AYTCjc5`DSN0U{| zyH=ZbSHQcg=$-3W#=COx&MWi-iC@e@B6x+lG&TKFoZeGS^P*aq7W$N-6J`JmY9VDm?VC6UbpHvp$CWdU7%&2M^7A@qwB&`5z57 z^7vjvkAF(1YO&^SSxcE{^-~B4b=D{*8&Oo4*~MU=szikn%4;!CA$1sP!W>%cmvt$k zgfT$RG&*Ierbb0Yl_TzcE#i*pa3HJEh$8D4pbrB41nz0r%?(q-g_Bb-z`jkk0MDlb zl;_w29O4#YghQN%z8+Kj&0xB!%j(=*;SO($7jOM|Nn7`Dd!bCbQplp%VPBA3o`8F})6C)yermN`LN(Lv4r@W+kT(r1N^y%)@ z$yu~CDhK88fTqfwv5-%Wc*En0yz97NZMC-O6>81JYOR3gGcn}d0=y>y6uY@G-h;_$jCYxp_fUJ9_rIq$-u1}) z9$OsCBU&t+4S4Y@0B075p@ziUf%r6_VmCKNJesU##4R@BvuWbx4{gLgB>s?AgTo!7 zGyoNujd{r{Fqbiti)dk552<$n^%20uZf=ZvUvfI5UTLNN(wV0I6do^eD~B6{v4O5d z>eZ|+R`^3=I7?kL3bU+BvXW-oeljJ&bP)9mK)nl$*v*Zh-b~goRF@4^PNQD9Z$pib zAZvUtt(DZ~fD9XfjGM_z%R>^TTDhIHD6HwqR(1t0eOT(S^bIMY61NC{YJEdxdvKi! z)2*9mDRr@{-J&FEF*S-|9)d7)+^#ocm{Pax=6dyU?V+=9yZ(Fsej`k{opoSVQ1J{X zu7h0|ySbrpoHyx4#lFvM#yw3Nr{PpDa@-*dah2%Y5a*(`xD&td?qyp+{J!v-)w@Zw zAQduoG80=31IE}`YV5rhUtv#i&U!pkpGwkXS`^d* zirO-O3pO$nVTE+1QM zqi%eFT6-;{*ooC94W?L>F}D&HM<*(ZITaHz#^|*%-T=lK%+A6LV>bj}`9DG^6M6su literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/ldap/sasl-scram-sha-512.pcap b/testing/btest/Traces/ldap/sasl-scram-sha-512.pcap new file mode 100644 index 0000000000000000000000000000000000000000..70fd3d6b0d3659dec9bf9e97aa1d87ecce5a5af5 GIT binary patch literal 4297 zcmb7{4@?{P702()kMPI*OQBu*C!4i2BOL_JV8BUZ2?ORo1TX}LZB@?a!#--?S$Ajt zc-{D;wMbdIbXis9KXk34sp_ODTDP{_5@=Fsnc8Sm6Q)L6D=nKAG)3K{NmG|i-FrXV z^zP!)<%uWY;J){H-}iox0#!%F0iSANLe9-S9Q0G4dH7!|Y2Q zZf2Udtk%xL4YLf(-dbj#E-nAyQT)wi+qb6o|BYd6B=@JpmS4EG{_YT7XLEA$Q28gD zDl-f!KmI1FqB{HZt!1_H_^HLuv_O}js`*!;~y}KKnb!4AhT`hYwUW@Xfm?SsD=Xj_l8sg*Cs%Lbf zSDk548V<;^-d;a?V5Ca#AN0%Ja;G{t=57-aw)9G>^z7x^Uq@K3&|>U0Fm?{g|M-K( z6l{_DpR;T0*KeTWE040w*I*(rje+H}efBp{vF7ht6}K@TGmmU2zJ`k20((Cgz%Q^R zg=`67$RWSi-@A)@Y_CI02!g0-5)?jg6kz9-x#j*L#U`i6qTp-5e~ ziGhBlGd|f9j7NL>v?DzecJmSq<0N^n9H zbRo)X8poiEr{-AZ6+pl=1|>Od{{?k%$?W3EQE+hS!LdcjXKFO65TS#ygki2wxNd5+p z{|=BbjX}vT*?&pNr!3?bGvr?_u#nFmLG<}&$iqs)GaxEy6U}~dVQ!bXiU(6w+-GFx zqa(7Ub0x&4B%JwVOG=HaBKDA|391yw0-cYLhgua`=OtNGVdJTERXRjjS0z!y0^foH zVa91%3uNQ=UtxhYSIh;T>dzGTW4IHC1WtXbH4Cg8D_mfmq%t9eJYc%4iE{O3Mn%GLi#N#Qvop$~`~|!qTKD_wz9kueb1O zkXL#1Oq0>GZVJbh6PqAAi;2C34{DC|#T}$n7o%c4qR3)@A{G=?XBjEk<>K6rIT{)o zcGvHztAlCVHqHy06qBOj@Mgd5;vlvY662+)^L|pEMr=-Zz6OpFcH=U1W0TGP9Cl;X zX*sg9YUSy}xY^&|k?IBLNRy^y?ZWP+z#_0uOQhL+Qvvw9Yp;jp#B~hF^xe{uh`$Bs859$iHU8J z3U3XHI^!%MMYVXPHf`yHq%f+4CD|Vlqfw`w6x0SKxi-ja5pFBV4U2-J85*$NY&D2s z!A7V53{G#dWxtP3uX1;9*`@QiWv|~!Ic?ms>!3IQO~W(>9nlv1Wjdmke}0zEXL|RX zWa(WIbWY4mzb4{r9A03VE)d2v2GxH&d5jY8%0j$?FHlP_n2EVu8%tW~o7p)K-o%O@ zP~jSj@H1-V(#qUcu;MRfVMGmlXER0n+tiBxn#Xu)1*}-4iZ?f`xQYg&;x{){Og>K; UcUu@2fpL|#>rWeu_?mL{e?Fa+O8@`> literal 0 HcmV?d00001 diff --git a/testing/btest/Traces/ldap/sasl-srp-who-am-i.pcap b/testing/btest/Traces/ldap/sasl-srp-who-am-i.pcap new file mode 100644 index 0000000000000000000000000000000000000000..9e70f2d1b063516f418723540e8cc557d484e226 GIT binary patch literal 2838 zcmb7`3pkW%8^@n_W*n9aIfP1@$tqKr8KuNhidD+tGt$Xv@Q#LId~+bP)EJ}m_1UCa zBjvnHv<@Y^Y#XtZw6T>^)aszv(2*-tzULWRtJ${e`tIwx=bCx1XMXqpxu5&}zwfoC zllcTd0`FpS5&#VTF#j@(-Q5g;JN%AvdZ+_e0KVv1v7mfPv}dtG^EXPG8zB9tWCob%{S1|x(u>Foq1Jp4 z0*HVpl+!~&^zX4$5TiayGzJsleea0=0fk?G@2(uY_bKoaA4 zlNr^lSOq&EqY^F1Fg9V*xPZo$mLvewCE#i{- zxIn}e+LJ{BoNrG?n_MLd5k(6{R&<6nzJnDN!^N#bc~RsTJ}(C63*+IxxvUsxk#M`% z#giP(6O!3HQFIuY6HOMd1l+KYJyOD3I055uP)|g5JKMM)$$rMZ6R5v;Gp&MOgU{MC ztoE9bamev>uy>(=+E$&HHI#I)R}>eX@7QUkSGJzW(E4@P+T*uKZ@l}}S8#@Y2(N4p zK5TTv(Eb#Aw#r23cxgY?`1m(8&4WK~9E(3Vm>Kv-iIz~K`{kriu%*Mfv&pG=u7#;f zq(Pj+#ms7Zvk8e|?9XKJ8g5w9vn#b~dyKxEz3rII!_-%CYkghKPJdq6nHX3sUMRXU zI8L;j=pLb++QAB5m`>^wKdji}DIi{EQjcCDnS9lx-nGb2{-UI#N&4?{+gAhK6E%lU zUm$kniXYhCF^lpE@)c#{_xZ1{fBjsiSa)8I`=kJ1gc*FB;MaMrjD~2vas2k({&N^G zW&gHqpGW6jhEI05&^Ilx(eRR?dgJ$V36dm|QSt8}$!Kt%9hq*R&%FPVu@A^r6sSj? zbdPs3HU8`wCt&*{S+~Ed-S`TjUZ&$!i{%O0HD&SFqg?{yei%5mH2`G9TnKk-eN{_K zdah49CS3T%3HyV1f%RmXEV-iHLuS%Hcqs91y+y(U`LDZQbPVkOd@rZHvwhvVg&DP@ zk9UR^-P?cfMw!mOb)NFz2c?f!?sCyft}I%>8&I_iiqtIGRPwxoo4cxKUqncXZIPz+ z?ICTa=!^?uDBOadL$u~JaH(Rkqzb?lINcsZi6q~x;+4(4^sqFb^#g#Vh z0QfyBjOEB&>ukla_hIfCtfBdl>|`dTq; z>@1^LJ3>TkHqIAt#JJ-!TiYee(7nuo_wqlxLywihmkufU67*3YL*x!^WAA;51s%d1 z5mVy{;1M)`l+yz_9d@(F8W97AKT3q|FbHjI$~*lzh)9=W`2>s*EX9sYxt$a{Fy(hr zEEO)5VZce#PTxDF^{h^FCO2wz!)5Wzvy<&^<sqsZ|*Q{OU(F>O?Qs2 z+%9ZG)#`%qbic*bNAn3!>||P96#Fxrnu~Xn8*i?wy;Ue*qO#kO8Wby&Tse0?EA?e2 zPlx{MjJ2&zhR4pQ=QFwKPWH(ywT30~Z|kZ5U;%3#LczGac#EIwiKrgDN-UbCTh#;B1*Te~5D z)QGAc_a`FN(CP%3hIKfR`!Pl5%KLOiIgHloNcPqRyk~Ip9B%{ i584`ui1SlEsnJHEQR!W^tq*Fnu2oFiol>Y&A4anR8 literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-ntlm.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-ntlm.zeek new file mode 100644 index 0000000000..0504ba7a0a --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-ntlm.zeek @@ -0,0 +1,12 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/sasl-ntlm.pcap %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ldap_search.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: This broke after #3826 got merged diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-scram-sha-512.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-scram-sha-512.zeek new file mode 100644 index 0000000000..9db41f96bc --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-scram-sha-512.zeek @@ -0,0 +1,12 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/sasl-scram-sha-512.pcap %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ldap_search.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: This broke after #3826 got merged diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-srp-who-am-i.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-srp-who-am-i.zeek new file mode 100644 index 0000000000..b467dbe484 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-srp-who-am-i.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/sasl-srp-who-am-i.pcap %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: SASL authentication using SRP (Secure Remote Password) diff --git a/testing/btest/scripts/base/protocols/ldap/starttls.zeek b/testing/btest/scripts/base/protocols/ldap/starttls.zeek new file mode 100644 index 0000000000..df94315210 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/starttls.zeek @@ -0,0 +1,25 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/ldap-starttls.pcap %INPUT >out +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ssl.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: LDAP supports StartTLS through extendedRequest 1.3.6.1.4.1.1466.20037 + +event LDAP::extended_request(c: connection, message_id: int, request_name: string, request_value: string) { + print c$uid, "extended_request", fmt("%s (%s)", request_name, LDAP::EXTENDED_REQUESTS[request_name]), request_value; +} + +event LDAP::extended_response(c: connection, message_id: int, result: LDAP::ResultCode, response_name: string, response_value: string) { + print c$uid, "extended_response", result, response_name, response_value; +} + +event LDAP::starttls(c: connection) { + print c$uid, "LDAP::starttls"; +} diff --git a/testing/btest/scripts/base/protocols/ldap/who-am-i.zeek b/testing/btest/scripts/base/protocols/ldap/who-am-i.zeek new file mode 100644 index 0000000000..6026add5cc --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/who-am-i.zeek @@ -0,0 +1,20 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/ldap-who-am-i.pcap %INPUT >out +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: Testing OpenLDAP's ldapwhoami utility with simple authentication. + +event LDAP::extended_request(c: connection, message_id: int, request_name: string, request_value: string) { + print c$uid, "extended_request", fmt("%s (%s)", request_name, LDAP::EXTENDED_REQUESTS[request_name]), request_value; +} + +event LDAP::extended_response(c: connection, message_id: int, result: LDAP::ResultCode, response_name: string, response_value: string) { + print c$uid, "extended_response", result, response_name, response_value; +} From 382b4b5473a79546662cd868e6828ae7028f3f8b Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Wed, 7 Aug 2024 14:10:54 +0200 Subject: [PATCH 35/41] Merge remote-tracking branch 'origin/topic/awelzel/ldap-fix-uint8-shift' * origin/topic/awelzel/ldap-fix-uint8-shift: ldap: Promote uint8 to uint64 before shifting (cherry picked from commit 97fa7cdc0a49869ee6605fac9cfc15f11d8c855b) --- src/analyzer/protocol/ldap/ldap.spicy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyzer/protocol/ldap/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy index 96f942d7a3..c8ec94273f 100644 --- a/src/analyzer/protocol/ldap/ldap.spicy +++ b/src/analyzer/protocol/ldap/ldap.spicy @@ -196,7 +196,7 @@ type MaybeEncrypted = unit(ctx: Ctx&) { # If so, switch into KRB mode assuming that's what is being used and # have a chance seeing some more plaintext LDAP in non-sealed tokens. rem: uint8[3] if ( ctx.messageMode == MessageMode::ENCRYPTED && (|self.mech| == 0 || self.mech.starts_with(b"GSS")) ) { - self.saslLen = (self.first << 24) + ($$[0] << 16) + ($$[1] << 8) + $$[2]; + self.saslLen = (uint64(self.first) << 24) + (uint64($$[0]) << 16) + (uint64($$[1]) << 8) + uint64($$[2]); } : uint16 if ( self.saslLen >= 2 ) { From 8f9c5f79c6b95fc667ce101368e0d8bee3f05360 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 30 Aug 2024 12:34:09 -0700 Subject: [PATCH 36/41] Updating CHANGES and VERSION. --- CHANGES | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index bcfa60229b..e81fcbf5e4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,148 @@ +7.0.0-9 | 2024-08-30 11:47:39 -0700 + + * ldap: Promote uint8 to uint64 before shifting (Arne Welzel, Corelight) + + (cherry picked from commit 97fa7cdc0a49869ee6605fac9cfc15f11d8c855b) + + * ldap: Add heuristic for wrap tokens (Arne Welzel, Corelight) + + Instead of dissecting the GSSAPI handshake, add another heuristic + into MaybeEncrypted to check for the WRAP token identifier. + + After this change, the pcap on the following ticket is processed + nicely: https://gitlab.com/wireshark/migration-test/-/issues/9398 + + (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) + + * ldap: Ignore ec/rrc for sealed wrap tokens (Arne Welzel, Corelight) + + It shouldn't matter for the encrypted payload that we'll + just consume and ignore. + + (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) + + * ldap: Add LDAP sample with SASL-SRP mechanism (Arne Welzel, Corelight) + + This is what @dopheide-esnet actually saw. Produced with a custom + cyrus-sasl and openldap build :-( + + (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) + + * ldap: Reintroduce encryption after SASL heuristic (Arne Welzel, Corelight) + + @dopheide-esnet provided sample captures where SASL SRP is used as + a SASL mechanism and the follow-up LDAP messages are encrypted. It's + not clear how to determine whether encryption will or will not happen, + so re-add a heuristic to determine this based on the first byte of + the first message *after* the successful bindResponse handshake. If + that byte is 0x30, assume cleartext. + + I haven't been able to produce such pcaps, unfortunately, but the + cleartext path is tested via the existing sasl-ntlm.pcap. + + (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) + + * ldap: Fix assuming GSS-SPNEGO for all bindResponses (Arne Welzel, Corelight) + + In retrospect that's an obvious bug. + + (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) + + * ldap: Implement extended request/response and StartTLS support (Arne Welzel, Corelight) + + PCAP was produced with a local OpenLDAP server configured to support StartTLS. + + This puts the Zeek calls into a separate ldap_zeek.spicy file/module + to separate it from LDAP. + + (cherry picked from commit 6a6a5c3d0d60a1d4d32ba2173c035023c29fbf1d) + + * ldap: Remove MessageWrapper with magic 0x30 searching (Arne Welzel, Corelight) + + This unit implements a heuristic to search for the 0x30 sequence + byte if Message couldn't readily be parsed. Remove it with the + idea of explicit and predictable support for SASL mechanisms. + + (cherry picked from commit 2ea3a651bd83b0dfa15924417e4667241531b57b) + + * ldap: Harden parsing a bit (Arne Welzel, Corelight) + + ASN1Message(True) may go off parsing arbitrary input data as + "something ASN.1" This could be GBs of octet strings or just very + long sequences. Avoid this by open-coding some top-level types expected. + + This also tries to avoid some of the &parse-from usages that result + in unnecessary copies of data. + + Adds a locally generated PCAP with addRequest/addResponse that we + don't currently handle. + + (cherry picked from commit 2ea3a651bd83b0dfa15924417e4667241531b57b) + + * ldap: Handle integrity-only KRB wrap tokens (Arne Welzel, Corelight) + + Mostly staring at the PCAPs and opened a few RFCs. For now, only if the + MS_KRB5 OID is used and accepted in a bind response, start stripping + KRB5 wrap tokens for both, client and server traffic. + + Would probably be nice to forward the GSS-API data to the analyzer... + + (cherry picked from commit 2ea3a651bd83b0dfa15924417e4667241531b57b) + + * http: fix password capture when enabled (Pierre Lalet) + + The current implementation would only log, if the password contains a + colon, the part before the first colon (e.g., the password + `password:password` would be logged as `password`). + + (cherry picked from commit c27e18631c5d9c6f04c230bd421c9750a1f02342) + + * Analyzer: Do not add child analyzers when finished (Arne Welzel, Corelight) + + Depending on an analyzer's implementation, its Done() method may + attempt to access analyzer or connection state when executing. + When this happens in the destructor of the parent analyzer during + the process of destructing a connection, this state may have been + deleted, resulting in use-after-free crashes or worse memory + corruption. + + The following cases have been observed in the wild for when this happens. + + * PIA matching during Done() for undelivered TCP data enables a Spicy + based analyzer which in turn attempts to raise an analyzer violation + during Done()->EndOfData(). + + * Spicy analyzers attaching new analyzers during their Done() processing + which in turn attempt to use TCP() (to call FindChild()) during Done() + while the analyzer tree / connection is being destructed. + + The second scenario was previously found to happen in the HTTP analyzer + and fixed with 6ef9423f3cff13e6c73f97eb6a3a27d6f64cc320. + + Plug these scenarios by short-circuiting AddChildAnalyzer() if the analyzer + or connection have finished or are being finished. + + (cherry picked from commit 45b33bf5c17d5e8cf6c777a9bd57e4a803dfad19) + + * TCP_Reassembler: Fix IsOrig() position in Match() call (Arne Welzel, Corelight) + + Found during a debug session with @rsmmr. Undelivered TCP data + would only be matched for the responder and eol set to IsOrig(). + + (cherry picked from commit 4a4cbf25765f387f0aa20277afd133918292b9c4) + + * Process metric callbacks from the main-loop thread (Tim Wojtulewicz, Corelight) + + This avoids the callbacks from being processed on the worker thread + spawned by Civetweb. It fixes data race issues with lookups involving + global variables, amongst other threading issues. + + (cherry picked from commit 3c3853dc7da9aad94a9b2d5a143cc7bd9476ea7a) + + * CI: Use 16GB of memory for FreeBSD builds (Tim Wojtulewicz, Corelight) + + (cherry picked from commit 9d9cc51e9dd93668cd332aa1aef283c9dc23a677) + 7.0.0 | 2024-07-31 09:37:03 -0700 * Release 7.0.0. diff --git a/VERSION b/VERSION index 66ce77b7ea..b1cd350f84 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0 +7.0.0-9 From 15be682f63e3622b245ff5744eb1ec212355bfc8 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 23 Aug 2024 08:10:02 +0200 Subject: [PATCH 37/41] Merge remote-tracking branch 'origin/topic/robin/gh-3881-spicy-ports' * origin/topic/robin/gh-3881-spicy-ports: Spicy: Register well-known ports through an event handler. Revert "Remove deprecated port/ports fields for spicy analyzers" (cherry picked from commit a2079bcda6e40180b888240a281c12cc0ca735be) --- CHANGES | 21 ++++++++++++ VERSION | 2 +- doc | 2 +- .../base/frameworks/spicy/init-framework.zeek | 8 ++++- src/spicy/manager.cc | 25 ++++++++++++--- src/spicy/manager.h | 4 +-- src/spicy/port-range.h | 5 +++ .../core.check-unused-event-handlers/.stderr | 1 + .../Baseline/spicy.port-deprecated/out.stderr | 2 -- testing/btest/Baseline/spicy.port-fail/output | 2 +- testing/btest/Baseline/spicy.port/output | 19 +++++++++++ testing/btest/spicy/port-deprecated.evt | 21 ------------ testing/btest/spicy/port-fail.evt | 2 -- testing/btest/spicy/port-range-one-port.zeek | 2 +- testing/btest/spicy/port.zeek | 32 +++++++++++++++++++ 15 files changed, 112 insertions(+), 36 deletions(-) delete mode 100644 testing/btest/Baseline/spicy.port-deprecated/out.stderr create mode 100644 testing/btest/Baseline/spicy.port/output delete mode 100644 testing/btest/spicy/port-deprecated.evt create mode 100644 testing/btest/spicy/port.zeek diff --git a/CHANGES b/CHANGES index e81fcbf5e4..d765816ae0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +7.0.0-11 | 2024-08-30 12:38:59 -0700 + + * Spicy: Register well-known ports through an event handler. (Robin Sommer, Corelight) + + This avoids the earlier problem of not tracking ports correctly in + scriptland, while still supporting `port` in EVT files and `%port` in + Spicy files. + + As it turns out we are already following the same approach for file + analyzers' MIME types, so I'm applying the same pattern: it's one + event per port, without further customization points. That leaves the + patch pretty small after all while fixing the original issue. + + (cherry picked from commit a2079bcda6e40180b888240a281c12cc0ca735be) + + * Revert "Remove deprecated port/ports fields for spicy analyzers" (Robin Sommer, Corelight) + + This reverts commit 15d404dd191a723960e4efd956eec22739d3f1c2. + + (cherry picked from commit a2079bcda6e40180b888240a281c12cc0ca735be) + 7.0.0-9 | 2024-08-30 11:47:39 -0700 * ldap: Promote uint8 to uint64 before shifting (Arne Welzel, Corelight) diff --git a/VERSION b/VERSION index b1cd350f84..2283f0636c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-9 +7.0.0-11 diff --git a/doc b/doc index 4e2413e2fb..b845bee39f 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 4e2413e2fb2f98298430b3e2cb384fc5f18cbde4 +Subproject commit b845bee39fa241892458d274184e2e9f22f4d096 diff --git a/scripts/base/frameworks/spicy/init-framework.zeek b/scripts/base/frameworks/spicy/init-framework.zeek index ae3a3b8e65..de6b528ee4 100644 --- a/scripts/base/frameworks/spicy/init-framework.zeek +++ b/scripts/base/frameworks/spicy/init-framework.zeek @@ -47,12 +47,18 @@ export { # Marked with &is_used to suppress complaints when there aren't any # Spicy file analyzers loaded, and hence this event can't be generated. -# The attribute is only supported for Zeek 5.0 and higher. event spicy_analyzer_for_mime_type(a: Files::Tag, mt: string) &is_used { Files::register_for_mime_type(a, mt); } +# Marked with &is_used to suppress complaints when there aren't any +# Spicy protocol analyzers loaded, and hence this event can't be generated. +event spicy_analyzer_for_port(a: Analyzer::Tag, p: port) &is_used + { + Analyzer::register_for_port(a, p); + } + function enable_protocol_analyzer(tag: Analyzer::Tag) : bool { return Spicy::__toggle_analyzer(tag, T); diff --git a/src/spicy/manager.cc b/src/spicy/manager.cc index 1a9420e22a..423febf1c9 100644 --- a/src/spicy/manager.cc +++ b/src/spicy/manager.cc @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -32,6 +33,7 @@ #include "zeek/spicy/file-analyzer.h" #include "zeek/spicy/packet-analyzer.h" #include "zeek/spicy/protocol-analyzer.h" +#include "zeek/spicy/runtime-support.h" #include "zeek/zeek-config-paths.h" using namespace zeek; @@ -74,9 +76,13 @@ void Manager::registerProtocolAnalyzer(const std::string& name, hilti::rt::Proto info.name_zeek = hilti::rt::replace(name, "::", "_"); info.name_zeekygen = hilti::rt::fmt("", name); info.protocol = proto; - info.ports = ports; info.linker_scope = linker_scope; + // Store ports in a deterministic order. We can't (easily) sort the + // `hilti::rt::Vector` unfortunately. + std::copy(ports.begin(), ports.end(), std::back_inserter(info.ports)); + std::sort(info.ports.begin(), info.ports.end()); + // We may have that analyzer already iff it was previously pre-registered // without a linker scope. We'll then only set the scope now. if ( auto t = _analyzer_name_to_tag_type.find(info.name_zeek); t != _analyzer_name_to_tag_type.end() ) { @@ -701,14 +707,25 @@ void Manager::InitPostScript() { if ( ! tag ) reporter->InternalError("cannot get analyzer tag for '%s'", p.name_analyzer.c_str()); + auto register_analyzer_for_port = [&](auto tag, const hilti::rt::Port& port_) { + SPICY_DEBUG(hilti::rt::fmt(" Scheduling analyzer for port %s", port_)); + + // Well-known ports are registered in scriptland, so we'll raise an + // event that will do it for us through a predefined handler. + zeek::Args vals = Args(); + vals.emplace_back(tag.AsVal()); + vals.emplace_back(zeek::spicy::rt::to_val(port_, base_type(TYPE_PORT))); + EventHandlerPtr handler = event_registry->Register("spicy_analyzer_for_port"); + event_mgr.Enqueue(handler, vals); + }; + for ( const auto& ports : p.ports ) { const auto proto = ports.begin.protocol(); // Port ranges are closed intervals. for ( auto port = ports.begin.port(); port <= ports.end.port(); ++port ) { const auto port_ = hilti::rt::Port(port, proto); - SPICY_DEBUG(hilti::rt::fmt(" Scheduling analyzer for port %s", port_)); - analyzer_mgr->RegisterAnalyzerForPort(tag, transport_protocol(port_), port); + register_analyzer_for_port(tag, port_); // Don't double register in case of single-port ranges. if ( ports.begin.port() == ports.end.port() ) @@ -727,7 +744,7 @@ void Manager::InitPostScript() { continue; SPICY_DEBUG(hilti::rt::fmt(" Scheduling analyzer for port %s", port.port)); - analyzer_mgr->RegisterAnalyzerForPort(tag, transport_protocol(port.port), port.port.port()); + register_analyzer_for_port(tag, port.port); } } } diff --git a/src/spicy/manager.h b/src/spicy/manager.h index 118e03b6c3..55f47c51fd 100644 --- a/src/spicy/manager.h +++ b/src/spicy/manager.h @@ -85,7 +85,7 @@ public: * * @param name name of the analyzer as defined in its EVT file * @param proto analyzer's transport-layer protocol - * @param prts well-known ports for the analyzer; it'll be activated automatically for these + * @param ports well-known ports for the analyzer; it'll be activated automatically for these * @param parser_orig name of the Spicy parser for the originator side; must match the name that * Spicy registers the unit's parser with * @param parser_resp name of the Spicy parser for the originator side; must match the name that @@ -343,7 +343,7 @@ private: std::string name_parser_resp; std::string name_replaces; hilti::rt::Protocol protocol = hilti::rt::Protocol::Undef; - hilti::rt::Vector<::zeek::spicy::rt::PortRange> ports; + std::vector<::zeek::spicy::rt::PortRange> ports; // we keep this sorted std::string linker_scope; // Computed and available once the analyzer has been registered. diff --git a/src/spicy/port-range.h b/src/spicy/port-range.h index bbe0d58c12..7e71d433f8 100644 --- a/src/spicy/port-range.h +++ b/src/spicy/port-range.h @@ -19,6 +19,11 @@ struct PortRange { hilti::rt::Port begin; /**< first port in the range */ hilti::rt::Port end; /**< last port in the range */ + + bool operator<(const PortRange& other) const { + // Just get us a deterministic order. + return std::tie(begin, end) < std::tie(other.begin, other.end); + } }; inline bool operator==(const PortRange& a, const PortRange& b) { diff --git a/testing/btest/Baseline/core.check-unused-event-handlers/.stderr b/testing/btest/Baseline/core.check-unused-event-handlers/.stderr index 69f805dbf7..9fc3532832 100644 --- a/testing/btest/Baseline/core.check-unused-event-handlers/.stderr +++ b/testing/btest/Baseline/core.check-unused-event-handlers/.stderr @@ -22,5 +22,6 @@ warning in , line 1: event handler never invoked: SupervisorControl::res warning in , line 1: event handler never invoked: SupervisorControl::status_request warning in , line 1: event handler never invoked: SupervisorControl::stop_request warning in , line 1: event handler never invoked: spicy_analyzer_for_mime_type +warning in , line 1: event handler never invoked: spicy_analyzer_for_port warning in , line 1: event handler never invoked: terminate_event warning in , line 1: event handler never invoked: this_is_never_used diff --git a/testing/btest/Baseline/spicy.port-deprecated/out.stderr b/testing/btest/Baseline/spicy.port-deprecated/out.stderr deleted file mode 100644 index a033682601..0000000000 --- a/testing/btest/Baseline/spicy.port-deprecated/out.stderr +++ /dev/null @@ -1,2 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[warning] <...>/udp-test.evt:4: Remove in v7.1: Analyzer spicy::TEST is using the deprecated 'port' or 'ports' keyword to register well-known ports. Use Analyzer::register_for_ports() in the accompanying Zeek script instead. diff --git a/testing/btest/Baseline/spicy.port-fail/output b/testing/btest/Baseline/spicy.port-fail/output index f572d2e79a..24eb09807d 100644 --- a/testing/btest/Baseline/spicy.port-fail/output +++ b/testing/btest/Baseline/spicy.port-fail/output @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/port-fail.evt:9: port outside of valid range +[error] <...>/port-fail.evt:7: port outside of valid range [error] error loading EVT file "<...>/port-fail.evt" diff --git a/testing/btest/Baseline/spicy.port/output b/testing/btest/Baseline/spicy.port/output new file mode 100644 index 0000000000..938a6c7b35 --- /dev/null +++ b/testing/btest/Baseline/spicy.port/output @@ -0,0 +1,19 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +Analyzer::ANALYZER_SPICY_TEST, 11337/udp +Analyzer::ANALYZER_SPICY_TEST, 11338/udp +Analyzer::ANALYZER_SPICY_TEST, 11339/udp +Analyzer::ANALYZER_SPICY_TEST, 11340/udp +Analyzer::ANALYZER_SPICY_TEST, 31337/udp +Analyzer::ANALYZER_SPICY_TEST, 31338/udp +Analyzer::ANALYZER_SPICY_TEST, 31339/udp +Analyzer::ANALYZER_SPICY_TEST, 31340/udp +{ +31339/udp, +31337/udp, +31338/udp, +11339/udp, +11338/udp, +11340/udp, +31340/udp, +11337/udp +} diff --git a/testing/btest/spicy/port-deprecated.evt b/testing/btest/spicy/port-deprecated.evt deleted file mode 100644 index 220a9d1faf..0000000000 --- a/testing/btest/spicy/port-deprecated.evt +++ /dev/null @@ -1,21 +0,0 @@ -# @TEST-REQUIRES: have-spicy -# -# @TEST-EXEC: spicyz -d -o test.hlto ./udp-test.evt 2>out.stderr -# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out.stderr -# -# @TEST-DOC: Remove with v7.1: Specifying ports is deprecated. - -module Test; - -import zeek; - -public type Message = unit { - data: bytes &eod {} -}; - -# @TEST-START-FILE udp-test.evt -protocol analyzer spicy::TEST over UDP: - parse with Test::Message, - port 11337/udp-11340/udp, - ports {31337/udp-31340/udp}; -# @TEST-END-FILE diff --git a/testing/btest/spicy/port-fail.evt b/testing/btest/spicy/port-fail.evt index e51ca0fb79..f00efc6210 100644 --- a/testing/btest/spicy/port-fail.evt +++ b/testing/btest/spicy/port-fail.evt @@ -2,8 +2,6 @@ # # @TEST-EXEC-FAIL: spicyz %INPUT -d -o x.hlto >output 2>&1 # @TEST-EXEC: TEST_DIFF_CANONIFIER=diff-canonifier-spicy btest-diff output -# -# @TEST-DOC: Remove with v7.1 protocol analyzer spicy::SSH over TCP: port 123456/udp; diff --git a/testing/btest/spicy/port-range-one-port.zeek b/testing/btest/spicy/port-range-one-port.zeek index 95c32f2b27..bdc5219791 100644 --- a/testing/btest/spicy/port-range-one-port.zeek +++ b/testing/btest/spicy/port-range-one-port.zeek @@ -5,7 +5,7 @@ # @TEST-EXEC: grep -e 'Scheduling analyzer' -e 'error during parsing' < out > out.filtered # @TEST-EXEC: btest-diff out.filtered -# @TEST-DOC: Remove with v7.1. Expect a single 'Scheduling analyzer ...' message in the debug output and no parsing errors. There was a bug that 'port 31336/udp' would be wrongly interpreted as a 31336/udp-31337/udp port range. Regression test for #3278. +# @TEST-DOC: Expect a single 'Scheduling analyzer ...' message in the debug output and no parsing errors. There was a bug that 'port 31336/udp' would be wrongly interpreted as a 31336/udp-31337/udp port range. Regression test for #3278. # @TEST-START-FILE udp-test.spicy module UDPTest; diff --git a/testing/btest/spicy/port.zeek b/testing/btest/spicy/port.zeek new file mode 100644 index 0000000000..81d3586c68 --- /dev/null +++ b/testing/btest/spicy/port.zeek @@ -0,0 +1,32 @@ +# @TEST-REQUIRES: have-spicy +# +# @TEST-EXEC: spicyz -d -o test.hlto test.spicy test.evt +# @TEST-EXEC: zeek test.hlto %INPUT >output +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Check that we raise port events for Spicy analyzers, and that the ports get correctly registered. + +event spicy_analyzer_for_port(a: Analyzer::Tag, p: port){ + print a, p; +} + +event zeek_done() { + print Analyzer::ports[Analyzer::ANALYZER_SPICY_TEST]; +} + +# @TEST-START-FILE test.spicy +module Test; + +import zeek; + +public type Message = unit { + data: bytes &eod {} +}; +# @TEST-END-FILE + +# @TEST-START-FILE test.evt +protocol analyzer spicy::Test over UDP: + parse with Test::Message, + port 11337/udp-11340/udp, + ports {31337/udp-31340/udp}; +# @TEST-END-FILE From 74b832fa39e296402fe8fddc72c3d4609a8f8f2a Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 30 Aug 2024 14:39:46 -0700 Subject: [PATCH 38/41] Update docs submodule [nomail] [skip ci] --- doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc b/doc index b845bee39f..8039548924 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit b845bee39fa241892458d274184e2e9f22f4d096 +Subproject commit 8039548924d13b991a7329691fef4c64b03d13fc From 595cdf8b557013a3e04627c9bcbd7544b02e9199 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 2 Sep 2024 12:44:54 +0200 Subject: [PATCH 39/41] Bump auxil/spicy to latest release --- auxil/spicy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxil/spicy b/auxil/spicy index 7ddf6ce441..a1b7c78287 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit 7ddf6ce441d63aa5894dd11d9a5047ddc761de9a +Subproject commit a1b7c78287ecb29cf17a3ef8a94125d87eadb152 From 89b9f9a456fbaeac84f2c1e65c142fef4182d0d1 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 3 Sep 2024 13:03:51 -0700 Subject: [PATCH 40/41] Update zeek-aux submodule to pick up zeek-archiver permissions fix --- auxil/zeek-aux | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxil/zeek-aux b/auxil/zeek-aux index 8a66cd60fb..e850412ab5 160000 --- a/auxil/zeek-aux +++ b/auxil/zeek-aux @@ -1 +1 @@ -Subproject commit 8a66cd60fb29a1237b5070854cb194f43a3f7a30 +Subproject commit e850412ab5dea10ee2ebb98e42527d80fcf9a7ed From 3bf8bfaac6784105d0c3cbbc18cf1d27952da81f Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 3 Sep 2024 13:04:23 -0700 Subject: [PATCH 41/41] Update CHANGES, VERSION, and NEWS for 7.0.1 release --- CHANGES | 6 ++++++ NEWS | 20 ++++++++++++++++++++ VERSION | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 8a1d0481dc..a124a7824b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +7.0.1 | 2024-09-03 13:04:23 -0700 + + * Update CHANGES, VERSION, and NEWS for 7.0.1 release (Tim Wojtulewicz, Corelight) + + * Update zeek-aux submodule to pick up zeek-archiver permissions fix (Tim Wojtulewicz, Corelight) + 7.0.0-14 | 2024-09-03 09:02:19 -0700 * Bump auxil/spicy to latest release (Benjamin Bannier, Corelight) diff --git a/NEWS b/NEWS index 57a02b61a0..dd0c324b26 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,26 @@ This document summarizes the most important changes in the current Zeek release. For an exhaustive list of changes, see the ``CHANGES`` file (note that submodules, such as Broker, come with their own ``CHANGES``.) +Zeek 7.0.1 +========== + +This release fixes the following bugs: + +- HTTP passwords with colon characters in them are now correctly logged. + +- The LDAP analyzer now supports handling of non-sealed GSS-API WRAP tokens. + +- Heuristics for parsing SASL encrypted and signed LDAP traffic have been made + more strict and predictable. Please provide input if this results in less + visibility in your environment. + +- StartTLS support was added to the LDAP analyzer. The SSL analyzer is enabled + for connections where client and server negotiate to TLS through the extended + request/response mechanism. + +- Specify less-strict permissions for directories and files created by + zeek-archiver to play more nicely with user's umask setting. + Zeek 7.0.0 ========== diff --git a/VERSION b/VERSION index fb81d6448a..9fe9ff9d99 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-14 +7.0.1