From 080d7418d734356fe1dc61e29facf998f251d80b Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 08:15:43 +0200 Subject: [PATCH 01/20] Import zeek/spicy-ldap@57b5eff9883d1c43896f4278218351a132de9ce1 --- src/spicy/spicy-ldap/.cmake-format.json | 26 + .../spicy-ldap/.github/workflows/check.yml | 35 + .../.github/workflows/pre-commit.yml | 14 + src/spicy/spicy-ldap/.gitignore | 7 + src/spicy/spicy-ldap/.mdlrc | 1 + src/spicy/spicy-ldap/.pre-commit-config.yaml | 23 + src/spicy/spicy-ldap/CMakeLists.txt | 18 + src/spicy/spicy-ldap/LICENSE | 29 + src/spicy/spicy-ldap/README.md | 74 ++ src/spicy/spicy-ldap/analyzer/CMakeLists.txt | 5 + src/spicy/spicy-ldap/analyzer/__load__.zeek | 2 + src/spicy/spicy-ldap/analyzer/asn1.spicy | 278 ++++++ src/spicy/spicy-ldap/analyzer/dpd.sig | 23 + src/spicy/spicy-ldap/analyzer/ldap.evt | 43 + src/spicy/spicy-ldap/analyzer/ldap.spicy | 871 ++++++++++++++++++ src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy | 14 + src/spicy/spicy-ldap/analyzer/main.zeek | 502 ++++++++++ .../spicy-ldap/cmake/FindSpicyPlugin.cmake | 78 ++ .../spicy-ldap/tests/analyzer/attributes.zeek | 13 + .../tests/analyzer/availability.zeek | 5 + .../spicy-ldap/tests/analyzer/basic.zeek | 12 + .../spicy-ldap/tests/analyzer/diff_port.zeek | 11 + .../spicy-ldap/tests/analyzer/functions.spicy | 131 +++ .../spicy-ldap/tests/analyzer/log_policy.zeek | 23 + .../tests/analyzer/sasl-encrypted.zeek | 13 + .../analyzer/search_filter_extended.zeek | 10 + .../baseline/analyzer.attributes/conn.log | 12 + .../baseline/analyzer.attributes/ldap.log | 13 + .../analyzer.attributes/ldap_search.log | 12 + .../tests/baseline/analyzer.basic/conn.log | 12 + .../tests/baseline/analyzer.basic/ldap.log | 13 + .../baseline/analyzer.basic/ldap_search.log | 12 + .../tests/baseline/analyzer.basic/output | 2 + .../baseline/analyzer.diff_port/conn.log | 12 + .../baseline/analyzer.diff_port/ldap.log | 13 + .../analyzer.diff_port/ldap_search.log | 12 + .../baseline/analyzer.log_policy/conn.log | 12 + .../tests/baseline/analyzer.log_policy/output | 2 + .../tests/baseline/analyzer.parse/output | 4 + .../baseline/analyzer.sasl-encrypted/conn.log | 12 + .../baseline/analyzer.sasl-encrypted/ldap.log | 12 + .../analyzer.sasl-encrypted/ldap_search.log | 12 + .../ldap_search.log | 12 + src/spicy/spicy-ldap/tests/btest.cfg | 34 + .../tests/scripts/zeek-path-install | 5 + src/spicy/spicy-ldap/tests/traces/README | 15 + .../spicy-ldap/tests/traces/issue-32.pcapng | Bin 0 -> 1436 bytes .../tests/traces/ldap-issue-32.pcapng | Bin 0 -> 1436 bytes .../tests/traces/ldap-krb5-sign-seal-01.pcap | Bin 0 -> 4957 bytes .../traces/ldap-simpleauth-diff-port.pcap | Bin 0 -> 1390 bytes .../tests/traces/ldap-simpleauth.pcap | Bin 0 -> 1390 bytes src/spicy/spicy-ldap/zkg.meta | 21 + .../ldap_search.log | 11 + 53 files changed, 2526 insertions(+) create mode 100644 src/spicy/spicy-ldap/.cmake-format.json create mode 100644 src/spicy/spicy-ldap/.github/workflows/check.yml create mode 100644 src/spicy/spicy-ldap/.github/workflows/pre-commit.yml create mode 100644 src/spicy/spicy-ldap/.gitignore create mode 100644 src/spicy/spicy-ldap/.mdlrc create mode 100644 src/spicy/spicy-ldap/.pre-commit-config.yaml create mode 100644 src/spicy/spicy-ldap/CMakeLists.txt create mode 100644 src/spicy/spicy-ldap/LICENSE create mode 100644 src/spicy/spicy-ldap/README.md create mode 100644 src/spicy/spicy-ldap/analyzer/CMakeLists.txt create mode 100644 src/spicy/spicy-ldap/analyzer/__load__.zeek create mode 100644 src/spicy/spicy-ldap/analyzer/asn1.spicy create mode 100644 src/spicy/spicy-ldap/analyzer/dpd.sig create mode 100644 src/spicy/spicy-ldap/analyzer/ldap.evt create mode 100644 src/spicy/spicy-ldap/analyzer/ldap.spicy create mode 100644 src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy create mode 100644 src/spicy/spicy-ldap/analyzer/main.zeek create mode 100644 src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake create mode 100644 src/spicy/spicy-ldap/tests/analyzer/attributes.zeek create mode 100644 src/spicy/spicy-ldap/tests/analyzer/availability.zeek create mode 100644 src/spicy/spicy-ldap/tests/analyzer/basic.zeek create mode 100644 src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek create mode 100644 src/spicy/spicy-ldap/tests/analyzer/functions.spicy create mode 100644 src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek create mode 100644 src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek create mode 100644 src/spicy/spicy-ldap/tests/analyzer/search_filter_extended.zeek create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.log create mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log create mode 100644 src/spicy/spicy-ldap/tests/btest.cfg create mode 100755 src/spicy/spicy-ldap/tests/scripts/zeek-path-install create mode 100644 src/spicy/spicy-ldap/tests/traces/README create mode 100644 src/spicy/spicy-ldap/tests/traces/issue-32.pcapng create mode 100644 src/spicy/spicy-ldap/tests/traces/ldap-issue-32.pcapng create mode 100644 src/spicy/spicy-ldap/tests/traces/ldap-krb5-sign-seal-01.pcap create mode 100644 src/spicy/spicy-ldap/tests/traces/ldap-simpleauth-diff-port.pcap create mode 100644 src/spicy/spicy-ldap/tests/traces/ldap-simpleauth.pcap create mode 100644 src/spicy/spicy-ldap/zkg.meta create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log diff --git a/src/spicy/spicy-ldap/.cmake-format.json b/src/spicy/spicy-ldap/.cmake-format.json new file mode 100644 index 0000000000..42b1e14fe9 --- /dev/null +++ b/src/spicy/spicy-ldap/.cmake-format.json @@ -0,0 +1,26 @@ +{ + "parse": { + "additional_commands": { + "spicy_add_analyzer": { + "kwargs": { + "NAME": "*", + "PACKAGE_NAME": "*", + "SOURCES": "*", + "SCRIPTS": "*" + } + } + } + }, + "format": { + "line_width": 100, + "tab_size": 4, + "separate_ctrl_name_with_space": true, + "max_subgroups_hwrap": 3 + }, + "markup": { + "enable_markup": false + }, + "lint": { + "disabled_codes": ["C0103"] + } +} diff --git a/src/spicy/spicy-ldap/.github/workflows/check.yml b/src/spicy/spicy-ldap/.github/workflows/check.yml new file mode 100644 index 0000000000..53c9e3ddd1 --- /dev/null +++ b/src/spicy/spicy-ldap/.github/workflows/check.yml @@ -0,0 +1,35 @@ +on: + pull_request: + push: + branches: [main] + +jobs: + Check: + strategy: + matrix: + version: + - zeek:6.0 + - zeek-dev:latest + + fail-fast: false + + runs-on: ubuntu-latest + container: zeek/${{ matrix.version }} + + steps: + - uses: actions/checkout@v2 + - name: Prepare + run: | + apt-get update + apt-get install -y -q --no-install-recommends g++ cmake make libpcap-dev + - name: Install + run: | + git config --global --add safe.directory $PWD + git clean -fd + eval $(zkg env) + echo Y | zkg -vvvvv install . + + - name: Show logs + if: always() + run: | + tail -n 1000000 $(zkg config state_dir)/logs/*.log diff --git a/src/spicy/spicy-ldap/.github/workflows/pre-commit.yml b/src/spicy/spicy-ldap/.github/workflows/pre-commit.yml new file mode 100644 index 0000000000..9035d06925 --- /dev/null +++ b/src/spicy/spicy-ldap/.github/workflows/pre-commit.yml @@ -0,0 +1,14 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [main] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - uses: pre-commit/action@v2.0.3 diff --git a/src/spicy/spicy-ldap/.gitignore b/src/spicy/spicy-ldap/.gitignore new file mode 100644 index 0000000000..648505ab7b --- /dev/null +++ b/src/spicy/spicy-ldap/.gitignore @@ -0,0 +1,7 @@ +build +.idea/ +cmake-build-debug/ +.DS_Store +*.swp +*.tmp +tests/.btest* diff --git a/src/spicy/spicy-ldap/.mdlrc b/src/spicy/spicy-ldap/.mdlrc new file mode 100644 index 0000000000..da394dc3f2 --- /dev/null +++ b/src/spicy/spicy-ldap/.mdlrc @@ -0,0 +1 @@ +rules "~MD033", "~MD013", "~MD046", "~MD010" diff --git a/src/spicy/spicy-ldap/.pre-commit-config.yaml b/src/spicy/spicy-ldap/.pre-commit-config.yaml new file mode 100644 index 0000000000..0ad081b7b4 --- /dev/null +++ b/src/spicy/spicy-ldap/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + +- repo: https://github.com/markdownlint/markdownlint + rev: v0.11.0 + hooks: + - id: markdownlint + +- repo: https://github.com/cheshirekow/cmake-format-precommit + rev: v0.6.13 + hooks: + - id: cmake-format + - id: cmake-lint + +exclude: '^tests/Baseline' diff --git a/src/spicy/spicy-ldap/CMakeLists.txt b/src/spicy/spicy-ldap/CMakeLists.txt new file mode 100644 index 0000000000..ee8767848a --- /dev/null +++ b/src/spicy/spicy-ldap/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15 FATAL_ERROR) + +project(Messages LANGUAGES C) + +list(PREPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") +find_package(SpicyPlugin REQUIRED) + +# Set mininum versions that this plugin needs. Make sure to use "x.y.z" format. +spicy_require_version("1.2.0") +spicy_plugin_require_version("0.99.0") +zeek_require_version("3.0.0") + +if (NOT CMAKE_BUILD_TYPE) + # Default to release build. + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") +endif () + +add_subdirectory(analyzer) diff --git a/src/spicy/spicy-ldap/LICENSE b/src/spicy/spicy-ldap/LICENSE new file mode 100644 index 0000000000..f32436e280 --- /dev/null +++ b/src/spicy/spicy-ldap/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2020-2021 by the Zeek Project through the International Computer +Science Institute. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +(1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +(2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +(3) Neither the name of the Zeek Project, the International Computer + Science Institute, nor the names of contributors may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/spicy/spicy-ldap/README.md b/src/spicy/spicy-ldap/README.md new file mode 100644 index 0000000000..dc97e6575a --- /dev/null +++ b/src/spicy/spicy-ldap/README.md @@ -0,0 +1,74 @@ +LDAP Analyzer +============= + +Here's what it has: + +- ASN.1 structure decoding: this is probably generally useful for more than just the LDAP parser, so it may be of interest for this to be included somehow as part of spicy's standard modules or whatever + - everything is working except for the "constructed" forms of `ASN1BitString` and `ASN1OctetString` +- LDAP: the LDAP parsing is basically "done once" through a single call to `ASN1Message` (which parses itself recursively) and then the application-level data is also parsed via `&parse-from` a byte array belonging to the outer ASN.1 sequence. This second level of parsing is also done using the ASN.1 data types. + - events + - `ldap::message` - called for each LDAP message + - `ldap::bindreq` - when a bind request is made + - `ldap::searchreq` - basic search request information + - `ldap::searchres` - called each time a search result is returned + - enums + - `ProtocolOpcode` + - `ResultCode` + - `BindAuthType` + - `SearchScope` + - `SearchDerefAlias` + - `FilterType` + - Zeek log files + - `ldap.log` - contains information about all LDAP messages except those that are search-related. Log lines are grouped by connection ID + message ID + - `ts` (time) + - `uid` (connection UID) + - `id` (connection ID 4-tuple) + - `proto` (transport protocol) + - `message_id` (LDAP message ID) + - `version` (LDAP version for bind requests) + - `opcode` (set of 1..n operations from this uid+message_id) + - `result` (set of 1..n results from this uid+message_id) + - `diagnostic_message` (vector of 0..n diagnostic message strings) + - `object` (vector of 0..n "objects," the meaning of which depends on the operation) + - `argument` (vector of 0..n "argument," the meaning of which depends on the operation) + - `ldap_search.log` - contains information about LDAP searches. Log lines are grouped by connection ID + message ID + - `ts` (time) + - `uid` (connection UID) + - `id` (connection ID 4-tuple) + - `proto` (transport protocol) + - `message_id` (LDAP message ID) + - `scope` (set of 1..n search scopes defined in this uid+message_id) + - `deref` (set of 1..n search deref alias options defined in this uid+message_id) + - `base_object` (vector of 0..n search base objects specified) + - `result_count` (number of result entries returned) + - `result` (set of 1..n results from this uid+message_id) + - `diagnostic_message` (vector of 0..n diagnostic message strings) + - `filter` (search filter string) + - `attributes` (vector of 0..n "attributes", the attributes that were returned) + - test + - basic tests for detecting plugin presence and simple bind and search result/requests + +Here's what it doesn't have, which could be added by future parties interested in expanding it: + +- LDAP [referrals](https://tools.ietf.org/html/rfc4511#section-4.1.10) are not parsed out of the results +- [SASL credentials](https://datatracker.ietf.org/doc/html/rfc4511#section-4.2) in bind requests are not being parsed beyond the mechanism string +- SASL information in bind responses are not being parsed; for that matter, SASL-based LDAP stuff hasn't been tested much and may have issues +- Search filters and attributes: the search filters, reconstructed from the query tree, is represented in string format. The AND and OR filters have a tree structure and are parsed with the `ParseNestedAndOr` unit, whereas the NOT filter consist of one single nested SearchFilter and is parsed with a `ParseNestedNot` unit. The remaining filter types can all be decoded to a string using the `DecodedAttributeValue` unit, which takes the `FilterType` as a parameter. The `FILTER_PRESENT` consists of a single octet string and can be parsed directly. By recursively constructing leafs and nodes in the tree, the final search filter can be represented, e.g. `(&(objectclass=*)(sAMAccountName=xxxxxxxx))`. The returned attributes are represented in a list and returned to the `ldap_search.log` if `option default_log_search_attributes = T;` is set (the default is False). +- the details of `SearchResultReference` are not being parsed +- the only detail of `ModifyRequest` being parsed is the object name +- the details of `AddRequest` are not being parsed +- the details of `ModDNRequest` are not being parsed +- the details of `CompareRequest` are not being parsed +- the details of `AbandonRequest` are not being parsed +- the details of `ExtendedRequest` are not being parsed +- the details of `ExtendedResponse` are not being parsed +- the details of `IntermediateResponse` are not being parsed +- [Logging policy](https://docs.zeek.org/en/master/frameworks/logging.html#filtering-log-records) is available. + +Useful Links: + +- +- +- +- +- diff --git a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt new file mode 100644 index 0000000000..094fe4aecb --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt @@ -0,0 +1,5 @@ +spicy_add_analyzer( + NAME LDAP + PACKAGE_NAME spicy-ldap + SOURCES ldap.spicy ldap.evt ldap_zeek.spicy + SCRIPTS __load__.zeek main.zeek dpd.sig) diff --git a/src/spicy/spicy-ldap/analyzer/__load__.zeek b/src/spicy/spicy-ldap/analyzer/__load__.zeek new file mode 100644 index 0000000000..4f7f22c492 --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/__load__.zeek @@ -0,0 +1,2 @@ +@load-sigs ./dpd.sig +@load ./main.zeek diff --git a/src/spicy/spicy-ldap/analyzer/asn1.spicy b/src/spicy/spicy-ldap/analyzer/asn1.spicy new file mode 100644 index 0000000000..001c131e25 --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/asn1.spicy @@ -0,0 +1,278 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +module ASN1; + +############################################################################### +# ASN.1 structure decoding +# +# A Layman's Guide to a Subset of ASN.1, BER, and DER +# http://luca.ntop.org/Teaching/Appunti/asn1.html +# +# ASN.1 Tutorial from Computer Networks and Open Systems: +# An Application Development Perspective +# https://www.obj-sys.com/asn1tutorial/asn1only.html +# +# The ASN1JS tool (http://lapo.it/asn1js and https://github.com/lapo-luchini/asn1js) +# is invaluable in debugging ASN.1 +############################################################################### + +import spicy; + +#- ASN.1 data types ---------------------------------------------------------- +# https://www.obj-sys.com/asn1tutorial/node124.html +# https://www.obj-sys.com/asn1tutorial/node10.html + +public type ASN1Type = enum { + Boolean = 1, + Integer = 2, + BitString = 3, + OctetString = 4, + NullVal = 5, + ObjectIdentifier = 6, + ObjectDescriptor = 7, + InstanceOf = 8, + Real = 9, + Enumerated = 10, + EmbeddedPDV = 11, + UTF8String = 12, + RelativeOID = 13, + Sequence = 16, + Set = 17, + NumericString = 18, + PrintableString = 19, + TeletextString = 20, + VideotextString = 21, + IA5String = 22, + UTCTime = 23, + GeneralizedTime = 24, + GraphicString = 25, + VisibleString = 26, + GeneralString = 27, + UniversalString = 28, + CharacterString = 29, + BMPString = 30 +}; + +#- ASN.1 data classes -------------------------------------------------------- + +public type ASN1Class = enum { + Universal = 0, + Application = 1, + ContextSpecific = 2, + Private = 3 +}; + +#- ASN.1 tag definition (including length) ------------------------------------ + +type LengthType = unit { + var len: uint64; + var tag_len: uint8; + + data : bitfield(8) { + num: 0..6; + islong: 7; + }; + + + switch ( self.data.islong ) { + 0 -> : void { + self.len = self.data.num; + self.tag_len = 1; + } + 1 -> : bytes &size=self.data.num + &convert=$$.to_uint(spicy::ByteOrder::Network) { + self.len = $$; + self.tag_len = self.data.num + 1; + } + }; +}; + +type ASN1Tag = unit { + : bitfield(8) { + type_: 0..4 &convert=ASN1Type($$); + constructed: 5 &convert=cast($$); + class: 6..7 &convert=ASN1Class($$); + }; +}; + +#- ASN.1 bit string ----------------------------------------------------------- +# https://www.obj-sys.com/asn1tutorial/node10.html + +type ASN1BitString = unit(len: uint64, constructed: bool) { + : uint8; # unused bits + value_bits: bytes &size=(len - 1); + + # TODO - constructed form + # https://github.com/zeek/spicy/issues/921 + # `bytes` needs << and >> support before we can implement complex bitstrings + # +}; + +#- ASN.1 octet string --------------------------------------------------------- +# https://www.obj-sys.com/asn1tutorial/node10.html + +type ASN1OctetString = unit(len: uint64, constructed: bool) { + value: bytes &size = len; + + # TODO - constructed form +}; + +#- ASN.1 various string types ------------------------------------------------- +# https://www.obj-sys.com/asn1tutorial/node124.html + +type ASN1String = unit(tag: ASN1Tag, len: uint64) { + var encoding: hilti::Charset; + + on %init { + switch ( tag.type_ ) { + # see "Restricted Character String Types" in + # "Generic String Encoding Rules (GSER) for ASN.1 Types" + # (https://datatracker.ietf.org/doc/html/rfc3641#section-3.2) + + case ASN1Type::PrintableString, + ASN1Type::GeneralizedTime, + ASN1Type::UTCTime: { + self.encoding = hilti::Charset::ASCII; + } + + case ASN1Type::UTF8String, + ASN1Type::GeneralString, + ASN1Type::CharacterString, + ASN1Type::GraphicString, + ASN1Type::IA5String, + ASN1Type::NumericString, + ASN1Type::TeletextString, + ASN1Type::VideotextString, + ASN1Type::VisibleString, + # TODO: RFC3641 mentions special UTF-8 mapping rules for + # BMPString and UniversalString. This *may* not be correct. + ASN1Type::BMPString, + ASN1Type::UniversalString: { + self.encoding = hilti::Charset::UTF8; + } + } + } + + value: ASN1OctetString(len, tag.constructed) &convert=$$.value.decode(self.encoding); +} &convert=self.value; + +#- ASN.1 OID ------------------------------------------------------------------ +# https://www.obj-sys.com/asn1tutorial/node124.html + +type ASN1ObjectIdentifierNibble = unit { + data : bitfield(8) { + num: 0..6; + more: 7; + }; +} &convert=self.data; + +type ASN1ObjectIdentifier = unit(len: uint64) { + var oid: vector; + var temp: uint64; + var oidstring: string; + + : uint8 if ( len >= 1 ) { + self.temp = $$ / 40; + self.oid.push_back( self.temp ); + self.oidstring = "%d" % (self.temp); + self.temp = $$ % 40; + self.oid.push_back( self.temp ); + self.oidstring = self.oidstring + ".%d" % (self.temp); + self.temp = 0; + } + + sublist: ASN1ObjectIdentifierNibble[len - 1] foreach { + self.temp = ( self.temp<<7 ) | $$.num; + if ( $$.more != 1 ) { + self.oid.push_back(self.temp); + self.oidstring = self.oidstring + ".%d" % (self.temp); + self.temp = 0; + } + } +}; + + +#- ASN.1 message header (tag + length information) ---------------------------- + +public type ASN1Header = unit { + tag: ASN1Tag; + len: LengthType; +}; + +#- ASN.1 message body --------------------------------------------------------- + +public type ASN1Body = unit(head: ASN1Header, recursive: bool) { + switch ( head.tag.type_ ) { + + ASN1Type::Boolean -> bool_value: uint8 &convert=cast($$) &requires=head.len.len==1; + + ASN1Type::Integer, + ASN1Type::Enumerated -> num_value: bytes &size=head.len.len + &convert=$$.to_int(spicy::ByteOrder::Big); + + ASN1Type::NullVal -> null_value: bytes &size=0 &requires=head.len.len==0; + + ASN1Type::BitString -> bitstr_value: ASN1BitString(head.len.len, head.tag.constructed); + + ASN1Type::OctetString -> str_value: ASN1OctetString(head.len.len, head.tag.constructed) + &convert=$$.value.decode(hilti::Charset::ASCII); + + ASN1Type::ObjectIdentifier -> str_value: ASN1ObjectIdentifier(head.len.len) + &convert=$$.oidstring; + + ASN1Type::BMPString, + ASN1Type::CharacterString, + ASN1Type::GeneralizedTime, + ASN1Type::GeneralString, + ASN1Type::GraphicString, + ASN1Type::IA5String, + ASN1Type::NumericString, + ASN1Type::PrintableString, + ASN1Type::TeletextString, + ASN1Type::UTCTime, + ASN1Type::UTF8String, + ASN1Type::VideotextString, + ASN1Type::VisibleString, + ASN1Type::UniversalString -> str_value: ASN1String(head.tag, head.len.len); + + ASN1Type::Sequence, ASN1Type::Set -> seq: ASN1SubMessages(head.len.len) if (recursive); + + # TODO: ASN1Type values not handled yet + ASN1Type::ObjectDescriptor, + ASN1Type::InstanceOf, + ASN1Type::Real, + ASN1Type::EmbeddedPDV, + ASN1Type::RelativeOID -> unimplemented_value: bytes &size=head.len.len; + + # unknown (to me) ASN.1 enumeration, skip over silently + * -> unimplemented_value: bytes &size=head.len.len; + }; +}; + +#- ASN.1 array of ASN.1 sequence/set sub-messages (up to msgLen bytes) -------- + +public type ASN1SubMessages = unit(msgLen: uint64) { + submessages: ASN1Message(True)[] &eod; +} &size=msgLen; + +#- ASN.1 message with header and body ----------------------------------------- +# Universal or Application/ContextSpecific/Private +# - if Universal, body:ASN1Body is parsed +# - else, application_data:bytes stores data array + +public type ASN1Message = unit(recursive: bool) { + var application_id: int32; + + head: ASN1Header; + switch ( self.head.tag.class ) { + + ASN1Class::Universal -> body: ASN1Body(self.head, recursive); + + ASN1Class::Application, + ASN1Class::ContextSpecific, + ASN1Class::Private -> application_data: bytes &size=self.head.len.len { + self.application_id = cast(self.head.tag.type_); + } + + }; +}; diff --git a/src/spicy/spicy-ldap/analyzer/dpd.sig b/src/spicy/spicy-ldap/analyzer/dpd.sig new file mode 100644 index 0000000000..dc734e5554 --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/dpd.sig @@ -0,0 +1,23 @@ +signature dpd_ldap_client_udp { + ip-proto == udp + payload /^\x30.\x02\x01.\x60/ +} + +signature dpd_ldap_server_udp { + ip-proto == udp + payload /^\x30/ + requires-reverse-signature dpd_ldap_client_udp + enable "spicy_LDAP_UDP" +} + +signature dpd_ldap_client_tcp { + ip-proto == tcp + payload /^\x30.\x02\x01.\x60/ +} + +signature dpd_ldap_server_tcp { + ip-proto == tcp + payload /^\x30/ + requires-reverse-signature dpd_ldap_client_tcp + enable "spicy_LDAP_TCP" +} diff --git a/src/spicy/spicy-ldap/analyzer/ldap.evt b/src/spicy/spicy-ldap/analyzer/ldap.evt new file mode 100644 index 0000000000..d255783998 --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/ldap.evt @@ -0,0 +1,43 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +protocol analyzer spicy::LDAP_TCP over TCP: + parse with LDAP::Messages, + ports { 389/tcp, 3268/tcp}; + +protocol analyzer spicy::LDAP_UDP over UDP: + parse with LDAP::Messages, + ports { 389/udp }; + +import LDAP; +import LDAP_Zeek; + +on LDAP::Message -> event LDAP::message($conn, + self.messageID, + self.opcode, + self.result.code, + self.result.matchedDN, + self.result.diagnosticMessage, + self.obj, + self.arg); + +on LDAP::BindRequest -> event LDAP::bindreq($conn, + message.messageID, + self.version, + self.name, + self.authType, + message.arg); + +on LDAP::SearchRequest -> event LDAP::searchreq($conn, + message.messageID, + self.baseObject, + self.scope, + self.deref, + self.sizeLimit, + self.timeLimit, + self.typesOnly, + self.filter, + self.attributes); + +on LDAP::SearchResultEntry -> event LDAP::searchres($conn, + message.messageID, + self.objectName); diff --git a/src/spicy/spicy-ldap/analyzer/ldap.spicy b/src/spicy/spicy-ldap/analyzer/ldap.spicy new file mode 100644 index 0000000000..a7be8af911 --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/ldap.spicy @@ -0,0 +1,871 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +module LDAP; + +import ASN1; +import spicy; + +# https://tools.ietf.org/html/rfc4511# +# https://ldap.com/ldapv3-wire-protocol-reference-asn1-ber/ +# https://lapo.it/asn1js + +#- Operation opcode ---------------------------------------------------------- +public type ProtocolOpcode = enum { + BIND_REQUEST = 0, + BIND_RESPONSE = 1, + UNBIND_REQUEST = 2, + SEARCH_REQUEST = 3, + SEARCH_RESULT_ENTRY = 4, + SEARCH_RESULT_DONE = 5, + MODIFY_REQUEST = 6, + MODIFY_RESPONSE = 7, + ADD_REQUEST = 8, + ADD_RESPONSE = 9, + DEL_REQUEST = 10, + DEL_RESPONSE = 11, + MOD_DN_REQUEST = 12, + MOD_DN_RESPONSE = 13, + COMPARE_REQUEST = 14, + COMPARE_RESPONSE = 15, + ABANDON_REQUEST = 16, + SEARCH_RESULT_REFERENCE = 19, + EXTENDED_REQUEST = 23, + EXTENDED_RESPONSE = 24, + INTERMEDIATE_RESPONSE = 25, +}; + +#- Result code --------------------------------------------------------------- +public type ResultCode = enum { + SUCCESS = 0, + OPERATIONS_ERROR = 1, + PROTOCOL_ERROR = 2, + TIME_LIMIT_EXCEEDED = 3, + SIZE_LIMIT_EXCEEDED = 4, + COMPARE_FALSE = 5, + COMPARE_TRUE = 6, + AUTH_METHOD_NOT_SUPPORTED = 7, + STRONGER_AUTH_REQUIRED = 8, + PARTIAL_RESULTS = 9, + REFERRAL = 10, + ADMIN_LIMIT_EXCEEDED = 11, + UNAVAILABLE_CRITICAL_EXTENSION = 12, + CONFIDENTIALITY_REQUIRED = 13, + SASL_BIND_IN_PROGRESS = 14, + NO_SUCH_ATTRIBUTE = 16, + UNDEFINED_ATTRIBUTE_TYPE = 17, + INAPPROPRIATE_MATCHING = 18, + CONSTRAINT_VIOLATION = 19, + ATTRIBUTE_OR_VALUE_EXISTS = 20, + INVALID_ATTRIBUTE_SYNTAX = 21, + NO_SUCH_OBJECT = 32, + ALIAS_PROBLEM = 33, + INVALID_DNSYNTAX = 34, + ALIAS_DEREFERENCING_PROBLEM = 36, + INAPPROPRIATE_AUTHENTICATION = 48, + INVALID_CREDENTIALS = 49, + INSUFFICIENT_ACCESS_RIGHTS = 50, + BUSY = 51, + UNAVAILABLE = 52, + UNWILLING_TO_PERFORM = 53, + LOOP_DETECT = 54, + SORT_CONTROL_MISSING = 60, + OFFSET_RANGE_ERROR = 61, + NAMING_VIOLATION = 64, + OBJECT_CLASS_VIOLATION = 65, + NOT_ALLOWED_ON_NON_LEAF = 66, + NOT_ALLOWED_ON_RDN = 67, + ENTRY_ALREADY_EXISTS = 68, + OBJECT_CLASS_MODS_PROHIBITED = 69, + RESULTS_TOO_LARGE = 70, + AFFECTS_MULTIPLE_DSAS = 71, + CONTROL_ERROR = 76, + OTHER = 80, + SERVER_DOWN = 81, + LOCAL_ERROR = 82, + ENCODING_ERROR = 83, + DECODING_ERROR = 84, + TIMEOUT = 85, + AUTH_UNKNOWN = 86, + FILTER_ERROR = 87, + USER_CANCELED = 88, + PARAM_ERROR = 89, + NO_MEMORY = 90, + CONNECT_ERROR = 91, + NOT_SUPPORTED = 92, + CONTROL_NOT_FOUND = 93, + NO_RESULTS_RETURNED = 94, + MORE_RESULTS_TO_RETURN = 95, + CLIENT_LOOP = 96, + REFERRAL_LIMIT_EXCEEDED = 97, + INVALID_RESPONSE = 100, + AMBIGUOUS_RESPONSE = 101, + TLS_NOT_SUPPORTED = 112, + INTERMEDIATE_RESPONSE = 113, + UNKNOWN_TYPE = 114, + LCUP_INVALID_DATA = 115, + LCUP_UNSUPPORTED_SCHEME = 116, + LCUP_RELOAD_REQUIRED = 117, + CANCELED = 118, + NO_SUCH_OPERATION = 119, + TOO_LATE = 120, + CANNOT_CANCEL = 121, + ASSERTION_FAILED = 122, + AUTHORIZATION_DENIED = 123, +}; + +#----------------------------------------------------------------------------- +public type Result = unit { + code: ASN1::ASN1Message(True) &convert=cast(cast($$.body.num_value)) + &default=ResultCode::Undef; + matchedDN: ASN1::ASN1Message(True) &convert=$$.body.str_value + &default=""; + diagnosticMessage: ASN1::ASN1Message(True) &convert=$$.body.str_value + &default=""; + + # TODO: if we want to parse referral URIs in result + # https://tools.ietf.org/html/rfc4511#section-4.1.10 +}; + +#----------------------------------------------------------------------------- +public type Messages = unit { + : MessageWrapper[]; +}; + +#----------------------------------------------------------------------------- +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; + } + + on %error { + self.backtrack(); + } +}; + +#----------------------------------------------------------------------------- +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 + + # This success variable is different, because this keeps track of the status for the MessageWrapper object + var success: bool = False; + var message: Message; + + # Here, we try to parse the message... + : Message &try { + + # ... 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 = $$; + } + } + + # 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). + + # 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 delimeter was not found, we + # leave the remainer 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; + +#----------------------------------------------------------------------------- +public type Message = unit { + 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; + + : 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; + } + } + } + + switch ( self.opcode ) { + ProtocolOpcode::BIND_REQUEST -> BIND_REQUEST: BindRequest(self); + ProtocolOpcode::BIND_RESPONSE -> BIND_RESPONSE: BindResponse(self); + ProtocolOpcode::UNBIND_REQUEST -> UNBIND_REQUEST: UnbindRequest(self); + ProtocolOpcode::SEARCH_REQUEST -> SEARCH_REQUEST: SearchRequest(self); + ProtocolOpcode::SEARCH_RESULT_ENTRY -> SEARCH_RESULT_ENTRY: SearchResultEntry(self); + ProtocolOpcode::SEARCH_RESULT_DONE -> SEARCH_RESULT_DONE: SearchResultDone(self); + ProtocolOpcode::MODIFY_REQUEST -> MODIFY_REQUEST: ModifyRequest(self); + ProtocolOpcode::MODIFY_RESPONSE -> MODIFY_RESPONSE: ModifyResponse(self); + ProtocolOpcode::ADD_RESPONSE -> ADD_RESPONSE: AddResponse(self); + ProtocolOpcode::DEL_REQUEST -> DEL_REQUEST: DelRequest(self); + ProtocolOpcode::DEL_RESPONSE -> DEL_RESPONSE: DelResponse(self); + ProtocolOpcode::MOD_DN_RESPONSE -> MOD_DN_RESPONSE: ModDNResponse(self); + ProtocolOpcode::COMPARE_RESPONSE -> COMPARE_RESPONSE: CompareResponse(self); + ProtocolOpcode::ABANDON_REQUEST -> ABANDON_REQUEST: AbandonRequest(self); + + # TODO: not yet implemented, redirect to NotImplemented because when we're + # 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::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 ); + + on %error { + self.backtrack(); + } + + on %done { + self.success = True; + } + +} &requires=((self?.messageID) && (self?.opcode) && (self.opcode != ProtocolOpcode::Undef)); + +#----------------------------------------------------------------------------- +# Bind Operation +# https://tools.ietf.org/html/rfc4511#section-4.2 + +public type BindAuthType = enum { + BIND_AUTH_SIMPLE = 0, + BIND_AUTH_SASL = 3, +}; + +type SaslCredentials = unit() { + mechanism: ASN1::ASN1Message(True) &convert=$$.body.str_value; + # TODO: if we want to parse the (optional) credentials string +}; + +# 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 +}; + +type BindRequest = unit(inout message: Message) { + version: ASN1::ASN1Message(True) &convert=$$.body.num_value; + name: ASN1::ASN1Message(True) &convert=$$.body.str_value { + message.obj = self.name; + } + var authType: BindAuthType = BindAuthType::Undef; + var authData: bytes = b""; + var simpleCreds: string = ""; + + : ASN1::ASN1Message(True) { + if ($$?.application_id) { + self.authType = cast(cast($$.application_id)); + self.authData = $$.application_data; + } + if ((self.authType == BindAuthType::BIND_AUTH_SIMPLE) && (|self.authData| > 0)) { + self.simpleCreds = self.authData.decode(); + if (|self.simpleCreds| > 0) { + message.arg = self.simpleCreds; + } + } + } + saslCreds: SaslCredentials() &parse-from=self.authData if ((self.authType == BindAuthType::BIND_AUTH_SASL) && + (|self.authData| > 0)) { + message.arg = self.saslCreds.mechanism; + } +} &requires=((self?.authType) && (self.authType != BindAuthType::Undef)); + +type BindResponse = unit(inout message: Message) { + : Result { + message.result = $$; + } + + # TODO: if we want to parse SASL credentials returned +}; + +#----------------------------------------------------------------------------- +# Unbind Operation +# https://tools.ietf.org/html/rfc4511#section-4.3 + +type UnbindRequest = unit(inout message: Message) { + # this page intentionally left blank +}; + +#----------------------------------------------------------------------------- +# Search Operation +# https://tools.ietf.org/html/rfc4511#section-4.5 + +public type SearchScope = enum { + SEARCH_BASE = 0, + SEARCH_SINGLE = 1, + SEARCH_TREE = 2, +}; + +public type SearchDerefAlias = enum { + DEREF_NEVER = 0, + DEREF_IN_SEARCHING = 1, + DEREF_FINDING_BASE = 2, + DEREF_ALWAYS = 3, +}; + +type FilterType = enum { + FILTER_AND = 0, + FILTER_OR = 1, + FILTER_NOT = 2, + FILTER_EQ = 3, + FILTER_SUBSTR = 4, + FILTER_GE = 5, + FILTER_LE = 6, + FILTER_PRESENT = 7, + FILTER_APPROX = 8, + FILTER_EXT = 9, + FILTER_INVALID = 254, +}; + +public type AttributeSelection = unit { + var attributes: vector; + + # TODO: parse AttributeSelection as per + # https://tools.ietf.org/html/rfc4511#section-4.5.1 + # and decide how deep that should be fleshed out. + : ASN1::ASN1Message(True) { + if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && + ($$.body?.seq)) { + for (i in $$.body.seq.submessages) { + if (i.body?.str_value) { + self.attributes.push_back(i.body.str_value); + } + } + } + } +}; + +type AttributeValueAssertion = unit { + var desc: string = ""; + var val: string = ""; + + : ASN1::ASN1Message(True) { + if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && + ($$.body?.seq) && + (|$$.body.seq.submessages| >= 2)) { + if ($$.body.seq.submessages[0].body?.str_value) { + self.desc = $$.body.seq.submessages[0].body.str_value; + } + if ($$.body.seq.submessages[1].body?.str_value) { + self.val = $$.body.seq.submessages[1].body.str_value; + } + } + } +}; + +# An AND or OR search filter can consist of many sub-searchfilters, so we try to parse these +type ParseNestedAndOr = unit { + searchfilters: SearchFilter[] &eod; +}; + +type ParseNestedNot = unit { + searchfilter: SearchFilter; +}; + +# Helper functions to properly format some custom data structures + +public function utf16_guid_to_hex_repr(bts: bytes) : string { + # Rather ugly workaround to pretty-print the CLDAP DomainGuid UTF16-LE encoded string + # in the same format as Wireshark (aabbccdd-eeff-gghh-iijj-kkllmmnnoopp) + + # We need to have exactly 16 bytes... + if ( |bts| != 16 ) { + # ... and otherwise just return an error code + return "GUID_FORMAT_FAILED"; + } + + local ret = ""; + for ( i in [[3, 2, 1, 0], [5, 4], [7, 6], [8, 9], [10, 11, 12, 13, 14, 15]] ) { + for ( j in i ) { + local bt: uint8 = *bts.at(j); + ret = ret + "%02x" % bt; + if ( j in [0, 4, 6, 9] ) { + ret = ret + "-"; + } + } + } + return ret; +} + +public function bytes_sid_to_hex_repr(bts: bytes) : string { + local ret = ""; + local cnt = 0; + + while ( cnt < |bts| ) { + local bt: uint8 = *bts.at(cnt); + ret = ret + "%02x" % bt; + + if ( cnt < |bts|-1 ) { + ret = ret + ":"; + } + cnt += 1; + } + return ret; +} + +public function bytes_sid_to_SID_repr(bts: bytes) : string { + # Example: SID -> S-1-5-21-1153942841-488947194-1912431946 + + # Needs to be exactly 24 bytes + if ( |bts| != 24 ) { + # ... and otherwise just return an error code + return "SID_FORMAT_FAILED"; + } + + local ret = "S-"; + local cnt = 0; + + # Mixed little and big endian, so turn everything to big endian first... + # Byte 1 seems to be skipped when parsing the SID + for ( i in [[0], [2, 3, 4, 5, 6, 7], [11, 10, 9, 8], [15, 14, 13, 12], [19, 18, 17, 16], [23, 22, 21, 20]] ) { + local dec_val_rep: bytes = b""; + for ( j in i ) { + local bt: uint8 = *bts.at(j); + dec_val_rep += bt; + cnt += 1; + } + + # ... so we can represent this integer value in big endian + ret = ret + "%u" % dec_val_rep.to_uint(spicy::ByteOrder::Big); + + # Only print the dash when we're not at the end + if ( cnt < 23 ) { + ret = ret + "-"; + } + } + return ret; +} + + +public function uint32_to_hex_repr(bts: bytes) : string { + # Needs to be exactly 4 bytes + if ( |bts| != 4 ) { + # ... and otherwise just return an error code + return "HEX_FORMAT_FAILED"; + } + + # Workaround to print the hex value of an uint32, prepended with '0x' + local ret = "0x"; + for ( i in [3, 2, 1, 0] ) { + local bt: uint8 = *bts.at(i); + ret = ret + "%02x" % bt; + } + return ret; +} + +# Helper to compute a string representation of a `SearchFilter`. +public function string_representation(search_filter: SearchFilter): string { + local repr: string; + + switch ( local fType = search_filter.filterType ) { + # The NOT, AND and OR filter types are trees and may hold many leaf nodes. So recursively get + # the stringPresentations for the leaf nodes and add them all in one final statement. + + case FilterType::FILTER_NOT: { + repr = "(!%s)" % search_filter.FILTER_NOT.searchfilter.stringRepresentation; + } + + case FilterType::FILTER_AND, FilterType::FILTER_OR: { + local nestedObj: ParseNestedAndOr; + local printChar = ""; + + if ( fType == FilterType::FILTER_AND ) { + printChar = "&"; + nestedObj = search_filter.FILTER_AND; + } else { + printChar = "|"; + nestedObj = search_filter.FILTER_OR; + } + + # Build the nested AND/OR statement in this loop. When we encounter the first element, + # we open the statement. At the second element, we close our first complete statement. For every + # following statement, we extend the AND/OR statement by wrapping it around the already completed + # statement. Although it is also valid to not do this wrapping, which is logically equivalent, e.g: + # + # (1) (2) + # (?(a=b)(c=d)(e=f)) vs (?(?(a=b)(c=d))(e=f)) + # + # the latter version is also shown by Wireshark. So although the parsed structure actually represents + # version (1) of the query, we now choose to print version (2). If this is not desirable, swap the code + # for the following: + # + # # Construct the nested structure, like (1) + # for ( SF in nestedObj.searchfilters ) { + # self.stringRepresentation = self.stringRepresentation + SF.stringRepresentation + # } + # # Close it with brackets and put the correct printChar for AND/OR in the statement + # self.stringRepresentation = "(%s" % printChar + self.stringRepresentation + ")"; + # + + local i = 0; + for ( searchFilter in nestedObj.searchfilters ) { + switch ( i ) { + case 0: { + repr = "(%s%s%s" % ( + printChar, + searchFilter.stringRepresentation, + # If we have exactly one element immediately close the statement since we are done. + |nestedObj.searchfilters| == 1 ? ")" : "" + ); + } + case 1: { + repr = repr + searchFilter.stringRepresentation + ")"; + } + default: { + repr = "(%s" % printChar + repr + searchFilter.stringRepresentation + ")"; + } + } + i += 1; + } + } + + # The following FilterTypes are leaf nodes and can thus be represented in a statement + + case FilterType::FILTER_EXT: { + # For extended search filters the meaning of the individual fields in + # `DecodedAttributeValue` is slightly different. + repr = "(%s:%s:=%s)" % (search_filter.FILTER_EXT.assertionValueDecoded, + search_filter.FILTER_EXT.attributeDesc.decode(), + search_filter.FILTER_EXT.matchValue); + } + case FilterType::FILTER_APPROX: { + repr = "(%s~=%s)" % (search_filter.FILTER_APPROX.attributeDesc.decode(), + search_filter.FILTER_APPROX.assertionValueDecoded); + } + case FilterType::FILTER_EQ: { + repr = "(%s=%s)" % (search_filter.FILTER_EQ.attributeDesc.decode(), + search_filter.FILTER_EQ.assertionValueDecoded); + } + case FilterType::FILTER_GE: { + repr = "(%s>=%s)" % (search_filter.FILTER_GE.attributeDesc.decode(), + search_filter.FILTER_GE.assertionValueDecoded); + } + case FilterType::FILTER_LE: { + repr = "(%s<=%s)" % (search_filter.FILTER_LE.attributeDesc.decode(), + search_filter.FILTER_LE.assertionValueDecoded); + } + case FilterType::FILTER_SUBSTR: { + repr = "(%s=*%s*)" % (search_filter.FILTER_SUBSTR.attributeDesc.decode(), + search_filter.FILTER_SUBSTR.assertionValueDecoded); + } + case FilterType::FILTER_PRESENT: { + repr = "(%s=*)" % search_filter.FILTER_PRESENT; + } + } + + return repr; +} + +# Represents an (extended) key-value pair present in SearchFilters +type DecodedAttributeValue = unit(fType: FilterType) { + var assertionValueDecoded: string = ""; + + : uint8; + attributeDesc_len: uint8; + attributeDesc: bytes &size=self.attributeDesc_len; + + # For some reason, two intermediate uint8 values are present in the FILTER_SUBSTR type. + : uint8 if ( fType == FilterType::FILTER_SUBSTR ); + : uint8 if ( fType == FilterType::FILTER_SUBSTR ); + + : uint8; + assertionValue_len: uint8; + assertionValue: bytes &size=self.assertionValue_len; + + # Only for the FILTER_EXT type, parse extra fields + : uint8 if ( fType == FilterType::FILTER_EXT ); + matchValue_len: uint8 if( fType == FilterType::FILTER_EXT ); + matchValue: bytes &size=self.matchValue_len if ( fType == FilterType::FILTER_EXT ); + + on %done { + switch ( self.attributeDesc ) { + # Special parsing required for some CLDAP attributes, + # see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/895a7744-aff3-4f64-bcfa-f8c05915d2e9 + + case b"DomainGuid": { + self.assertionValueDecoded = utf16_guid_to_hex_repr(self.assertionValue); + } + + case b"objectSid", b"AAC": { + self.assertionValueDecoded = bytes_sid_to_hex_repr(self.assertionValue); + } + + case b"DomainSid": { + self.assertionValueDecoded = bytes_sid_to_SID_repr(self.assertionValue); + } + + case b"NtVer": { + self.assertionValueDecoded = uint32_to_hex_repr(self.assertionValue); + } + + # By default, decode with UTF-8 + default: { + self.assertionValueDecoded = self.assertionValue.decode(); + } + } + } +}; + +type SearchFilter = unit { + var filterType: FilterType = FilterType::Undef; + var filterBytes: bytes = b""; + var filterLen: uint64 = 0; + var stringRepresentation: string = ""; + + : ASN1::ASN1Message(True) { + if ($$?.application_id) { + self.filterType = cast(cast($$.application_id)); + self.filterBytes = $$.application_data; + self.filterLen = $$.head.len.len; + } else { + self.filterType = FilterType::FILTER_INVALID; + } + } + + switch ( self.filterType ) { + + # FilterTypes that hold one or more SearchFilters inside them + + FilterType::FILTER_AND -> FILTER_AND: ParseNestedAndOr() + &parse-from=self.filterBytes; + FilterType::FILTER_OR -> FILTER_OR: ParseNestedAndOr() + &parse-from=self.filterBytes; + FilterType::FILTER_NOT -> FILTER_NOT: ParseNestedNot() + &parse-from=self.filterBytes; + + # FilterTypes that we can actually convert to a string + + FilterType::FILTER_EQ -> FILTER_EQ: DecodedAttributeValue(FilterType::FILTER_EQ) + &parse-from=self.filterBytes; + FilterType::FILTER_SUBSTR -> FILTER_SUBSTR: DecodedAttributeValue(FilterType::FILTER_SUBSTR) + &parse-from=self.filterBytes; + FilterType::FILTER_GE -> FILTER_GE: DecodedAttributeValue(FilterType::FILTER_GE) + &parse-from=self.filterBytes; + FilterType::FILTER_LE -> FILTER_LE: DecodedAttributeValue(FilterType::FILTER_LE) + &parse-from=self.filterBytes; + FilterType::FILTER_APPROX -> FILTER_APPROX: DecodedAttributeValue(FilterType::FILTER_APPROX) + &parse-from=self.filterBytes; + FilterType::FILTER_EXT -> FILTER_EXT: DecodedAttributeValue(FilterType::FILTER_EXT) + &parse-from=self.filterBytes; + FilterType::FILTER_PRESENT -> FILTER_PRESENT: ASN1::ASN1OctetString(self.filterLen, False) + &convert=$$.value.decode(hilti::Charset::ASCII) + &parse-from=self.filterBytes; + }; + + # So when you're done with recursively parsing the filters, we can now leverage the tree structure to + # recursively get the stringRepresentations for those leafs, which are SearchFilters + + on %done { + self.stringRepresentation = string_representation(self); + } + + on %error { + self.stringRepresentation = "FILTER_PARSING_ERROR"; + } + +}; + +public type SearchRequest = unit(inout message: Message) { + baseObject: ASN1::ASN1Message(True) &convert=$$.body.str_value { + message.obj = self.baseObject; + } + scope: ASN1::ASN1Message(True) &convert=cast(cast($$.body.num_value)) + &default=SearchScope::Undef { + message.arg = "%s" % self.scope; + } + deref: ASN1::ASN1Message(True) &convert=cast(cast($$.body.num_value)) + &default=SearchDerefAlias::Undef; + sizeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0; + timeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0; + typesOnly: ASN1::ASN1Message(True) &convert=$$.body.bool_value &default=False; + filter: SearchFilter &convert=$$.stringRepresentation; + attributes: AttributeSelection &convert=$$.attributes; +}; + +type SearchResultEntry = unit(inout message: Message) { + objectName: ASN1::ASN1Message(True) &convert=$$.body.str_value { + message.obj = self.objectName; + } + # TODO: if we want to descend down into PartialAttributeList + attributes: ASN1::ASN1Message(True); +}; + +type SearchResultDone = unit(inout message: Message) { + : Result { + message.result = $$; + } +}; + +# TODO: implement SearchResultReference +# type SearchResultReference = unit(inout message: Message) { +# +# }; + +#----------------------------------------------------------------------------- +# Modify Operation +# https://tools.ietf.org/html/rfc4511#section-4.6 + +type ModifyRequest = unit(inout message: Message) { + objectName: ASN1::ASN1Message(True) &convert=$$.body.str_value { + message.obj = self.objectName; + } + + # TODO: parse changes +}; + +type ModifyResponse = unit(inout message: Message) { + : Result { + message.result = $$; + } +}; + +#----------------------------------------------------------------------------- +# Add Operation +# https://tools.ietf.org/html/rfc4511#section-4.7 + +# TODO: implement AddRequest +# type AddRequest = unit(inout message: Message) { +# +# +# }; + +type AddResponse = unit(inout message: Message) { + : Result { + message.result = $$; + } +}; + +#----------------------------------------------------------------------------- +# Delete Operation +# https://tools.ietf.org/html/rfc4511#section-4.8 + +type DelRequest = unit(inout message: Message) { + objectName: ASN1::ASN1Message(True) &convert=$$.body.str_value { + message.obj = self.objectName; + } +}; + +type DelResponse = unit(inout message: Message) { + : Result { + message.result = $$; + } +}; + +#----------------------------------------------------------------------------- +# Modify DN Operation +# https://tools.ietf.org/html/rfc4511#section-4.8 + +# TODO: implement ModDNRequest +# type ModDNRequest = unit(inout message: Message) { +# +# }; + +type ModDNResponse = unit(inout message: Message) { + : Result { + message.result = $$; + } +}; + +#----------------------------------------------------------------------------- +# Compare Operation +# https://tools.ietf.org/html/rfc4511#section-4.10 + +# TODO: implement CompareRequest +# type CompareRequest = unit(inout message: Message) { +# +# }; + +type CompareResponse = unit(inout message: Message) { + : Result { + message.result = $$; + } +}; + +#----------------------------------------------------------------------------- +# Abandon Operation +# https://tools.ietf.org/html/rfc4511#section-4.11 + +type AbandonRequest = unit(inout message: Message) { + messageID: ASN1::ASN1Message(True) &convert=$$.body.num_value { + message.obj = "%d" % (self.messageID); + } +}; + +#----------------------------------------------------------------------------- +# Extended Operation +# https://tools.ietf.org/html/rfc4511#section-4.12 + +# TODO: implement ExtendedRequest +# type ExtendedRequest = unit(inout message: Message) { +# +# }; + +# TODO: implement ExtendedResponse +# type ExtendedResponse = unit(inout message: Message) { +# +# }; + +#----------------------------------------------------------------------------- +# IntermediateResponse Message +# https://tools.ietf.org/html/rfc4511#section-4.13 + +# TODO: implement IntermediateResponse +# type IntermediateResponse = unit(inout message: Message) { +# +# }; diff --git a/src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy b/src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy new file mode 100644 index 0000000000..d0f9c7fd4d --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy @@ -0,0 +1,14 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +module LDAP_Zeek; + +import zeek; +import LDAP; + +on LDAP::MessageWrapper::%done { + zeek::confirm_protocol(); +} + +on LDAP::MessageWrapper::%error { + zeek::reject_protocol("error while parsing LDAP message"); +} diff --git a/src/spicy/spicy-ldap/analyzer/main.zeek b/src/spicy/spicy-ldap/analyzer/main.zeek new file mode 100644 index 0000000000..44955bffb0 --- /dev/null +++ b/src/spicy/spicy-ldap/analyzer/main.zeek @@ -0,0 +1,502 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +module LDAP; + +export { + redef enum Log::ID += { LDAP_LOG, + LDAP_SEARCH_LOG }; + + ## Whether clear text passwords are captured or not. + option default_capture_password = F; + + ## Whether to log LDAP search attributes or not. + option default_log_search_attributes = F; + + ## Default logging policy hook for LDAP_LOG. + global log_policy: Log::PolicyHook; + + ## Default logging policy hook for LDAP_SEARCH_LOG. + global log_policy_search: Log::PolicyHook; + + ############################################################################# + # This is the format of ldap.log (ldap operations minus search-related) + # Each line represents a unique connection+message_id (requests/responses) + type Message: record { + + # Timestamp for when the event happened. + ts: time &log; + + # Unique ID for the connection. + uid: string &log; + + # The connection's 4-tuple of endpoint addresses/ports. + id: conn_id &log; + + # transport protocol + proto: string &log &optional; + + # Message ID + message_id: int &log &optional; + + # LDAP version + version: int &log &optional; + + # normalized operations (e.g., bind_request and bind_response to "bind") + opcode: set[string] &log &optional; + + # Result code(s) + result: set[string] &log &optional; + + # result diagnostic message(s) + diagnostic_message: vector of string &log &optional; + + # object(s) + object: vector of string &log &optional; + + # argument(s) + argument: vector of string &log &optional; + }; + + ############################################################################# + # This is the format of ldap_search.log (search-related messages only) + # Each line represents a unique connection+message_id (requests/responses) + type Search: record { + + # Timestamp for when the event happened. + ts: time &log; + + # Unique ID for the connection. + uid: string &log; + + # The connection's 4-tuple of endpoint addresses/ports. + id: conn_id &log; + + # transport protocol + proto: string &log &optional; + + # Message ID + message_id: int &log &optional; + + # sets of search scope and deref alias + scope: set[string] &log &optional; + deref: set[string] &log &optional; + + # base search objects + base_object: vector of string &log &optional; + + # number of results returned + result_count: count &log &optional; + + # Result code (s) + result: set[string] &log &optional; + + # result diagnostic message(s) + diagnostic_message: vector of string &log &optional; + + # a string representation of the search filter used in the query + filter: string &log &optional; + + # a list of attributes that were returned in the search + attributes: vector of string &log &optional; + }; + + # Event that can be handled to access the ldap record as it is sent on + # to the logging framework. + global log_ldap: event(rec: LDAP::Message); + global log_ldap_search: event(rec: LDAP::Search); + + # Event called for each LDAP message (either direction) + global LDAP::message: event(c: connection, + message_id: int, + opcode: LDAP::ProtocolOpcode, + result: LDAP::ResultCode, + matched_dn: string, + diagnostic_message: string, + object: string, + argument: string); + + const PROTOCOL_OPCODES = { + [LDAP::ProtocolOpcode_BIND_REQUEST] = "bind", + [LDAP::ProtocolOpcode_BIND_RESPONSE] = "bind", + [LDAP::ProtocolOpcode_UNBIND_REQUEST] = "unbind", + [LDAP::ProtocolOpcode_SEARCH_REQUEST] = "search", + [LDAP::ProtocolOpcode_SEARCH_RESULT_ENTRY] = "search", + [LDAP::ProtocolOpcode_SEARCH_RESULT_DONE] = "search", + [LDAP::ProtocolOpcode_MODIFY_REQUEST] = "modify", + [LDAP::ProtocolOpcode_MODIFY_RESPONSE] = "modify", + [LDAP::ProtocolOpcode_ADD_REQUEST] = "add", + [LDAP::ProtocolOpcode_ADD_RESPONSE] = "add", + [LDAP::ProtocolOpcode_DEL_REQUEST] = "delete", + [LDAP::ProtocolOpcode_DEL_RESPONSE] = "delete", + [LDAP::ProtocolOpcode_MOD_DN_REQUEST] = "modify", + [LDAP::ProtocolOpcode_MOD_DN_RESPONSE] = "modify", + [LDAP::ProtocolOpcode_COMPARE_REQUEST] = "compare", + [LDAP::ProtocolOpcode_COMPARE_RESPONSE] = "compare", + [LDAP::ProtocolOpcode_ABANDON_REQUEST] = "abandon", + [LDAP::ProtocolOpcode_SEARCH_RESULT_REFERENCE] = "search", + [LDAP::ProtocolOpcode_EXTENDED_REQUEST] = "extended", + [LDAP::ProtocolOpcode_EXTENDED_RESPONSE] = "extended", + [LDAP::ProtocolOpcode_INTERMEDIATE_RESPONSE] = "intermediate" + } &default = "unknown"; + + const BIND_SIMPLE = "bind simple"; + const BIND_SASL = "bind SASL"; + + const RESULT_CODES = { + [LDAP::ResultCode_SUCCESS] = "success", + [LDAP::ResultCode_OPERATIONS_ERROR] = "operations error", + [LDAP::ResultCode_PROTOCOL_ERROR] = "protocol error", + [LDAP::ResultCode_TIME_LIMIT_EXCEEDED] = "time limit exceeded", + [LDAP::ResultCode_SIZE_LIMIT_EXCEEDED] = "size limit exceeded", + [LDAP::ResultCode_COMPARE_FALSE] = "compare false", + [LDAP::ResultCode_COMPARE_TRUE] = "compare true", + [LDAP::ResultCode_AUTH_METHOD_NOT_SUPPORTED] = "auth method not supported", + [LDAP::ResultCode_STRONGER_AUTH_REQUIRED] = "stronger auth required", + [LDAP::ResultCode_PARTIAL_RESULTS] = "partial results", + [LDAP::ResultCode_REFERRAL] = "referral", + [LDAP::ResultCode_ADMIN_LIMIT_EXCEEDED] = "admin limit exceeded", + [LDAP::ResultCode_UNAVAILABLE_CRITICAL_EXTENSION] = "unavailable critical extension", + [LDAP::ResultCode_CONFIDENTIALITY_REQUIRED] = "confidentiality required", + [LDAP::ResultCode_SASL_BIND_IN_PROGRESS] = "SASL bind in progress", + [LDAP::ResultCode_NO_SUCH_ATTRIBUTE] = "no such attribute", + [LDAP::ResultCode_UNDEFINED_ATTRIBUTE_TYPE] = "undefined attribute type", + [LDAP::ResultCode_INAPPROPRIATE_MATCHING] = "inappropriate matching", + [LDAP::ResultCode_CONSTRAINT_VIOLATION] = "constraint violation", + [LDAP::ResultCode_ATTRIBUTE_OR_VALUE_EXISTS] = "attribute or value exists", + [LDAP::ResultCode_INVALID_ATTRIBUTE_SYNTAX] = "invalid attribute syntax", + [LDAP::ResultCode_NO_SUCH_OBJECT] = "no such object", + [LDAP::ResultCode_ALIAS_PROBLEM] = "alias problem", + [LDAP::ResultCode_INVALID_DNSYNTAX] = "invalid DN syntax", + [LDAP::ResultCode_ALIAS_DEREFERENCING_PROBLEM] = "alias dereferencing problem", + [LDAP::ResultCode_INAPPROPRIATE_AUTHENTICATION] = "inappropriate authentication", + [LDAP::ResultCode_INVALID_CREDENTIALS] = "invalid credentials", + [LDAP::ResultCode_INSUFFICIENT_ACCESS_RIGHTS] = "insufficient access rights", + [LDAP::ResultCode_BUSY] = "busy", + [LDAP::ResultCode_UNAVAILABLE] = "unavailable", + [LDAP::ResultCode_UNWILLING_TO_PERFORM] = "unwilling to perform", + [LDAP::ResultCode_LOOP_DETECT] = "loop detect", + [LDAP::ResultCode_SORT_CONTROL_MISSING] = "sort control missing", + [LDAP::ResultCode_OFFSET_RANGE_ERROR] = "offset range error", + [LDAP::ResultCode_NAMING_VIOLATION] = "naming violation", + [LDAP::ResultCode_OBJECT_CLASS_VIOLATION] = "object class violation", + [LDAP::ResultCode_NOT_ALLOWED_ON_NON_LEAF] = "not allowed on non-leaf", + [LDAP::ResultCode_NOT_ALLOWED_ON_RDN] = "not allowed on RDN", + [LDAP::ResultCode_ENTRY_ALREADY_EXISTS] = "entry already exists", + [LDAP::ResultCode_OBJECT_CLASS_MODS_PROHIBITED] = "object class mods prohibited", + [LDAP::ResultCode_RESULTS_TOO_LARGE] = "results too large", + [LDAP::ResultCode_AFFECTS_MULTIPLE_DSAS] = "affects multiple DSAs", + [LDAP::ResultCode_CONTROL_ERROR] = "control error", + [LDAP::ResultCode_OTHER] = "other", + [LDAP::ResultCode_SERVER_DOWN] = "server down", + [LDAP::ResultCode_LOCAL_ERROR] = "local error", + [LDAP::ResultCode_ENCODING_ERROR] = "encoding error", + [LDAP::ResultCode_DECODING_ERROR] = "decoding error", + [LDAP::ResultCode_TIMEOUT] = "timeout", + [LDAP::ResultCode_AUTH_UNKNOWN] = "auth unknown", + [LDAP::ResultCode_FILTER_ERROR] = "filter error", + [LDAP::ResultCode_USER_CANCELED] = "user canceled", + [LDAP::ResultCode_PARAM_ERROR] = "param error", + [LDAP::ResultCode_NO_MEMORY] = "no memory", + [LDAP::ResultCode_CONNECT_ERROR] = "connect error", + [LDAP::ResultCode_NOT_SUPPORTED] = "not supported", + [LDAP::ResultCode_CONTROL_NOT_FOUND] = "control not found", + [LDAP::ResultCode_NO_RESULTS_RETURNED] = "no results returned", + [LDAP::ResultCode_MORE_RESULTS_TO_RETURN] = "more results to return", + [LDAP::ResultCode_CLIENT_LOOP] = "client loop", + [LDAP::ResultCode_REFERRAL_LIMIT_EXCEEDED] = "referral limit exceeded", + [LDAP::ResultCode_INVALID_RESPONSE] = "invalid response", + [LDAP::ResultCode_AMBIGUOUS_RESPONSE] = "ambiguous response", + [LDAP::ResultCode_TLS_NOT_SUPPORTED] = "TLS not supported", + [LDAP::ResultCode_INTERMEDIATE_RESPONSE] = "intermediate response", + [LDAP::ResultCode_UNKNOWN_TYPE] = "unknown type", + [LDAP::ResultCode_LCUP_INVALID_DATA] = "LCUP invalid data", + [LDAP::ResultCode_LCUP_UNSUPPORTED_SCHEME] = "LCUP unsupported scheme", + [LDAP::ResultCode_LCUP_RELOAD_REQUIRED] = "LCUP reload required", + [LDAP::ResultCode_CANCELED] = "canceled", + [LDAP::ResultCode_NO_SUCH_OPERATION] = "no such operation", + [LDAP::ResultCode_TOO_LATE] = "too late", + [LDAP::ResultCode_CANNOT_CANCEL] = "cannot cancel", + [LDAP::ResultCode_ASSERTION_FAILED] = "assertion failed", + [LDAP::ResultCode_AUTHORIZATION_DENIED] = "authorization denied" + } &default = "unknown"; + + const SEARCH_SCOPES = { + [LDAP::SearchScope_SEARCH_BASE] = "base", + [LDAP::SearchScope_SEARCH_SINGLE] = "single", + [LDAP::SearchScope_SEARCH_TREE] = "tree", + } &default = "unknown"; + + const SEARCH_DEREF_ALIASES = { + [LDAP::SearchDerefAlias_DEREF_NEVER] = "never", + [LDAP::SearchDerefAlias_DEREF_IN_SEARCHING] = "searching", + [LDAP::SearchDerefAlias_DEREF_FINDING_BASE] = "finding", + [LDAP::SearchDerefAlias_DEREF_ALWAYS] = "always", + } &default = "unknown"; +} + +############################################################################# +global OPCODES_FINISHED: set[LDAP::ProtocolOpcode] = { LDAP::ProtocolOpcode_BIND_RESPONSE, + LDAP::ProtocolOpcode_UNBIND_REQUEST, + LDAP::ProtocolOpcode_SEARCH_RESULT_DONE, + LDAP::ProtocolOpcode_MODIFY_RESPONSE, + LDAP::ProtocolOpcode_ADD_RESPONSE, + LDAP::ProtocolOpcode_DEL_RESPONSE, + LDAP::ProtocolOpcode_MOD_DN_RESPONSE, + LDAP::ProtocolOpcode_COMPARE_RESPONSE, + LDAP::ProtocolOpcode_ABANDON_REQUEST, + LDAP::ProtocolOpcode_EXTENDED_RESPONSE }; + +global OPCODES_SEARCH: set[LDAP::ProtocolOpcode] = { LDAP::ProtocolOpcode_SEARCH_REQUEST, + LDAP::ProtocolOpcode_SEARCH_RESULT_ENTRY, + LDAP::ProtocolOpcode_SEARCH_RESULT_DONE, + LDAP::ProtocolOpcode_SEARCH_RESULT_REFERENCE }; + +############################################################################# +redef record connection += { + ldap_proto: string &optional; + ldap_messages: table[int] of Message &optional; + ldap_searches: table[int] of Search &optional; +}; + +############################################################################# +event zeek_init() &priority=5 { + Log::create_stream(LDAP::LDAP_LOG, [$columns=Message, $ev=log_ldap, $path="ldap", $policy=log_policy]); + Log::create_stream(LDAP::LDAP_SEARCH_LOG, [$columns=Search, $ev=log_ldap_search, $path="ldap_search", $policy=log_policy_search]); +} + +############################################################################# +function set_session(c: connection, message_id: int, opcode: LDAP::ProtocolOpcode) { + + if (! c?$ldap_messages ) + c$ldap_messages = table(); + + if (! c?$ldap_searches ) + c$ldap_searches = table(); + + if ((opcode in OPCODES_SEARCH) && (message_id !in c$ldap_searches)) { + c$ldap_searches[message_id] = [$ts=network_time(), + $uid=c$uid, + $id=c$id, + $message_id=message_id, + $result_count=0]; + + } else if ((opcode !in OPCODES_SEARCH) && (message_id !in c$ldap_messages)) { + c$ldap_messages[message_id] = [$ts=network_time(), + $uid=c$uid, + $id=c$id, + $message_id=message_id]; + } + +} + +############################################################################# +@if (Version::at_least("5.2.0")) +event analyzer_confirmation_info(atype: AllAnalyzers::Tag, info: AnalyzerConfirmationInfo) { + if ( atype == Analyzer::ANALYZER_SPICY_LDAP_TCP ) { + info$c$ldap_proto = "tcp"; + } +} +@else @if (Version::at_least("4.2.0")) +event analyzer_confirmation(c: connection, atype: AllAnalyzers::Tag, aid: count) { +@else +event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) { +@endif + + if ( atype == Analyzer::ANALYZER_SPICY_LDAP_TCP ) { + c$ldap_proto = "tcp"; + } + +} +@endif +############################################################################# +event LDAP::message(c: connection, + message_id: int, + opcode: LDAP::ProtocolOpcode, + result: LDAP::ResultCode, + matched_dn: string, + diagnostic_message: string, + object: string, + argument: string) { + + if (opcode == LDAP::ProtocolOpcode_SEARCH_RESULT_DONE) { + set_session(c, message_id, opcode); + + if ( result != LDAP::ResultCode_Undef ) { + if ( ! c$ldap_searches[message_id]?$result ) + c$ldap_searches[message_id]$result = set(); + add c$ldap_searches[message_id]$result[RESULT_CODES[result]]; + } + + if ( diagnostic_message != "" ) { + if ( ! c$ldap_searches[message_id]?$diagnostic_message ) + c$ldap_searches[message_id]$diagnostic_message = vector(); + c$ldap_searches[message_id]$diagnostic_message += diagnostic_message; + } + + if (( ! c$ldap_searches[message_id]?$proto ) && c?$ldap_proto) + c$ldap_searches[message_id]$proto = c$ldap_proto; + + Log::write(LDAP::LDAP_SEARCH_LOG, c$ldap_searches[message_id]); + delete c$ldap_searches[message_id]; + + } else if (opcode !in OPCODES_SEARCH) { + set_session(c, message_id, opcode); + + if ( ! c$ldap_messages[message_id]?$opcode ) + c$ldap_messages[message_id]$opcode = set(); + add c$ldap_messages[message_id]$opcode[PROTOCOL_OPCODES[opcode]]; + + if ( result != LDAP::ResultCode_Undef ) { + if ( ! c$ldap_messages[message_id]?$result ) + c$ldap_messages[message_id]$result = set(); + add c$ldap_messages[message_id]$result[RESULT_CODES[result]]; + } + + if ( diagnostic_message != "" ) { + if ( ! c$ldap_messages[message_id]?$diagnostic_message ) + c$ldap_messages[message_id]$diagnostic_message = vector(); + c$ldap_messages[message_id]$diagnostic_message += diagnostic_message; + } + + if ( object != "" ) { + if ( ! c$ldap_messages[message_id]?$object ) + c$ldap_messages[message_id]$object = vector(); + c$ldap_messages[message_id]$object += object; + } + + if ( argument != "" ) { + if ( ! c$ldap_messages[message_id]?$argument ) + c$ldap_messages[message_id]$argument = vector(); + if ("bind simple" in c$ldap_messages[message_id]$opcode && !default_capture_password) + c$ldap_messages[message_id]$argument += "REDACTED"; + else + c$ldap_messages[message_id]$argument += argument; + } + + if (opcode in OPCODES_FINISHED) { + + if ((BIND_SIMPLE in c$ldap_messages[message_id]$opcode) || + (BIND_SASL in c$ldap_messages[message_id]$opcode)) { + # don't have both "bind" and "bind " in the operations list + delete c$ldap_messages[message_id]$opcode[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; + } + + if (( ! c$ldap_messages[message_id]?$proto ) && c?$ldap_proto) + c$ldap_messages[message_id]$proto = c$ldap_proto; + + Log::write(LDAP::LDAP_LOG, c$ldap_messages[message_id]); + delete c$ldap_messages[message_id]; + } + } + +} + +############################################################################# +event LDAP::searchreq(c: connection, + message_id: int, + base_object: string, + scope: LDAP::SearchScope, + deref: LDAP::SearchDerefAlias, + size_limit: int, + time_limit: int, + types_only: bool, + filter: string, + attributes: vector of string) { + + set_session(c, message_id, LDAP::ProtocolOpcode_SEARCH_REQUEST); + + if ( scope != LDAP::SearchScope_Undef ) { + if ( ! c$ldap_searches[message_id]?$scope ) + c$ldap_searches[message_id]$scope = set(); + add c$ldap_searches[message_id]$scope[SEARCH_SCOPES[scope]]; + } + + if ( deref != LDAP::SearchDerefAlias_Undef ) { + if ( ! c$ldap_searches[message_id]?$deref ) + c$ldap_searches[message_id]$deref = set(); + add c$ldap_searches[message_id]$deref[SEARCH_DEREF_ALIASES[deref]]; + } + + if ( base_object != "" ) { + if ( ! c$ldap_searches[message_id]?$base_object ) + c$ldap_searches[message_id]$base_object = vector(); + c$ldap_searches[message_id]$base_object += base_object; + } + c$ldap_searches[message_id]$filter = filter; + + if ( default_log_search_attributes ) { + c$ldap_searches[message_id]$attributes = attributes; + } +} + +############################################################################# +event LDAP::searchres(c: connection, + message_id: int, + object_name: string) { + + set_session(c, message_id, LDAP::ProtocolOpcode_SEARCH_RESULT_ENTRY); + + c$ldap_searches[message_id]$result_count += 1; +} + +############################################################################# +event LDAP::bindreq(c: connection, + message_id: int, + version: int, + name: string, + authType: LDAP::BindAuthType, + authInfo: string) { + + set_session(c, message_id, LDAP::ProtocolOpcode_BIND_REQUEST); + + if ( ! c$ldap_messages[message_id]?$version ) + c$ldap_messages[message_id]$version = version; + + if ( ! c$ldap_messages[message_id]?$opcode ) + c$ldap_messages[message_id]$opcode = set(); + + if (authType == LDAP::BindAuthType_BIND_AUTH_SIMPLE) { + add c$ldap_messages[message_id]$opcode[BIND_SIMPLE]; + } else if (authType == LDAP::BindAuthType_BIND_AUTH_SASL) { + add c$ldap_messages[message_id]$opcode[BIND_SASL]; + } + +} + +############################################################################# +event connection_state_remove(c: connection) { + + # log any "pending" unlogged LDAP messages/searches + + if ( c?$ldap_messages && (|c$ldap_messages| > 0) ) { + for ( [mid], m in c$ldap_messages ) { + if (mid > 0) { + + if ((BIND_SIMPLE in m$opcode) || (BIND_SASL in m$opcode)) { + # don't have both "bind" and "bind " in the operations list + delete m$opcode[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; + } + + if (( ! m?$proto ) && c?$ldap_proto) + m$proto = c$ldap_proto; + + Log::write(LDAP::LDAP_LOG, m); + } + } + delete c$ldap_messages; + } + + if ( c?$ldap_searches && (|c$ldap_searches| > 0) ) { + for ( [mid], s in c$ldap_searches ) { + if (mid > 0) { + + if (( ! s?$proto ) && c?$ldap_proto) + s$proto = c$ldap_proto; + + Log::write(LDAP::LDAP_SEARCH_LOG, s); + } + } + delete c$ldap_searches; + } + +} diff --git a/src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake b/src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake new file mode 100644 index 0000000000..67cbd4716e --- /dev/null +++ b/src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake @@ -0,0 +1,78 @@ +# Find the Spicy plugin to get access to the infrastructure it provides. +# +# While most of the actual CMake logic for building analyzers comes with the Spicy +# plugin for Zeek, this code bootstraps us by asking "spicyz" for the plugin's +# location. Either make sure that "spicyz" is in PATH, set the environment +# variable SPICYZ to point to its location, or set variable ZEEK_SPICY_ROOT +# in either CMake or environment to point to its installation or build +# directory. +# +# This exports: +# +# SPICY_PLUGIN_FOUND True if plugin and all dependencies were found +# SPICYZ Path to spicyz +# SPICY_PLUGIN_VERSION Version string of plugin +# SPICY_PLUGIN_VERSION_NUMBER Numerical version number of plugin + +# Runs `spicyz` with the flags given as second argument and stores the output in the variable named +# by the first argument. +function (run_spicycz output) + execute_process(COMMAND "${SPICYZ}" ${ARGN} OUTPUT_VARIABLE output_ + OUTPUT_STRIP_TRAILING_WHITESPACE) + + string(STRIP "${output_}" output_) + set(${output} "${output_}" PARENT_SCOPE) +endfunction () + +# Checks that the Spicy plugin version it at least the given version. +function (spicy_plugin_require_version version) + string(REGEX MATCH "([0-9]*)\.([0-9]*)\.([0-9]*).*" _ ${version}) + math(EXPR version_number "${CMAKE_MATCH_1} * 10000 + ${CMAKE_MATCH_2} * 100 + ${CMAKE_MATCH_3}") + + if ("${SPICY_PLUGIN_VERSION_NUMBER}" LESS "${version_number}") + message(FATAL_ERROR "Package requires at least Spicy plugin version ${version}, " + "have ${SPICY_PLUGIN_VERSION}") + endif () +endfunction () + +### +### Main +### + +if (NOT SPICYZ) + set(SPICYZ "$ENV{SPICYZ}") +endif () + +if (NOT SPICYZ) + # Support an in-tree Spicy build. + find_program( + spicyz spicyz + HINTS ${ZEEK_SPICY_ROOT}/bin ${ZEEK_SPICY_ROOT}/build/bin $ENV{ZEEK_SPICY_ROOT}/bin + $ENV{ZEEK_SPICY_ROOT}/build/bin ${PROJECT_SOURCE_DIR}/../../build/bin) + set(SPICYZ "${spicyz}") +endif () + +message(STATUS "spicyz: ${SPICYZ}") + +if (SPICYZ) + set(SPICYZ "${SPICYZ}" CACHE PATH "" FORCE) # make sure it's in the cache + + run_spicycz(SPICY_PLUGIN_VERSION "--version") + run_spicycz(SPICY_PLUGIN_VERSION_NUMBER "--version-number") + message(STATUS "Zeek plugin version: ${SPICY_PLUGIN_VERSION}") + + run_spicycz(spicy_plugin_path "--print-plugin-path") + set(spicy_plugin_cmake_path "${spicy_plugin_path}/cmake") + message(STATUS "Zeek plugin CMake path: ${spicy_plugin_cmake_path}") + + list(PREPEND CMAKE_MODULE_PATH "${spicy_plugin_cmake_path}") + find_package(Zeek REQUIRED) + find_package(Spicy REQUIRED) + zeek_print_summary() + spicy_print_summary() + + include(ZeekSpicyAnalyzerSupport) +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SpicyPlugin DEFAULT_MSG SPICYZ ZEEK_FOUND) diff --git a/src/spicy/spicy-ldap/tests/analyzer/attributes.zeek b/src/spicy/spicy-ldap/tests/analyzer/attributes.zeek new file mode 100644 index 0000000000..e20cf7cc6b --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/attributes.zeek @@ -0,0 +1,13 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth.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-DOC: Test LDAP search attributes with small trace. + +@load analyzer + +redef LDAP::default_log_search_attributes = T; diff --git a/src/spicy/spicy-ldap/tests/analyzer/availability.zeek b/src/spicy/spicy-ldap/tests/analyzer/availability.zeek new file mode 100644 index 0000000000..7c48f3e015 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/availability.zeek @@ -0,0 +1,5 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-EXEC: zeek -NN | grep -q ANALYZER_SPICY_LDAP_TCP +# +# @TEST-DOC: Check that LDAP (TCP) is analyzer is available. diff --git a/src/spicy/spicy-ldap/tests/analyzer/basic.zeek b/src/spicy/spicy-ldap/tests/analyzer/basic.zeek new file mode 100644 index 0000000000..c7bb23e16e --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/basic.zeek @@ -0,0 +1,12 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth.pcap %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output +# @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-DOC: Test LDAP analyzer with small trace. + +@load analyzer diff --git a/src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek b/src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek new file mode 100644 index 0000000000..5e415fbb69 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth-diff-port.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-DOC: Test LDAP analyzer with small trace. + +@load analyzer diff --git a/src/spicy/spicy-ldap/tests/analyzer/functions.spicy b/src/spicy/spicy-ldap/tests/analyzer/functions.spicy new file mode 100644 index 0000000000..5679dba650 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/functions.spicy @@ -0,0 +1,131 @@ +# @TEST-EXEC: spicyc -j -d -L ${DIST}/analyzer %INPUT +# +# @TEST-DOC: Validates helper functions in LDAP module. + +module test; + +import LDAP; + +# ---------------------------------------------------------------------------------- +# function utf16_guid_to_hex_repr() +# - requires exactly 16 bytes + +# Not enough bytes (15) +assert LDAP::utf16_guid_to_hex_repr(b"1234567890ABCDE") == "GUID_FORMAT_FAILED"; + +# Too much bytes (17) +assert LDAP::utf16_guid_to_hex_repr(b"1234567890ABCDEFG") == "GUID_FORMAT_FAILED"; + +# Empty +assert LDAP::utf16_guid_to_hex_repr(b"") == "GUID_FORMAT_FAILED"; + +# 16 times \x00 +assert LDAP::utf16_guid_to_hex_repr(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") == "00000000-0000-0000-0000-000000000000"; + +# 16 times \xff +assert LDAP::utf16_guid_to_hex_repr(b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") == "ffffffff-ffff-ffff-ffff-ffffffffffff"; + +# Valid DomainGuidFilter +assert LDAP::utf16_guid_to_hex_repr(b"\x3b\x52\xb3\xb0\x6f\x54\xaf\x4f\x93\xb2\x29\x4a\x38\x50\x98\xf2") == "b0b3523b-546f-4faf-93b2-294a385098f2"; + +# ---------------------------------------------------------------------------------- +# function bytes_sid_to_hex_repr() +# - transforms bytes of arbitrary length to a ':' separated string + +# Empty +assert LDAP::bytes_sid_to_hex_repr(b"") == ""; + +# 10 times \x00 +assert LDAP::bytes_sid_to_hex_repr(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") == "00:00:00:00:00:00:00:00:00:00"; + +# 10 times \xff +assert LDAP::bytes_sid_to_hex_repr(b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") == "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff"; + +# Valid `AAC` value +assert LDAP::bytes_sid_to_hex_repr(b"\x80\x00\x00\x00") == "80:00:00:00"; + +# Valid objectSid +assert LDAP::bytes_sid_to_hex_repr(b"\x01\x05\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\xd5\x64\xbe\x81\x5d\x68\x9c\x0d\x44\x4a\xae\x74\x01\x02\x00\x00") == "01:05:00:00:00:00:00:05:15:00:00:00:d5:64:be:81:5d:68:9c:0d:44:4a:ae:74:01:02:00:00"; + +# ---------------------------------------------------------------------------------- +# function bytes_sid_to_SID_repr() +# - requires exactly 24 bytes + +# Not enough bytes (0 and 10) +assert LDAP::bytes_sid_to_SID_repr(b"") == "SID_FORMAT_FAILED"; +assert LDAP::bytes_sid_to_SID_repr(b"1234567890") == "SID_FORMAT_FAILED"; + +# Too much bytes (25) +assert LDAP::bytes_sid_to_SID_repr(b"1234567890123456789012345") == "SID_FORMAT_FAILED"; + +# Empty +assert LDAP::bytes_sid_to_SID_repr(b"") == "SID_FORMAT_FAILED"; + +# Valid SID +assert LDAP::bytes_sid_to_SID_repr(b"\x01\x04\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\x39\xc5\xc7\x44\xfa\xbd\x24\x1d\x4a\x65\xfd\x71") == "S-1-5-21-1153942841-488947194-1912431946"; + +# Some random bytes - probably an invalid SID but no error +assert LDAP::bytes_sid_to_SID_repr(b"\x02\x08\x00\x02\x00\x00\x00\x05\x15\x20\x00\x12\xd5\x64\xaf\x84\x5d\x68\x9c\x0d\x44\x4c\xad\x73") == "S-2-8589934597-301998101-2226087125-228354141-1940737092"; + +# All 1's +assert LDAP::bytes_sid_to_SID_repr(b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") == "S-255-281474976710655-4294967295-4294967295-4294967295-4294967295"; + +# ---------------------------------------------------------------------------------- +# function uint32_to_hex_repr() + +# Not enough bytes (0 and 2) +assert LDAP::uint32_to_hex_repr(b"") == "HEX_FORMAT_FAILED"; +assert LDAP::uint32_to_hex_repr(b"12") == "HEX_FORMAT_FAILED"; + +# Too much bytes (6) +assert LDAP::uint32_to_hex_repr(b"123456") == "HEX_FORMAT_FAILED"; + +# Empty +assert LDAP::uint32_to_hex_repr(b"") == "HEX_FORMAT_FAILED"; + +# Valid `NtVer` value +assert LDAP::uint32_to_hex_repr(b"\x16\x00\x00\x00") == "0x00000016"; + +# 4 times \x00 +assert LDAP::uint32_to_hex_repr(b"\x00\x00\x00\x00") == "0x00000000"; + +# 4 times \xff +assert LDAP::uint32_to_hex_repr(b"\xff\xff\xff\xff") == "0xffffffff"; + +# ---------------------------------------------------------------------------------- +# function string_representation() +function make_nested_repr(filters: vector): string { + local nestedOr: LDAP::ParseNestedAndOr; + nestedOr.searchfilters = vector(); + + for (f in filters) { + local or_: LDAP::SearchFilter; + or_.filterType = LDAP::FilterType::FILTER_PRESENT; + or_.FILTER_PRESENT = f; + or_.stringRepresentation = LDAP::string_representation(or_); + + nestedOr.searchfilters.push_back(or_); + } + + local searchFilter: LDAP::SearchFilter; + searchFilter.filterType = LDAP::FilterType::FILTER_OR; + searchFilter.FILTER_OR = nestedOr; + + return LDAP::string_representation(searchFilter); +} + +function test_string_representation() { + local repr0 = make_nested_repr(vector()); + assert repr0 == "": repr0; + + local repr1 = make_nested_repr(vector("foo")); + assert repr1 == "(|(foo=*))": repr1; + + local repr2 = make_nested_repr(vector("foo", "bar")); + assert repr2 == "(|(foo=*)(bar=*))": repr2; + + local repr3 = make_nested_repr(vector("foo", "bar", "baz")); + assert repr3 == "(|(|(foo=*)(bar=*))(baz=*))": repr3; +} + +test_string_representation(); diff --git a/src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek b/src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek new file mode 100644 index 0000000000..0a642223db --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek @@ -0,0 +1,23 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth.pcap %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output +# @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: ! test -f ldap.log +# @TEST-EXEC: ! test -f ldap_search.log +# +# @TEST-DOC: Test LDAP analyzer with small trace using logging policies. + +@load analyzer + +hook LDAP::log_policy(rec: LDAP::Message, id: Log::ID, filter: Log::Filter) + { + break; + } + +hook LDAP::log_policy_search(rec: LDAP::Search, id: Log::ID, + filter: Log::Filter) + { + break; + } diff --git a/src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek b/src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek new file mode 100644 index 0000000000..52bbce73cb --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek @@ -0,0 +1,13 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-krb5-sign-seal-01.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 weird.log +# @TEST-EXEC: ! test -f dpd.log +# +# @TEST-DOC: Test LDAP analyzer with SASL encrypted payloads. + +@load analyzer diff --git a/src/spicy/spicy-ldap/tests/analyzer/search_filter_extended.zeek b/src/spicy/spicy-ldap/tests/analyzer/search_filter_extended.zeek new file mode 100644 index 0000000000..924e1ab09a --- /dev/null +++ b/src/spicy/spicy-ldap/tests/analyzer/search_filter_extended.zeek @@ -0,0 +1,10 @@ +# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. + +# @TEST-DOC: This test case is a regression test for #23. +# +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/issue-32.pcapng %INPUT +# @TEST-EXEC: cat ldap_search.log | zeek-cut -C uid filter base_object > ldap_search.log2 && mv ldap_search.log2 ldap_search.log +# @TEST-EXEC: btest-diff ldap_search.log +# +# @TEST-DOC: Test LDAP analyzer with small trace. diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.log new file mode 100644 index 0000000000..3bdde7206c --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.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. +### NOTE: This file has been sorted with diff-sort. +#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] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap.log new file mode 100644 index 0000000000..462cec25c7 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id version opcode result diagnostic_message object argument +#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.log new file mode 100644 index 0000000000..954b0a5d01 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) sAMAccountName diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.log new file mode 100644 index 0000000000..3bdde7206c --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.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. +### NOTE: This file has been sorted with diff-sort. +#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] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap.log new file mode 100644 index 0000000000..462cec25c7 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id version opcode result diagnostic_message object argument +#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.log new file mode 100644 index 0000000000..9bc7fa70de --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output new file mode 100644 index 0000000000..b1bb951e92 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +### NOTE: This file has been sorted with diff-sort. diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.log new file mode 100644 index 0000000000..2d87050cfa --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.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. +### NOTE: This file has been sorted with diff-sort. +#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] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap.log new file mode 100644 index 0000000000..4cebad26c1 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id version opcode result diagnostic_message object argument +#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.log new file mode 100644 index 0000000000..7d50764ff7 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.log new file mode 100644 index 0000000000..3bdde7206c --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.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. +### NOTE: This file has been sorted with diff-sort. +#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] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output b/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output new file mode 100644 index 0000000000..b1bb951e92 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +### NOTE: This file has been sorted with diff-sort. diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output b/src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output new file mode 100644 index 0000000000..c07b15461b --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +LDAP::Messages { + payload: test string +} diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.log new file mode 100644 index 0000000000..3159ed4b82 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.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. +### NOTE: This file has been sorted with diff-sort. +#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] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp spicy_ldap_tcp 0.813275 1814 2391 S1 0 ShADd 6 2062 4 2559 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap.log new file mode 100644 index 0000000000..40dd1d3672 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id version opcode result diagnostic_message object argument +#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 215 3 bind SASL success - - GSS-SPNEGO diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.log new file mode 100644 index 0000000000..7ad3fbccb5 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.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. +### NOTE: This file has been sorted with diff-sort. +#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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +#close XXXX-XX-XX-XX-XX-XX +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 213 base never - 1 success - (objectclass=*) - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log new file mode 100644 index 0000000000..555a1c7270 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.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. +### NOTE: This file has been sorted with diff-sort. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields uid filter base_object +#types string string vector[string] +#close XXXX-XX-XX-XX-XX-XX +CHhAvVGS1DHFjwGM9 (departmentNumber:2.16.840.1.113730.3.3.2.46.1:=>=N4709) DC=matrix\x2cDC=local diff --git a/src/spicy/spicy-ldap/tests/btest.cfg b/src/spicy/spicy-ldap/tests/btest.cfg new file mode 100644 index 0000000000..914dea4dde --- /dev/null +++ b/src/spicy/spicy-ldap/tests/btest.cfg @@ -0,0 +1,34 @@ +[btest] +MinVersion = 0.66 + +TestDirs = analyzer +TmpDir = %(testbase)s/.tmp +BaselineDir = %(testbase)s/baseline +IgnoreDirs = .svn CVS .tmp Baseline Failing traces Traces +IgnoreFiles = .DS_Store *.pcap data.* *.dat *.wmv *.der *.tmp *.swp .*.swp #* CMakeLists.txt + +[environment] +DIST=%(testbase)s/.. +PATH=%(testbase)s/../tests/scripts:`spicyz --print-plugin-path`/tests/scripts:%(default_path)s +SCRIPTS=`spicyz --print-plugin-path`/tests/Scripts +ZEEK_SPICY_MODULE_PATH=%(testbase)s/../build/spicy-modules +TEST_DIFF_CANONIFIER=`spicyz --print-plugin-path`/tests/Scripts/canonify-zeek-log-sorted +TRACES=%(testbase)s/traces +ZEEKPATH=%(testbase)s/..:`zeek-config --zeekpath` +ZEEK_SEED_FILE=`spicyz --print-plugin-path`/tests/random.seed + +# Set variables to well-defined state. +LANG=C +LC_ALL=C +TZ=UTC +CC= +CXX= +CFLAGS= +CPPFLAGS= +CXXFLAGS= +LDFLAGS= +DYLDFLAGS= + +[environment-installation] +ZEEK_SPICY_MODULE_PATH= +ZEEKPATH=`%(testbase)s/scripts/zeek-path-install` diff --git a/src/spicy/spicy-ldap/tests/scripts/zeek-path-install b/src/spicy/spicy-ldap/tests/scripts/zeek-path-install new file mode 100755 index 0000000000..3ce6131d6d --- /dev/null +++ b/src/spicy/spicy-ldap/tests/scripts/zeek-path-install @@ -0,0 +1,5 @@ +#! /bin/sh +# +# Assembles the Zeek path for testing the installed version (can't do that in btest.cfg directly). + +echo $(spicyz --print-scripts-path):$(zkg config script_dir):$(zeek-config --zeekpath) diff --git a/src/spicy/spicy-ldap/tests/traces/README b/src/spicy/spicy-ldap/tests/traces/README new file mode 100644 index 0000000000..4858d99642 --- /dev/null +++ b/src/spicy/spicy-ldap/tests/traces/README @@ -0,0 +1,15 @@ +The test suite comes with a set of traces collected from a variety of +places that we document below. While these traces are all coming from +public sources, please note that they may carry their own licenses. +We collect them here for convenience only. + +- [ldap-simpleauth.pcap](https://github.com/arkime/arkime/blob/main/tests/pcap/ldap-simpleauth.pcap) +- ldap-simpleauth-diff-port.pcap: made with + `tcprewrite -r 3268:32681 -i ldap-simpleauth.pcap -o ldap-simpleauth-diff-port.pcap` +- ldap-krb5-sign-seal-01.pcap: trace is derived from + + - the LDAP flow selected (filtered out the Kerberos packets) + - truncated to 10 packets (where packet 10 contains the SASL encrypted LDAP message) + - one `\x30` byte in the cyphertext changed to `\x00` +- ldap-issue-32.pcapng: Provided by GH user martinvanhensbergen, + diff --git a/src/spicy/spicy-ldap/tests/traces/issue-32.pcapng b/src/spicy/spicy-ldap/tests/traces/issue-32.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..8ed316dd51f5a6cc15291ecdf73b87d2e7062fed GIT binary patch literal 1436 zcmai!&rcIU6vt=Fwm^kg5&0zv6BEsr((Nq$ZG@Dz$d3qVK%?=*(yp+f-7ULYpz1*c z5);D3faOR$;SH}QCMKvPCLWFc111O_Jb2eP+nUgZ;@f?@Z+2!r^Y%M0V{dGmVGg;FCcCg;Q%DTPJ7)bA#)lr${}Il&1mYBYD6cN}~koUUMj3`8Z5>Y=9|zBHVX z51m2h+Q2adfxT3pwSN2BQ82;u8w-&QH8}To^9a?!AD~}dM-ddUtvq_SYu^Tcv$@5r zDaW3}^=Qj#qV4=>VGSX&{K3N5l6kf%9_!19h9)odK$KRKV%pAF>`aY?L2xq+dKF&o z?B#_3AMz1i;03`O^b+0+7f2l7g{O{`lod52BPqssE;B7@E4BT7;w(#5t2z%a3b*Y5`wC>xj)_VSclw zE>xfG6Z-scafL-_QwJ;RvvIIo)Q6b~wMWnsTlW{L4b_NQ+uWksD92}8+8FcKYqn7!aQf!5JEX3DJEGxt(jjr(*ROeGp literal 0 HcmV?d00001 diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-issue-32.pcapng b/src/spicy/spicy-ldap/tests/traces/ldap-issue-32.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..8ed316dd51f5a6cc15291ecdf73b87d2e7062fed GIT binary patch literal 1436 zcmai!&rcIU6vt=Fwm^kg5&0zv6BEsr((Nq$ZG@Dz$d3qVK%?=*(yp+f-7ULYpz1*c z5);D3faOR$;SH}QCMKvPCLWFc111O_Jb2eP+nUgZ;@f?@Z+2!r^Y%M0V{dGmVGg;FCcCg;Q%DTPJ7)bA#)lr${}Il&1mYBYD6cN}~koUUMj3`8Z5>Y=9|zBHVX z51m2h+Q2adfxT3pwSN2BQ82;u8w-&QH8}To^9a?!AD~}dM-ddUtvq_SYu^Tcv$@5r zDaW3}^=Qj#qV4=>VGSX&{K3N5l6kf%9_!19h9)odK$KRKV%pAF>`aY?L2xq+dKF&o z?B#_3AMz1i;03`O^b+0+7f2l7g{O{`lod52BPqssE;B7@E4BT7;w(#5t2z%a3b*Y5`wC>xj)_VSclw zE>xfG6Z-scafL-_QwJ;RvvIIo)Q6b~wMWnsTlW{L4b_NQ+uWksD92}8+8FcKYqn7!aQf!5JEX3DJEGxt(jjr(*ROeGp literal 0 HcmV?d00001 diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-krb5-sign-seal-01.pcap b/src/spicy/spicy-ldap/tests/traces/ldap-krb5-sign-seal-01.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a5591cb571be36f32701dd8b2f8c5e781577d2a2 GIT binary patch literal 4957 zcmc&&X+RU#7M>(GVU{)b2m}T7DMb{O z7TKiu$|j)V0$NejS{I~6aYNDSb3srMq~OAvJ83J>&_3V$@siw`JLlf}opaAQ_neby zIaO0gMga2rXK)ZfNce;D;2HO-LpmRbP=`1SdUW=+HkK^V1KZb&liaZR~7 zDH?B>t~F_Wc6?7SoE%FYc%Ds05Hg@1AdvtWqFFT$L&I@Ym?|_{Bt**zg-8&Qv|iVG zt;So?+iyPxsD(%I49WtB-_kdZ9=vqBV>DpBR=353_K6ngCLO8>6K72 zgZl`Qjc*#ZkyxbkS{;b>C`2um$-r~g5nLJTaIJ-q$;cHR?0p6hZ4&&E;V+IvLeh04 zkzZguIZuSjWW?-Qz)+@$l<}gm7?i7s#KdxGJQ%~5aWUyCArA{gV=$m6Mq`9xfu}?) z$KvENFpiH!p$d^4AAC;+MkPeq^Mjd5f2|TmP#aYwj>4>juj2DfHg|ZkK(BX?^ z3nVfqHwN@Yd^C3GF12O&mN6+Y_#W94jYT7cBB2~dhDN&l5J8?$RZZoF@7;%bi^hXS z+ExLL3Jvv}`#i{wf3=8X(7#pKsWOsg0yGjIH4)_3X&%n9v z0)Z40pmNL_f8Y{EgFReL@0D!L_ME%gc7+|huZj_4a;B;WuaT$>Blr}Kura}7Gk~1Z zaKOM|Hg_r)lgn}Y${>d&wtjXtOa_zSOX!IpbLFU*k4pJsT%$I8OlE^yMvjSX2s&;- z)g+-DBRU@}CP`R~f(EhklVgO?`dSKewjj{oj{b&njk1}9C3JZIt9Wb_~GaXe% zfM#IXG3a)<8D;|$^#jaNupAhph~?y9t5zXS3|qp~Oc?pSA0db-Mb$<|eu^%Q z49a{mKH<#^}$RW2&38i5N+btjW30NDe(j>8;HNu3d)q)wyJ zX3{aziyd-pojimld%Y9&nso z=**aH24LN4_LpvMW~9cGac**)Q!GR>hJt7oDJhXaNeM4(7Q$v^(0n`d2byjt1PGSv5&C>%iBYomz+aferJ2+OE}V;$)Iw6uLM5 zM^}fl`!8Fc(dAxUnA7ez_TstZ%gdUp%C51tKJEIXHCvFqoyPX4uYP)%_x0Kr%Eef; z!;+&dsd=UeE~gJkPLylSy%5=EZzxWhN_R5cy!}kq{7rXRrIJgG*b^yjv)woBN-u3l zNXV~Tw{uf8DcN*Y?}qOic08VLrzE{|4i7W-yqdB){`${d{h6J20z)Pix)~`tU z)Jc2l1^emWSXr^Wngr)2x)(nE^bV)=OBb7Zr3v%Vo5tpaoU^oJ)!!FJ-Oeew$2g@Jzs={WMP?FM@~% zWUeA`LcO_{tT8)jL0wb83Pn$-YvKCtqltkvTV3ZZ0SOaj4GJIk7RL`q-VYX`3||hpC-p zaAbzEXw$g)qU||8nHTg=1htK~^gr1t$~{y?ojkP^`|*Y1;fagv$-3u#P3pI04)jD+ z=db4&yM1@re03h}VECdI%lk>)SH!)3$1fS}Srb*5(RzvfMb9AH;>DP5PL*Wk((WC% zpoSBuqFl0%Brs0+hzcc!rUsu0f_D*8Gk=MA8wfDpdlw-vxO#;dnUHEDpNnob$n78=zKcr35j*f<>M>U z@~&ImTj`zmYw9dp$8+u%`rXd$aCrA%eMxvl)y1$>C%tcKY7cMBtR$~lusz`x}xo*BWPBpJ2|6(uqC{Af&q+B3QT~SIS zNNFfOJ+{=V!s6za=f7_%(R6h^s-4+c>$BhTyQ@E$9n?5@<5wvXyvZ{QeqeoaVIXP#tD_{*mI&lIlJnoX6P zES?>!toPbu$$IYNT>1;WPh_iMw$rtvMe|Ny#xMTk4;7kisS25#Uy4C_V1oD>6`BA-ZJ)&k!uDEH4J?oz6ra;?`ZT!*Pe~tbtcEGYu(B+7~-u5 zbP)K8g?POhvhg_6_$}BFf5}mf9(4$f21ps z;=+_dMoL}*1t%5i42iu(DH}mbT0~0fkO)ggByxsS6+ZExre74r;H#7!20r)AHz?b< zW5BcfwOiI+(WwEEIbtXnI0tT233|J4gzOE@Tyo6yfarkWtuv{09%o@GkACfH$%B-- zGUMcdvhsyN>x^<=vrmG`DJMg1mS*mrHW*}|7efz7{d^ZxLX6WGBo~(*wvo9B$*46T z@?601-1NF+t<6gpTnWrQ#c&xC84)pbJ0wHI02v%qRCC>4@At^ASUPd?NA9R)$J%ys zqBeKizU77KKHXh!H(dMbhpmCa-G+DPdKPdRdXc?(bE;~x&if=L^D2(}^&T%M&kh2# L`C58gJTCnkHz=9R literal 0 HcmV?d00001 diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-simpleauth-diff-port.pcap b/src/spicy/spicy-ldap/tests/traces/ldap-simpleauth-diff-port.pcap new file mode 100644 index 0000000000000000000000000000000000000000..649078aa952e3493288044a9c432006278cd2b8b GIT binary patch literal 1390 zcmbtUO=uHQ5T3W$#+azAv9zHStWv~6nrut3f<{xS-fZ_^%|Q>1*#&7dk!%_R4K$+l z2LzA)VNeQ66+DPYtzZeEht@#xr(P62*o)Gu5U3{3yd);Zl^lFzChsM?-+bRUv->Xl zQ+vd=H20S@7w!WsJhzBR}5{5gPL3mgRSBschA&3v-UiZ@{hnldr% znEkRqXenW9;mvydQEYn3Or|ErM1fEr)S$xl^ZQ%pdCpZ)UAhmFW>1z733*~#Q}T0n zR774(**jp*(r;8t1-0cqz+S9MVaRo7awF&JspGnc$eJQS@%9w4CWdW@6~;YrX>02g_w21IWDsVhdKLE<90S4r{TL^-Mt5&qkuV)gG!|cnF|i zWeP)o_PJu*pBb!P>yL*16ch)8w?kO{0^Thlg8*&TSsC_N(mv{ zsc}VOxm#C>8gc!ASdVZ|Vd&J&jGa66(hv)s3i*+1L|{U2RBS&m;7uf)JXgL-XSB)6 z1S>NM4DiDk-0iw#i<}tMg0bK!v~Q|S+@$v(?hghdW8v6f;It-MxWkxass2Br-uVJx z5ouEx+C1YL<2HMddacdlj@gw6+5BTy+2$D1SIOp(=p7hD38m#68ukwBT2!Y^nVDWv z_YaM{X*+oCsOQ{61*|oy$_*B@`UbmE(sjI;!mufmnJv62uTfdeW4jW`&!ugsZ1vSA zRCWv}cjPFI@BfKP+1;uZcSlt{4m@ zbJJgQ-g1RCcq3$*`J8vx*^omUw&9$w-pHea;Jw)AcVDwKz)B(3npri*YVJG|=g-V9 DF)4=^ literal 0 HcmV?d00001 diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-simpleauth.pcap b/src/spicy/spicy-ldap/tests/traces/ldap-simpleauth.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1cf904a0061a0a2b143f4c2de209dddb12e78da2 GIT binary patch literal 1390 zcmbtUL1+_E5S_o-#*m~X#?poouu2gNX|gTRdN4J$wKwY?tUc62V|GCr&1yESf#wj= zsy%rT#DhT*6cjv2ky^nLn;s0g2-b^G5B5?icoGW5)R~{OiR(%ZelnB)H~DYgdo#(W zrB{yy5Mg(P0T>?c%=C`BvH(N4r|`voer_%DynG#?#|EbWf@xK(7?5T$g1pu?WS2`O$^%*D~@{#Q>^nj zR~UlU^7#r^rm__uaswyL{5lw=Qsp(9xRCf;@-g9vT**ctX%jmy9Or3g=b91NOnPQ<+tJp9}6POU45WRx~p;XGp^UhoOj5gVs zU}qMA0lpZ6N1eAF+Jy- zq)lOJ^SpnO+Z;mbwKh+C7S=SfS@TwGP9lAUY>tVcfnk(TUcNIUp%Gn8=(MRY)644q zp^-Q35YO#K&fQeNUZbkgU_muDIDnGw( literal 0 HcmV?d00001 diff --git a/src/spicy/spicy-ldap/zkg.meta b/src/spicy/spicy-ldap/zkg.meta new file mode 100644 index 0000000000..4a51819fe9 --- /dev/null +++ b/src/spicy/spicy-ldap/zkg.meta @@ -0,0 +1,21 @@ +[package] +summary = LDAP analyzer +description = An LDAP analyzer based on Spicy +script_dir = analyzer +plugin_dir = build/spicy-modules +build_command = mkdir -p build && cd build && SPICYZ=$(command -v spicyz || echo %(package_base)s/spicy-plugin/build/bin/spicyz) cmake .. && cmake --build . +test_command = cd tests && PATH=$(zkg config plugin_dir)/packages/spicy-plugin/bin:$PATH btest -d -j $(nproc) + +# We depend on spicy-plugin>=1.2.2, but currently cannot express that +# dependency due to zeek/package-manager#106 which has been fixed in +# zkg-2.12.0, but has not been released with zeek yet. +# depends = spicy-plugin >=1.2.2 + +[template] +source = package-template-spicy +version = master +zkg_version = 2.12.0 + +[template_vars] +namespace = LDAP +name = Messages diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log new file mode 100644 index 0000000000..c63d2dea35 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/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 uid filter base_object +#types string string vector[string] +CHhAvVGS1DHFjwGM9 (departmentNumber:2.16.840.1.113730.3.3.2.46.1:=>=N4709) DC=matrix\x2cDC=local +#close XXXX-XX-XX-XX-XX-XX From dc0ef39fb06f8e4143ab7fcef72d76d6fbcd1145 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 08:25:38 +0200 Subject: [PATCH 02/20] Integrate spicy-ldap into build --- src/spicy/CMakeLists.txt | 2 + src/spicy/spicy-ldap/CMakeLists.txt | 17 ---- src/spicy/spicy-ldap/analyzer/CMakeLists.txt | 3 +- .../spicy-ldap/cmake/FindSpicyPlugin.cmake | 78 ------------------- 4 files changed, 3 insertions(+), 97 deletions(-) delete mode 100644 src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake diff --git a/src/spicy/CMakeLists.txt b/src/spicy/CMakeLists.txt index 8d3d625dd7..e997004cd2 100644 --- a/src/spicy/CMakeLists.txt +++ b/src/spicy/CMakeLists.txt @@ -28,3 +28,5 @@ install(DIRECTORY "${PROJECT_SOURCE_DIR}/scripts/spicy/" DESTINATION "${ZEEK_SPI set(ZEEK_SPICY_DATA_PATH "${CMAKE_INSTALL_FULL_DATADIR}/zeek" CACHE PATH "") add_subdirectory(spicyz) + +add_subdirectory(spicy-ldap) diff --git a/src/spicy/spicy-ldap/CMakeLists.txt b/src/spicy/spicy-ldap/CMakeLists.txt index ee8767848a..d17735d5b4 100644 --- a/src/spicy/spicy-ldap/CMakeLists.txt +++ b/src/spicy/spicy-ldap/CMakeLists.txt @@ -1,18 +1 @@ -cmake_minimum_required(VERSION 3.15 FATAL_ERROR) - -project(Messages LANGUAGES C) - -list(PREPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -find_package(SpicyPlugin REQUIRED) - -# Set mininum versions that this plugin needs. Make sure to use "x.y.z" format. -spicy_require_version("1.2.0") -spicy_plugin_require_version("0.99.0") -zeek_require_version("3.0.0") - -if (NOT CMAKE_BUILD_TYPE) - # Default to release build. - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") -endif () - add_subdirectory(analyzer) diff --git a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt index 094fe4aecb..1bd759cf7c 100644 --- a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt +++ b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt @@ -1,5 +1,4 @@ spicy_add_analyzer( NAME LDAP PACKAGE_NAME spicy-ldap - SOURCES ldap.spicy ldap.evt ldap_zeek.spicy - SCRIPTS __load__.zeek main.zeek dpd.sig) + SOURCES ldap.spicy ldap.evt ldap_zeek.spicy) diff --git a/src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake b/src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake deleted file mode 100644 index 67cbd4716e..0000000000 --- a/src/spicy/spicy-ldap/cmake/FindSpicyPlugin.cmake +++ /dev/null @@ -1,78 +0,0 @@ -# Find the Spicy plugin to get access to the infrastructure it provides. -# -# While most of the actual CMake logic for building analyzers comes with the Spicy -# plugin for Zeek, this code bootstraps us by asking "spicyz" for the plugin's -# location. Either make sure that "spicyz" is in PATH, set the environment -# variable SPICYZ to point to its location, or set variable ZEEK_SPICY_ROOT -# in either CMake or environment to point to its installation or build -# directory. -# -# This exports: -# -# SPICY_PLUGIN_FOUND True if plugin and all dependencies were found -# SPICYZ Path to spicyz -# SPICY_PLUGIN_VERSION Version string of plugin -# SPICY_PLUGIN_VERSION_NUMBER Numerical version number of plugin - -# Runs `spicyz` with the flags given as second argument and stores the output in the variable named -# by the first argument. -function (run_spicycz output) - execute_process(COMMAND "${SPICYZ}" ${ARGN} OUTPUT_VARIABLE output_ - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(STRIP "${output_}" output_) - set(${output} "${output_}" PARENT_SCOPE) -endfunction () - -# Checks that the Spicy plugin version it at least the given version. -function (spicy_plugin_require_version version) - string(REGEX MATCH "([0-9]*)\.([0-9]*)\.([0-9]*).*" _ ${version}) - math(EXPR version_number "${CMAKE_MATCH_1} * 10000 + ${CMAKE_MATCH_2} * 100 + ${CMAKE_MATCH_3}") - - if ("${SPICY_PLUGIN_VERSION_NUMBER}" LESS "${version_number}") - message(FATAL_ERROR "Package requires at least Spicy plugin version ${version}, " - "have ${SPICY_PLUGIN_VERSION}") - endif () -endfunction () - -### -### Main -### - -if (NOT SPICYZ) - set(SPICYZ "$ENV{SPICYZ}") -endif () - -if (NOT SPICYZ) - # Support an in-tree Spicy build. - find_program( - spicyz spicyz - HINTS ${ZEEK_SPICY_ROOT}/bin ${ZEEK_SPICY_ROOT}/build/bin $ENV{ZEEK_SPICY_ROOT}/bin - $ENV{ZEEK_SPICY_ROOT}/build/bin ${PROJECT_SOURCE_DIR}/../../build/bin) - set(SPICYZ "${spicyz}") -endif () - -message(STATUS "spicyz: ${SPICYZ}") - -if (SPICYZ) - set(SPICYZ "${SPICYZ}" CACHE PATH "" FORCE) # make sure it's in the cache - - run_spicycz(SPICY_PLUGIN_VERSION "--version") - run_spicycz(SPICY_PLUGIN_VERSION_NUMBER "--version-number") - message(STATUS "Zeek plugin version: ${SPICY_PLUGIN_VERSION}") - - run_spicycz(spicy_plugin_path "--print-plugin-path") - set(spicy_plugin_cmake_path "${spicy_plugin_path}/cmake") - message(STATUS "Zeek plugin CMake path: ${spicy_plugin_cmake_path}") - - list(PREPEND CMAKE_MODULE_PATH "${spicy_plugin_cmake_path}") - find_package(Zeek REQUIRED) - find_package(Spicy REQUIRED) - zeek_print_summary() - spicy_print_summary() - - include(ZeekSpicyAnalyzerSupport) -endif () - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SpicyPlugin DEFAULT_MSG SPICYZ ZEEK_FOUND) From ffbc45ed6eeb769489a8af40cba630362960535c Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 08:26:07 +0200 Subject: [PATCH 03/20] Remove project configuration files in spicy-ldap --- src/spicy/spicy-ldap/.cmake-format.json | 26 ------- .../spicy-ldap/.github/workflows/check.yml | 35 --------- .../.github/workflows/pre-commit.yml | 14 ---- src/spicy/spicy-ldap/.gitignore | 7 -- src/spicy/spicy-ldap/.mdlrc | 1 - src/spicy/spicy-ldap/.pre-commit-config.yaml | 23 ------ src/spicy/spicy-ldap/LICENSE | 29 -------- src/spicy/spicy-ldap/README.md | 74 ------------------- src/spicy/spicy-ldap/zkg.meta | 21 ------ 9 files changed, 230 deletions(-) delete mode 100644 src/spicy/spicy-ldap/.cmake-format.json delete mode 100644 src/spicy/spicy-ldap/.github/workflows/check.yml delete mode 100644 src/spicy/spicy-ldap/.github/workflows/pre-commit.yml delete mode 100644 src/spicy/spicy-ldap/.gitignore delete mode 100644 src/spicy/spicy-ldap/.mdlrc delete mode 100644 src/spicy/spicy-ldap/.pre-commit-config.yaml delete mode 100644 src/spicy/spicy-ldap/LICENSE delete mode 100644 src/spicy/spicy-ldap/README.md delete mode 100644 src/spicy/spicy-ldap/zkg.meta diff --git a/src/spicy/spicy-ldap/.cmake-format.json b/src/spicy/spicy-ldap/.cmake-format.json deleted file mode 100644 index 42b1e14fe9..0000000000 --- a/src/spicy/spicy-ldap/.cmake-format.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "parse": { - "additional_commands": { - "spicy_add_analyzer": { - "kwargs": { - "NAME": "*", - "PACKAGE_NAME": "*", - "SOURCES": "*", - "SCRIPTS": "*" - } - } - } - }, - "format": { - "line_width": 100, - "tab_size": 4, - "separate_ctrl_name_with_space": true, - "max_subgroups_hwrap": 3 - }, - "markup": { - "enable_markup": false - }, - "lint": { - "disabled_codes": ["C0103"] - } -} diff --git a/src/spicy/spicy-ldap/.github/workflows/check.yml b/src/spicy/spicy-ldap/.github/workflows/check.yml deleted file mode 100644 index 53c9e3ddd1..0000000000 --- a/src/spicy/spicy-ldap/.github/workflows/check.yml +++ /dev/null @@ -1,35 +0,0 @@ -on: - pull_request: - push: - branches: [main] - -jobs: - Check: - strategy: - matrix: - version: - - zeek:6.0 - - zeek-dev:latest - - fail-fast: false - - runs-on: ubuntu-latest - container: zeek/${{ matrix.version }} - - steps: - - uses: actions/checkout@v2 - - name: Prepare - run: | - apt-get update - apt-get install -y -q --no-install-recommends g++ cmake make libpcap-dev - - name: Install - run: | - git config --global --add safe.directory $PWD - git clean -fd - eval $(zkg env) - echo Y | zkg -vvvvv install . - - - name: Show logs - if: always() - run: | - tail -n 1000000 $(zkg config state_dir)/logs/*.log diff --git a/src/spicy/spicy-ldap/.github/workflows/pre-commit.yml b/src/spicy/spicy-ldap/.github/workflows/pre-commit.yml deleted file mode 100644 index 9035d06925..0000000000 --- a/src/spicy/spicy-ldap/.github/workflows/pre-commit.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: pre-commit - -on: - pull_request: - push: - branches: [main] - -jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - - uses: pre-commit/action@v2.0.3 diff --git a/src/spicy/spicy-ldap/.gitignore b/src/spicy/spicy-ldap/.gitignore deleted file mode 100644 index 648505ab7b..0000000000 --- a/src/spicy/spicy-ldap/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -build -.idea/ -cmake-build-debug/ -.DS_Store -*.swp -*.tmp -tests/.btest* diff --git a/src/spicy/spicy-ldap/.mdlrc b/src/spicy/spicy-ldap/.mdlrc deleted file mode 100644 index da394dc3f2..0000000000 --- a/src/spicy/spicy-ldap/.mdlrc +++ /dev/null @@ -1 +0,0 @@ -rules "~MD033", "~MD013", "~MD046", "~MD010" diff --git a/src/spicy/spicy-ldap/.pre-commit-config.yaml b/src/spicy/spicy-ldap/.pre-commit-config.yaml deleted file mode 100644 index 0ad081b7b4..0000000000 --- a/src/spicy/spicy-ldap/.pre-commit-config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# See https://pre-commit.com for more information -# See https://pre-commit.com/hooks.html for more hooks -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files - -- repo: https://github.com/markdownlint/markdownlint - rev: v0.11.0 - hooks: - - id: markdownlint - -- repo: https://github.com/cheshirekow/cmake-format-precommit - rev: v0.6.13 - hooks: - - id: cmake-format - - id: cmake-lint - -exclude: '^tests/Baseline' diff --git a/src/spicy/spicy-ldap/LICENSE b/src/spicy/spicy-ldap/LICENSE deleted file mode 100644 index f32436e280..0000000000 --- a/src/spicy/spicy-ldap/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2020-2021 by the Zeek Project through the International Computer -Science Institute. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -(1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -(2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -(3) Neither the name of the Zeek Project, the International Computer - Science Institute, nor the names of contributors may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/src/spicy/spicy-ldap/README.md b/src/spicy/spicy-ldap/README.md deleted file mode 100644 index dc97e6575a..0000000000 --- a/src/spicy/spicy-ldap/README.md +++ /dev/null @@ -1,74 +0,0 @@ -LDAP Analyzer -============= - -Here's what it has: - -- ASN.1 structure decoding: this is probably generally useful for more than just the LDAP parser, so it may be of interest for this to be included somehow as part of spicy's standard modules or whatever - - everything is working except for the "constructed" forms of `ASN1BitString` and `ASN1OctetString` -- LDAP: the LDAP parsing is basically "done once" through a single call to `ASN1Message` (which parses itself recursively) and then the application-level data is also parsed via `&parse-from` a byte array belonging to the outer ASN.1 sequence. This second level of parsing is also done using the ASN.1 data types. - - events - - `ldap::message` - called for each LDAP message - - `ldap::bindreq` - when a bind request is made - - `ldap::searchreq` - basic search request information - - `ldap::searchres` - called each time a search result is returned - - enums - - `ProtocolOpcode` - - `ResultCode` - - `BindAuthType` - - `SearchScope` - - `SearchDerefAlias` - - `FilterType` - - Zeek log files - - `ldap.log` - contains information about all LDAP messages except those that are search-related. Log lines are grouped by connection ID + message ID - - `ts` (time) - - `uid` (connection UID) - - `id` (connection ID 4-tuple) - - `proto` (transport protocol) - - `message_id` (LDAP message ID) - - `version` (LDAP version for bind requests) - - `opcode` (set of 1..n operations from this uid+message_id) - - `result` (set of 1..n results from this uid+message_id) - - `diagnostic_message` (vector of 0..n diagnostic message strings) - - `object` (vector of 0..n "objects," the meaning of which depends on the operation) - - `argument` (vector of 0..n "argument," the meaning of which depends on the operation) - - `ldap_search.log` - contains information about LDAP searches. Log lines are grouped by connection ID + message ID - - `ts` (time) - - `uid` (connection UID) - - `id` (connection ID 4-tuple) - - `proto` (transport protocol) - - `message_id` (LDAP message ID) - - `scope` (set of 1..n search scopes defined in this uid+message_id) - - `deref` (set of 1..n search deref alias options defined in this uid+message_id) - - `base_object` (vector of 0..n search base objects specified) - - `result_count` (number of result entries returned) - - `result` (set of 1..n results from this uid+message_id) - - `diagnostic_message` (vector of 0..n diagnostic message strings) - - `filter` (search filter string) - - `attributes` (vector of 0..n "attributes", the attributes that were returned) - - test - - basic tests for detecting plugin presence and simple bind and search result/requests - -Here's what it doesn't have, which could be added by future parties interested in expanding it: - -- LDAP [referrals](https://tools.ietf.org/html/rfc4511#section-4.1.10) are not parsed out of the results -- [SASL credentials](https://datatracker.ietf.org/doc/html/rfc4511#section-4.2) in bind requests are not being parsed beyond the mechanism string -- SASL information in bind responses are not being parsed; for that matter, SASL-based LDAP stuff hasn't been tested much and may have issues -- Search filters and attributes: the search filters, reconstructed from the query tree, is represented in string format. The AND and OR filters have a tree structure and are parsed with the `ParseNestedAndOr` unit, whereas the NOT filter consist of one single nested SearchFilter and is parsed with a `ParseNestedNot` unit. The remaining filter types can all be decoded to a string using the `DecodedAttributeValue` unit, which takes the `FilterType` as a parameter. The `FILTER_PRESENT` consists of a single octet string and can be parsed directly. By recursively constructing leafs and nodes in the tree, the final search filter can be represented, e.g. `(&(objectclass=*)(sAMAccountName=xxxxxxxx))`. The returned attributes are represented in a list and returned to the `ldap_search.log` if `option default_log_search_attributes = T;` is set (the default is False). -- the details of `SearchResultReference` are not being parsed -- the only detail of `ModifyRequest` being parsed is the object name -- the details of `AddRequest` are not being parsed -- the details of `ModDNRequest` are not being parsed -- the details of `CompareRequest` are not being parsed -- the details of `AbandonRequest` are not being parsed -- the details of `ExtendedRequest` are not being parsed -- the details of `ExtendedResponse` are not being parsed -- the details of `IntermediateResponse` are not being parsed -- [Logging policy](https://docs.zeek.org/en/master/frameworks/logging.html#filtering-log-records) is available. - -Useful Links: - -- -- -- -- -- diff --git a/src/spicy/spicy-ldap/zkg.meta b/src/spicy/spicy-ldap/zkg.meta deleted file mode 100644 index 4a51819fe9..0000000000 --- a/src/spicy/spicy-ldap/zkg.meta +++ /dev/null @@ -1,21 +0,0 @@ -[package] -summary = LDAP analyzer -description = An LDAP analyzer based on Spicy -script_dir = analyzer -plugin_dir = build/spicy-modules -build_command = mkdir -p build && cd build && SPICYZ=$(command -v spicyz || echo %(package_base)s/spicy-plugin/build/bin/spicyz) cmake .. && cmake --build . -test_command = cd tests && PATH=$(zkg config plugin_dir)/packages/spicy-plugin/bin:$PATH btest -d -j $(nproc) - -# We depend on spicy-plugin>=1.2.2, but currently cannot express that -# dependency due to zeek/package-manager#106 which has been fixed in -# zkg-2.12.0, but has not been released with zeek yet. -# depends = spicy-plugin >=1.2.2 - -[template] -source = package-template-spicy -version = master -zkg_version = 2.12.0 - -[template_vars] -namespace = LDAP -name = Messages From 42515574645f25dbb667a76de417608bafedd9e7 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 08:38:22 +0200 Subject: [PATCH 04/20] Fix typos in spicy-ldap --- .typos.toml | 2 ++ src/spicy/spicy-ldap/analyzer/ldap.spicy | 4 ++-- src/spicy/spicy-ldap/tests/traces/README | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.typos.toml b/.typos.toml index cc29d0abb1..06c59b1068 100644 --- a/.typos.toml +++ b/.typos.toml @@ -69,3 +69,5 @@ caf = "caf" helo = "helo" # Seems we use this in the management framework requestor = "requestor" +# `inout` is used as a keyword in Spicy, but looks like a typo of `input`. +inout = "inout" diff --git a/src/spicy/spicy-ldap/analyzer/ldap.spicy b/src/spicy/spicy-ldap/analyzer/ldap.spicy index a7be8af911..fab860c251 100644 --- a/src/spicy/spicy-ldap/analyzer/ldap.spicy +++ b/src/spicy/spicy-ldap/analyzer/ldap.spicy @@ -191,8 +191,8 @@ public type MessageWrapper = unit { 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 delimeter was not found, we - # leave the remainer empty, but note that the bytes must be consumed either way to avoid stalling the + # 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 ) { diff --git a/src/spicy/spicy-ldap/tests/traces/README b/src/spicy/spicy-ldap/tests/traces/README index 4858d99642..5a388dc70d 100644 --- a/src/spicy/spicy-ldap/tests/traces/README +++ b/src/spicy/spicy-ldap/tests/traces/README @@ -10,6 +10,6 @@ We collect them here for convenience only. - the LDAP flow selected (filtered out the Kerberos packets) - truncated to 10 packets (where packet 10 contains the SASL encrypted LDAP message) - - one `\x30` byte in the cyphertext changed to `\x00` + - one `\x30` byte in the ciphertext changed to `\x00` - ldap-issue-32.pcapng: Provided by GH user martinvanhensbergen, From 6e87f49ca800377bed5cbb94818a88893ae49395 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 08:42:11 +0200 Subject: [PATCH 05/20] Remove uses of `zeek` module in spicy-ldap --- src/spicy/spicy-ldap/analyzer/CMakeLists.txt | 2 +- src/spicy/spicy-ldap/analyzer/ldap.evt | 1 - src/spicy/spicy-ldap/analyzer/ldap.spicy | 4 ++++ src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy | 14 -------------- 4 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy diff --git a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt index 1bd759cf7c..e25ec7a828 100644 --- a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt +++ b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt @@ -1,4 +1,4 @@ spicy_add_analyzer( NAME LDAP PACKAGE_NAME spicy-ldap - SOURCES ldap.spicy ldap.evt ldap_zeek.spicy) + SOURCES ldap.spicy ldap.evt) diff --git a/src/spicy/spicy-ldap/analyzer/ldap.evt b/src/spicy/spicy-ldap/analyzer/ldap.evt index d255783998..bef6cb2af7 100644 --- a/src/spicy/spicy-ldap/analyzer/ldap.evt +++ b/src/spicy/spicy-ldap/analyzer/ldap.evt @@ -9,7 +9,6 @@ protocol analyzer spicy::LDAP_UDP over UDP: ports { 389/udp }; import LDAP; -import LDAP_Zeek; on LDAP::Message -> event LDAP::message($conn, self.messageID, diff --git a/src/spicy/spicy-ldap/analyzer/ldap.spicy b/src/spicy/spicy-ldap/analyzer/ldap.spicy index fab860c251..ee6dc74db9 100644 --- a/src/spicy/spicy-ldap/analyzer/ldap.spicy +++ b/src/spicy/spicy-ldap/analyzer/ldap.spicy @@ -869,3 +869,7 @@ type AbandonRequest = unit(inout message: Message) { # type IntermediateResponse = unit(inout message: Message) { # # }; + +on LDAP::MessageWrapper::%done { + spicy::accept_input(); +} diff --git a/src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy b/src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy deleted file mode 100644 index d0f9c7fd4d..0000000000 --- a/src/spicy/spicy-ldap/analyzer/ldap_zeek.spicy +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2021 by the Zeek Project. See LICENSE for details. - -module LDAP_Zeek; - -import zeek; -import LDAP; - -on LDAP::MessageWrapper::%done { - zeek::confirm_protocol(); -} - -on LDAP::MessageWrapper::%error { - zeek::reject_protocol("error while parsing LDAP message"); -} From cfe24189f204d36852c9a0b58afa39471730d34f Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 09:42:31 +0200 Subject: [PATCH 06/20] Explicitly list `asn1.spicy` as spicy-ldap source This will lead to the file being installed so it can be consumed by other parsers. --- src/spicy/spicy-ldap/analyzer/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt index e25ec7a828..fb264f0038 100644 --- a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt +++ b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt @@ -1,4 +1,4 @@ spicy_add_analyzer( NAME LDAP PACKAGE_NAME spicy-ldap - SOURCES ldap.spicy ldap.evt) + SOURCES ldap.spicy ldap.evt asn1.spicy) From e5445409861735fc62bb0b384b4af5dc74b66147 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 10:13:02 +0200 Subject: [PATCH 07/20] Explicitly use all of spicy-ldap's modules This fixes building of this multi-module analyzer. --- .cmake-format.json | 3 ++- src/spicy/spicy-ldap/analyzer/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.cmake-format.json b/.cmake-format.json index 3061265a04..cb071ca269 100644 --- a/.cmake-format.json +++ b/.cmake-format.json @@ -69,7 +69,8 @@ "kwargs": { "NAME": "*", "PACKAGE_NAME": "*", - "SOURCES": "*" + "SOURCES": "*", + "MODULES": "*" } } } diff --git a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt index fb264f0038..a687e880ff 100644 --- a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt +++ b/src/spicy/spicy-ldap/analyzer/CMakeLists.txt @@ -1,4 +1,5 @@ spicy_add_analyzer( NAME LDAP PACKAGE_NAME spicy-ldap - SOURCES ldap.spicy ldap.evt asn1.spicy) + SOURCES ldap.spicy ldap.evt asn1.spicy + MODULES LDAP ASN1) From f172febbcb037523c9ff5f7fd07dd6ae04275b7f Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 10:44:14 +0200 Subject: [PATCH 08/20] Move spicy-ldap into Zeek protocol analyzer tree --- scripts/base/init-default.zeek | 1 + .../base/protocols/ldap}/__load__.zeek | 0 .../analyzer => scripts/base/protocols/ldap}/dpd.sig | 4 ++-- .../base/protocols/ldap}/main.zeek | 4 ++-- src/analyzer/protocol/CMakeLists.txt | 1 + .../protocol/ldap}/CMakeLists.txt | 0 .../analyzer => analyzer/protocol/ldap}/asn1.spicy | 0 .../analyzer => analyzer/protocol/ldap}/ldap.evt | 4 ++-- .../analyzer => analyzer/protocol/ldap}/ldap.spicy | 0 src/spicy/CMakeLists.txt | 2 -- src/spicy/spicy-ldap/CMakeLists.txt | 1 - .../spicy-ldap/tests/analyzer/availability.zeek | 2 +- .../canonified_loaded_scripts.log | 2 ++ testing/btest/Baseline/coverage.find-bro-logs/out | 2 ++ .../Baseline/scripts.base.files.x509.files/files.log | 12 ++++++------ .../Baseline/spicy.port-range-one-port/out.filtered | 3 +++ 16 files changed, 22 insertions(+), 16 deletions(-) rename {src/spicy/spicy-ldap/analyzer => scripts/base/protocols/ldap}/__load__.zeek (100%) rename {src/spicy/spicy-ldap/analyzer => scripts/base/protocols/ldap}/dpd.sig (88%) rename {src/spicy/spicy-ldap/analyzer => scripts/base/protocols/ldap}/main.zeek (99%) rename src/{spicy/spicy-ldap/analyzer => analyzer/protocol/ldap}/CMakeLists.txt (100%) rename src/{spicy/spicy-ldap/analyzer => analyzer/protocol/ldap}/asn1.spicy (100%) rename src/{spicy/spicy-ldap/analyzer => analyzer/protocol/ldap}/ldap.evt (95%) rename src/{spicy/spicy-ldap/analyzer => analyzer/protocol/ldap}/ldap.spicy (100%) delete mode 100644 src/spicy/spicy-ldap/CMakeLists.txt diff --git a/scripts/base/init-default.zeek b/scripts/base/init-default.zeek index cbfcca571d..b7d11dfbd2 100644 --- a/scripts/base/init-default.zeek +++ b/scripts/base/init-default.zeek @@ -59,6 +59,7 @@ @load base/protocols/imap @load base/protocols/irc @load base/protocols/krb +@load base/protocols/ldap @load base/protocols/modbus @load base/protocols/mqtt @load base/protocols/mysql diff --git a/src/spicy/spicy-ldap/analyzer/__load__.zeek b/scripts/base/protocols/ldap/__load__.zeek similarity index 100% rename from src/spicy/spicy-ldap/analyzer/__load__.zeek rename to scripts/base/protocols/ldap/__load__.zeek diff --git a/src/spicy/spicy-ldap/analyzer/dpd.sig b/scripts/base/protocols/ldap/dpd.sig similarity index 88% rename from src/spicy/spicy-ldap/analyzer/dpd.sig rename to scripts/base/protocols/ldap/dpd.sig index dc734e5554..bf545ed375 100644 --- a/src/spicy/spicy-ldap/analyzer/dpd.sig +++ b/scripts/base/protocols/ldap/dpd.sig @@ -7,7 +7,7 @@ signature dpd_ldap_server_udp { ip-proto == udp payload /^\x30/ requires-reverse-signature dpd_ldap_client_udp - enable "spicy_LDAP_UDP" + enable "LDAP_UDP" } signature dpd_ldap_client_tcp { @@ -19,5 +19,5 @@ signature dpd_ldap_server_tcp { ip-proto == tcp payload /^\x30/ requires-reverse-signature dpd_ldap_client_tcp - enable "spicy_LDAP_TCP" + enable "LDAP_TCP" } diff --git a/src/spicy/spicy-ldap/analyzer/main.zeek b/scripts/base/protocols/ldap/main.zeek similarity index 99% rename from src/spicy/spicy-ldap/analyzer/main.zeek rename to scripts/base/protocols/ldap/main.zeek index 44955bffb0..1cdff64292 100644 --- a/src/spicy/spicy-ldap/analyzer/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -292,7 +292,7 @@ function set_session(c: connection, message_id: int, opcode: LDAP::ProtocolOpcod ############################################################################# @if (Version::at_least("5.2.0")) event analyzer_confirmation_info(atype: AllAnalyzers::Tag, info: AnalyzerConfirmationInfo) { - if ( atype == Analyzer::ANALYZER_SPICY_LDAP_TCP ) { + if ( atype == Analyzer::ANALYZER_LDAP_TCP ) { info$c$ldap_proto = "tcp"; } } @@ -302,7 +302,7 @@ event analyzer_confirmation(c: connection, atype: AllAnalyzers::Tag, aid: count) event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) { @endif - if ( atype == Analyzer::ANALYZER_SPICY_LDAP_TCP ) { + if ( atype == Analyzer::ANALYZER_LDAP_TCP ) { c$ldap_proto = "tcp"; } diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 4ea6642255..314a965730 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(ident) add_subdirectory(imap) add_subdirectory(irc) add_subdirectory(krb) +add_subdirectory(ldap) add_subdirectory(login) add_subdirectory(mime) add_subdirectory(modbus) diff --git a/src/spicy/spicy-ldap/analyzer/CMakeLists.txt b/src/analyzer/protocol/ldap/CMakeLists.txt similarity index 100% rename from src/spicy/spicy-ldap/analyzer/CMakeLists.txt rename to src/analyzer/protocol/ldap/CMakeLists.txt diff --git a/src/spicy/spicy-ldap/analyzer/asn1.spicy b/src/analyzer/protocol/ldap/asn1.spicy similarity index 100% rename from src/spicy/spicy-ldap/analyzer/asn1.spicy rename to src/analyzer/protocol/ldap/asn1.spicy diff --git a/src/spicy/spicy-ldap/analyzer/ldap.evt b/src/analyzer/protocol/ldap/ldap.evt similarity index 95% rename from src/spicy/spicy-ldap/analyzer/ldap.evt rename to src/analyzer/protocol/ldap/ldap.evt index bef6cb2af7..6b217348b1 100644 --- a/src/spicy/spicy-ldap/analyzer/ldap.evt +++ b/src/analyzer/protocol/ldap/ldap.evt @@ -1,10 +1,10 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -protocol analyzer spicy::LDAP_TCP over TCP: +protocol analyzer LDAP_TCP over TCP: parse with LDAP::Messages, ports { 389/tcp, 3268/tcp}; -protocol analyzer spicy::LDAP_UDP over UDP: +protocol analyzer LDAP_UDP over UDP: parse with LDAP::Messages, ports { 389/udp }; diff --git a/src/spicy/spicy-ldap/analyzer/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy similarity index 100% rename from src/spicy/spicy-ldap/analyzer/ldap.spicy rename to src/analyzer/protocol/ldap/ldap.spicy diff --git a/src/spicy/CMakeLists.txt b/src/spicy/CMakeLists.txt index e997004cd2..8d3d625dd7 100644 --- a/src/spicy/CMakeLists.txt +++ b/src/spicy/CMakeLists.txt @@ -28,5 +28,3 @@ install(DIRECTORY "${PROJECT_SOURCE_DIR}/scripts/spicy/" DESTINATION "${ZEEK_SPI set(ZEEK_SPICY_DATA_PATH "${CMAKE_INSTALL_FULL_DATADIR}/zeek" CACHE PATH "") add_subdirectory(spicyz) - -add_subdirectory(spicy-ldap) diff --git a/src/spicy/spicy-ldap/CMakeLists.txt b/src/spicy/spicy-ldap/CMakeLists.txt deleted file mode 100644 index d17735d5b4..0000000000 --- a/src/spicy/spicy-ldap/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(analyzer) diff --git a/src/spicy/spicy-ldap/tests/analyzer/availability.zeek b/src/spicy/spicy-ldap/tests/analyzer/availability.zeek index 7c48f3e015..44234ac15d 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/availability.zeek +++ b/src/spicy/spicy-ldap/tests/analyzer/availability.zeek @@ -1,5 +1,5 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -# @TEST-EXEC: zeek -NN | grep -q ANALYZER_SPICY_LDAP_TCP +# @TEST-EXEC: zeek -NN | grep -q ANALYZER_LDAP_TCP # # @TEST-DOC: Check that LDAP (TCP) is analyzer is available. 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 7ad3d68c64..2b87b5796f 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 @@ -406,6 +406,8 @@ scripts/base/init-default.zeek scripts/base/protocols/krb/main.zeek scripts/base/protocols/krb/consts.zeek scripts/base/protocols/krb/files.zeek + scripts/base/protocols/ldap/__load__.zeek + scripts/base/protocols/ldap/main.zeek scripts/base/protocols/modbus/__load__.zeek scripts/base/protocols/modbus/consts.zeek scripts/base/protocols/modbus/main.zeek diff --git a/testing/btest/Baseline/coverage.find-bro-logs/out b/testing/btest/Baseline/coverage.find-bro-logs/out index f410d976ab..bd3b78858e 100644 --- a/testing/btest/Baseline/coverage.find-bro-logs/out +++ b/testing/btest/Baseline/coverage.find-bro-logs/out @@ -20,6 +20,8 @@ known_certs known_hosts known_modbus known_services +ldap +ldap_search loaded_scripts modbus modbus_register_change diff --git a/testing/btest/Baseline/scripts.base.files.x509.files/files.log b/testing/btest/Baseline/scripts.base.files.x509.files/files.log index e64dfc52c0..ce19924fa1 100644 --- a/testing/btest/Baseline/scripts.base.files.x509.files/files.log +++ b/testing/btest/Baseline/scripts.base.files.x509.files/files.log @@ -7,10 +7,10 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid md5 sha1 sha256 #types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string string string -XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 -XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d -XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 -XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 -XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d -XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 +XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 +XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d +XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 +XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 +XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d +XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/spicy.port-range-one-port/out.filtered b/testing/btest/Baseline/spicy.port-range-one-port/out.filtered index 293b1047f3..708e225624 100644 --- a/testing/btest/Baseline/spicy.port-range-one-port/out.filtered +++ b/testing/btest/Baseline/spicy.port-range-one-port/out.filtered @@ -1,2 +1,5 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[zeek] Scheduling analyzer for port 389/tcp +[zeek] Scheduling analyzer for port 3268/tcp +[zeek] Scheduling analyzer for port 389/udp [zeek] Scheduling analyzer for port 31336/udp From d7db52dff6a8af0bc7f81f5a51aba0d213cbdf04 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 08:53:52 +0200 Subject: [PATCH 09/20] Integrate spicy-ldap test suite --- .../tests/baseline/analyzer.log_policy/output | 2 -- .../ldap_search.log | 12 ------- src/spicy/spicy-ldap/tests/btest.cfg | 34 ------------------ .../tests/scripts/zeek-path-install | 5 --- src/spicy/spicy-ldap/tests/traces/README | 15 -------- .../tests/traces/ldap-issue-32.pcapng | Bin 1436 -> 0 bytes .../coverage.record-fields/out.default | 33 +++++++++++++++++ .../conn.log | 3 +- .../ldap.log | 3 +- .../ldap_search.log | 3 +- .../conn.log | 3 +- .../ldap.log | 3 +- .../ldap_search.log | 3 +- .../scripts.base.protocols.ldap.basic}/output | 3 -- .../conn.log | 3 +- .../ldap.log | 3 +- .../ldap_search.log | 3 +- .../conn.log | 3 +- .../output | 1 - .../conn.log | 3 +- .../ldap.log | 3 +- .../ldap_search.log | 3 +- testing/btest/Traces/README | 13 ++++++- .../btest/Traces/ldap}/issue-32.pcapng | Bin .../btest/Traces/ldap/krb5-sign-seal-01.pcap | Bin .../Traces/ldap/simpleauth-diff-port.pcap | Bin .../btest/Traces/ldap/simpleauth.pcap | Bin .../base/protocols/ldap}/attributes.zeek | 4 +-- .../base/protocols/ldap}/availability.zeek | 0 .../scripts/base/protocols/ldap}/basic.zeek | 4 +-- .../base/protocols/ldap}/diff_port.zeek | 4 +-- .../base/protocols/ldap}/functions.spicy | 5 ++- .../base/protocols/ldap}/log_policy.zeek | 4 +-- .../base/protocols/ldap}/sasl-encrypted.zeek | 4 +-- .../ldap}/search_filter_extended.zeek | 0 35 files changed, 67 insertions(+), 115 deletions(-) delete mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output delete mode 100644 src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log delete mode 100644 src/spicy/spicy-ldap/tests/btest.cfg delete mode 100755 src/spicy/spicy-ldap/tests/scripts/zeek-path-install delete mode 100644 src/spicy/spicy-ldap/tests/traces/README delete mode 100644 src/spicy/spicy-ldap/tests/traces/ldap-issue-32.pcapng rename {src/spicy/spicy-ldap/tests/baseline/analyzer.attributes => testing/btest/Baseline/scripts.base.protocols.ldap.attributes}/conn.log (84%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.basic => testing/btest/Baseline/scripts.base.protocols.ldap.attributes}/ldap.log (94%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.attributes => testing/btest/Baseline/scripts.base.protocols.ldap.attributes}/ldap_search.log (93%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy => testing/btest/Baseline/scripts.base.protocols.ldap.basic}/conn.log (84%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.attributes => testing/btest/Baseline/scripts.base.protocols.ldap.basic}/ldap.log (94%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.basic => testing/btest/Baseline/scripts.base.protocols.ldap.basic}/ldap_search.log (93%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.parse => testing/btest/Baseline/scripts.base.protocols.ldap.basic}/output (73%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.basic => testing/btest/Baseline/scripts.base.protocols.ldap.diff_port}/conn.log (84%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port => testing/btest/Baseline/scripts.base.protocols.ldap.diff_port}/ldap.log (94%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port => testing/btest/Baseline/scripts.base.protocols.ldap.diff_port}/ldap_search.log (93%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port => testing/btest/Baseline/scripts.base.protocols.ldap.log_policy}/conn.log (84%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.basic => testing/btest/Baseline/scripts.base.protocols.ldap.log_policy}/output (68%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted => testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted}/conn.log (83%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted => testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted}/ldap.log (92%) rename {src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted => testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted}/ldap_search.log (92%) rename {src/spicy/spicy-ldap/tests/traces => testing/btest/Traces/ldap}/issue-32.pcapng (100%) rename src/spicy/spicy-ldap/tests/traces/ldap-krb5-sign-seal-01.pcap => testing/btest/Traces/ldap/krb5-sign-seal-01.pcap (100%) rename src/spicy/spicy-ldap/tests/traces/ldap-simpleauth-diff-port.pcap => testing/btest/Traces/ldap/simpleauth-diff-port.pcap (100%) rename src/spicy/spicy-ldap/tests/traces/ldap-simpleauth.pcap => testing/btest/Traces/ldap/simpleauth.pcap (100%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/attributes.zeek (83%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/availability.zeek (100%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/basic.zeek (82%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/diff_port.zeek (80%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/functions.spicy (96%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/log_policy.zeek (88%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/sasl-encrypted.zeek (83%) rename {src/spicy/spicy-ldap/tests/analyzer => testing/btest/scripts/base/protocols/ldap}/search_filter_extended.zeek (100%) diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output b/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output deleted file mode 100644 index b1bb951e92..0000000000 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/output +++ /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. -### NOTE: This file has been sorted with diff-sort. diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log b/src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log deleted file mode 100644 index 555a1c7270..0000000000 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.search_filter_extended/ldap_search.log +++ /dev/null @@ -1,12 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. -#separator \x09 -#set_separator , -#empty_field (empty) -#unset_field - -#path ldap_search -#open XXXX-XX-XX-XX-XX-XX -#fields uid filter base_object -#types string string vector[string] -#close XXXX-XX-XX-XX-XX-XX -CHhAvVGS1DHFjwGM9 (departmentNumber:2.16.840.1.113730.3.3.2.46.1:=>=N4709) DC=matrix\x2cDC=local diff --git a/src/spicy/spicy-ldap/tests/btest.cfg b/src/spicy/spicy-ldap/tests/btest.cfg deleted file mode 100644 index 914dea4dde..0000000000 --- a/src/spicy/spicy-ldap/tests/btest.cfg +++ /dev/null @@ -1,34 +0,0 @@ -[btest] -MinVersion = 0.66 - -TestDirs = analyzer -TmpDir = %(testbase)s/.tmp -BaselineDir = %(testbase)s/baseline -IgnoreDirs = .svn CVS .tmp Baseline Failing traces Traces -IgnoreFiles = .DS_Store *.pcap data.* *.dat *.wmv *.der *.tmp *.swp .*.swp #* CMakeLists.txt - -[environment] -DIST=%(testbase)s/.. -PATH=%(testbase)s/../tests/scripts:`spicyz --print-plugin-path`/tests/scripts:%(default_path)s -SCRIPTS=`spicyz --print-plugin-path`/tests/Scripts -ZEEK_SPICY_MODULE_PATH=%(testbase)s/../build/spicy-modules -TEST_DIFF_CANONIFIER=`spicyz --print-plugin-path`/tests/Scripts/canonify-zeek-log-sorted -TRACES=%(testbase)s/traces -ZEEKPATH=%(testbase)s/..:`zeek-config --zeekpath` -ZEEK_SEED_FILE=`spicyz --print-plugin-path`/tests/random.seed - -# Set variables to well-defined state. -LANG=C -LC_ALL=C -TZ=UTC -CC= -CXX= -CFLAGS= -CPPFLAGS= -CXXFLAGS= -LDFLAGS= -DYLDFLAGS= - -[environment-installation] -ZEEK_SPICY_MODULE_PATH= -ZEEKPATH=`%(testbase)s/scripts/zeek-path-install` diff --git a/src/spicy/spicy-ldap/tests/scripts/zeek-path-install b/src/spicy/spicy-ldap/tests/scripts/zeek-path-install deleted file mode 100755 index 3ce6131d6d..0000000000 --- a/src/spicy/spicy-ldap/tests/scripts/zeek-path-install +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh -# -# Assembles the Zeek path for testing the installed version (can't do that in btest.cfg directly). - -echo $(spicyz --print-scripts-path):$(zkg config script_dir):$(zeek-config --zeekpath) diff --git a/src/spicy/spicy-ldap/tests/traces/README b/src/spicy/spicy-ldap/tests/traces/README deleted file mode 100644 index 5a388dc70d..0000000000 --- a/src/spicy/spicy-ldap/tests/traces/README +++ /dev/null @@ -1,15 +0,0 @@ -The test suite comes with a set of traces collected from a variety of -places that we document below. While these traces are all coming from -public sources, please note that they may carry their own licenses. -We collect them here for convenience only. - -- [ldap-simpleauth.pcap](https://github.com/arkime/arkime/blob/main/tests/pcap/ldap-simpleauth.pcap) -- ldap-simpleauth-diff-port.pcap: made with - `tcprewrite -r 3268:32681 -i ldap-simpleauth.pcap -o ldap-simpleauth-diff-port.pcap` -- ldap-krb5-sign-seal-01.pcap: trace is derived from - - - the LDAP flow selected (filtered out the Kerberos packets) - - truncated to 10 packets (where packet 10 contains the SASL encrypted LDAP message) - - one `\x30` byte in the ciphertext changed to `\x00` -- ldap-issue-32.pcapng: Provided by GH user martinvanhensbergen, - diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-issue-32.pcapng b/src/spicy/spicy-ldap/tests/traces/ldap-issue-32.pcapng deleted file mode 100644 index 8ed316dd51f5a6cc15291ecdf73b87d2e7062fed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1436 zcmai!&rcIU6vt=Fwm^kg5&0zv6BEsr((Nq$ZG@Dz$d3qVK%?=*(yp+f-7ULYpz1*c z5);D3faOR$;SH}QCMKvPCLWFc111O_Jb2eP+nUgZ;@f?@Z+2!r^Y%M0V{dGmVGg;FCcCg;Q%DTPJ7)bA#)lr${}Il&1mYBYD6cN}~koUUMj3`8Z5>Y=9|zBHVX z51m2h+Q2adfxT3pwSN2BQ82;u8w-&QH8}To^9a?!AD~}dM-ddUtvq_SYu^Tcv$@5r zDaW3}^=Qj#qV4=>VGSX&{K3N5l6kf%9_!19h9)odK$KRKV%pAF>`aY?L2xq+dKF&o z?B#_3AMz1i;03`O^b+0+7f2l7g{O{`lod52BPqssE;B7@E4BT7;w(#5t2z%a3b*Y5`wC>xj)_VSclw zE>xfG6Z-scafL-_QwJ;RvvIIo)Q6b~wMWnsTlW{L4b_NQ+uWksD92}8+8FcKYqn7!aQf!5JEX3DJEGxt(jjr(*ROeGp diff --git a/testing/btest/Baseline/coverage.record-fields/out.default b/testing/btest/Baseline/coverage.record-fields/out.default index 25d9e950bf..68d049e536 100644 --- a/testing/btest/Baseline/coverage.record-fields/out.default +++ b/testing/btest/Baseline/coverage.record-fields/out.default @@ -360,6 +360,39 @@ connection { * ts: time, log=T, optional=F * uid: string, log=T, optional=F } + * ldap_messages: table[int] of record LDAP::Message, log=F, optional=T + LDAP::Message { + * argument: vector of string, log=T, optional=T + * diagnostic_message: vector of string, log=T, optional=T + * id: record conn_id, log=T, optional=F + conn_id { ... } + * message_id: int, log=T, optional=T + * object: vector of string, log=T, optional=T + * opcode: set[string], log=T, optional=T + * proto: string, log=T, optional=T + * result: set[string], log=T, optional=T + * ts: time, log=T, optional=F + * uid: string, log=T, optional=F + * version: int, log=T, optional=T + } + * ldap_proto: string, log=F, optional=T + * ldap_searches: table[int] of record LDAP::Search, log=F, optional=T + LDAP::Search { + * attributes: vector of string, log=T, optional=T + * base_object: vector of string, log=T, optional=T + * deref: set[string], log=T, optional=T + * diagnostic_message: vector of string, log=T, optional=T + * filter: string, log=T, optional=T + * id: record conn_id, log=T, optional=F + conn_id { ... } + * message_id: int, log=T, optional=T + * proto: string, log=T, optional=T + * result: set[string], log=T, optional=T + * result_count: count, log=T, optional=T + * scope: set[string], log=T, optional=T + * ts: time, log=T, optional=F + * uid: string, log=T, optional=F + } * modbus: record Modbus::Info, log=F, optional=T Modbus::Info { * exception: string, log=T, optional=T diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/conn.log similarity index 84% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.attributes/conn.log index 3bdde7206c..a69f1ec56a 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/conn.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/conn.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #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.0.0.1 25936 10.0.0.2 3268 tcp ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - #close XXXX-XX-XX-XX-XX-XX -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log similarity index 94% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log index 462cec25c7..8f50988763 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,6 +7,6 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcode result diagnostic_message object argument #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log similarity index 93% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log index 954b0a5d01..ad4567a0a2 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scope deref base_object result_count result diagnostic_message filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) sAMAccountName +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/conn.log similarity index 84% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.basic/conn.log index 3bdde7206c..a69f1ec56a 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.log_policy/conn.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/conn.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #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.0.0.1 25936 10.0.0.2 3268 tcp ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - #close XXXX-XX-XX-XX-XX-XX -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log similarity index 94% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log index 462cec25c7..8f50988763 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.attributes/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,6 +7,6 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcode result diagnostic_message object argument #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log similarity index 93% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log index 9bc7fa70de..1497e67a58 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scope deref base_object result_count result diagnostic_message filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/output similarity index 73% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output rename to testing/btest/Baseline/scripts.base.protocols.ldap.basic/output index c07b15461b..49d861c74c 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.parse/output +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/output @@ -1,4 +1 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -LDAP::Messages { - payload: test string -} diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/conn.log similarity index 84% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/conn.log index 3bdde7206c..f60bcc1b32 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/conn.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/conn.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #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.0.0.1 25936 10.0.0.2 32681 tcp ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - #close XXXX-XX-XX-XX-XX-XX -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log similarity index 94% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log index 4cebad26c1..5c2ec47c69 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,6 +7,6 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcode result diagnostic_message object argument #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log similarity index 93% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log index 7d50764ff7..5113c76d90 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scope deref base_object result_count result diagnostic_message filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.log_policy/conn.log similarity index 84% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.log_policy/conn.log index 2d87050cfa..a69f1ec56a 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.diff_port/conn.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.log_policy/conn.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #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.0.0.1 25936 10.0.0.2 3268 tcp ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - #close XXXX-XX-XX-XX-XX-XX -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp spicy_ldap_tcp 181.520479 258 188 RSTO 0 ShADdR 8 590 4 360 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output b/testing/btest/Baseline/scripts.base.protocols.ldap.log_policy/output similarity index 68% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output rename to testing/btest/Baseline/scripts.base.protocols.ldap.log_policy/output index b1bb951e92..49d861c74c 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.basic/output +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.log_policy/output @@ -1,2 +1 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/conn.log similarity index 83% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/conn.log index 3159ed4b82..eaaa60672a 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/conn.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/conn.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #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 172.31.1.104 3116 172.31.1.101 389 tcp ldap_tcp 0.813275 1814 2391 S1 0 ShADd 6 2062 4 2559 - #close XXXX-XX-XX-XX-XX-XX -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp spicy_ldap_tcp 0.813275 1814 2391 S1 0 ShADd 6 2062 4 2559 - diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log similarity index 92% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log index 40dd1d3672..a1f0e5f0b8 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcode result diagnostic_message object argument #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 215 3 bind SASL success - - GSS-SPNEGO +#close XXXX-XX-XX-XX-XX-XX diff --git a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log similarity index 92% rename from src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.log rename to testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log index 7ad3fbccb5..0436cc9f1c 100644 --- a/src/spicy/spicy-ldap/tests/baseline/analyzer.sasl-encrypted/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log @@ -1,5 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -### NOTE: This file has been sorted with diff-sort. #separator \x09 #set_separator , #empty_field (empty) @@ -8,5 +7,5 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scope deref base_object result_count result diagnostic_message filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -#close XXXX-XX-XX-XX-XX-XX XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 213 base never - 1 success - (objectclass=*) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/README b/testing/btest/Traces/README index f7ea25b807..bc5a304436 100644 --- a/testing/btest/Traces/README +++ b/testing/btest/Traces/README @@ -6,4 +6,15 @@ depend on them for tests. Trace Index/Sources: -- modbus/modbus-eit.trace: Sourced from https://www.netresec.com/?page=PCAP4SICS, credit to https://cs3sthlm.se/. The packets in this trace were pulled from the 4SICS-GeekLounge-151021.pcap file. \ No newline at end of file +- modbus/modbus-eit.trace: Sourced from https://www.netresec.com/?page=PCAP4SICS, credit to https://cs3sthlm.se/. The packets in this trace were pulled from the 4SICS-GeekLounge-151021.pcap file. + +- [ldap/simpleauth.pcap](https://github.com/arkime/arkime/blob/main/tests/pcap/ldap-simpleauth.pcap) +- ldap/simpleauth-diff-port.pcap: made with + `tcprewrite -r 3268:32681 -i simpleauth.pcap -o simpleauth-diff-port.pcap` +- ldap/krb5-sign-seal-01.pcap: trace is derived from + + - the LDAP flow selected (filtered out the Kerberos packets) + - truncated to 10 packets (where packet 10 contains the SASL encrypted LDAP message) + - one `\x30` byte in the ciphertext changed to `\x00` +- ldap/issue-32.pcapng: Provided by GH user martinvanhensbergen, + diff --git a/src/spicy/spicy-ldap/tests/traces/issue-32.pcapng b/testing/btest/Traces/ldap/issue-32.pcapng similarity index 100% rename from src/spicy/spicy-ldap/tests/traces/issue-32.pcapng rename to testing/btest/Traces/ldap/issue-32.pcapng diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-krb5-sign-seal-01.pcap b/testing/btest/Traces/ldap/krb5-sign-seal-01.pcap similarity index 100% rename from src/spicy/spicy-ldap/tests/traces/ldap-krb5-sign-seal-01.pcap rename to testing/btest/Traces/ldap/krb5-sign-seal-01.pcap diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-simpleauth-diff-port.pcap b/testing/btest/Traces/ldap/simpleauth-diff-port.pcap similarity index 100% rename from src/spicy/spicy-ldap/tests/traces/ldap-simpleauth-diff-port.pcap rename to testing/btest/Traces/ldap/simpleauth-diff-port.pcap diff --git a/src/spicy/spicy-ldap/tests/traces/ldap-simpleauth.pcap b/testing/btest/Traces/ldap/simpleauth.pcap similarity index 100% rename from src/spicy/spicy-ldap/tests/traces/ldap-simpleauth.pcap rename to testing/btest/Traces/ldap/simpleauth.pcap diff --git a/src/spicy/spicy-ldap/tests/analyzer/attributes.zeek b/testing/btest/scripts/base/protocols/ldap/attributes.zeek similarity index 83% rename from src/spicy/spicy-ldap/tests/analyzer/attributes.zeek rename to testing/btest/scripts/base/protocols/ldap/attributes.zeek index e20cf7cc6b..bc482ebbfa 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/attributes.zeek +++ b/testing/btest/scripts/base/protocols/ldap/attributes.zeek @@ -1,6 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth.pcap %INPUT +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth.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 @@ -8,6 +8,4 @@ # # @TEST-DOC: Test LDAP search attributes with small trace. -@load analyzer - redef LDAP::default_log_search_attributes = T; diff --git a/src/spicy/spicy-ldap/tests/analyzer/availability.zeek b/testing/btest/scripts/base/protocols/ldap/availability.zeek similarity index 100% rename from src/spicy/spicy-ldap/tests/analyzer/availability.zeek rename to testing/btest/scripts/base/protocols/ldap/availability.zeek diff --git a/src/spicy/spicy-ldap/tests/analyzer/basic.zeek b/testing/btest/scripts/base/protocols/ldap/basic.zeek similarity index 82% rename from src/spicy/spicy-ldap/tests/analyzer/basic.zeek rename to testing/btest/scripts/base/protocols/ldap/basic.zeek index c7bb23e16e..b5753b1fea 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/basic.zeek +++ b/testing/btest/scripts/base/protocols/ldap/basic.zeek @@ -1,6 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth.pcap %INPUT >output 2>&1 +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth.pcap %INPUT >output 2>&1 # @TEST-EXEC: btest-diff output # @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 @@ -8,5 +8,3 @@ # @TEST-EXEC: btest-diff ldap_search.log # # @TEST-DOC: Test LDAP analyzer with small trace. - -@load analyzer diff --git a/src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek b/testing/btest/scripts/base/protocols/ldap/diff_port.zeek similarity index 80% rename from src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek rename to testing/btest/scripts/base/protocols/ldap/diff_port.zeek index 5e415fbb69..565903355d 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/diff_port.zeek +++ b/testing/btest/scripts/base/protocols/ldap/diff_port.zeek @@ -1,11 +1,9 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth-diff-port.pcap %INPUT +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth-diff-port.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-DOC: Test LDAP analyzer with small trace. - -@load analyzer diff --git a/src/spicy/spicy-ldap/tests/analyzer/functions.spicy b/testing/btest/scripts/base/protocols/ldap/functions.spicy similarity index 96% rename from src/spicy/spicy-ldap/tests/analyzer/functions.spicy rename to testing/btest/scripts/base/protocols/ldap/functions.spicy index 5679dba650..4bcc721673 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/functions.spicy +++ b/testing/btest/scripts/base/protocols/ldap/functions.spicy @@ -1,4 +1,7 @@ -# @TEST-EXEC: spicyc -j -d -L ${DIST}/analyzer %INPUT +# This test can only run if we have the LDAP grammar available. +# @TEST-REQUIRES: [ -n ${DIST} ] +# +# @TEST-EXEC: spicyc -j -d -L ${DIST}/src/analyzer/protocol/ldap %INPUT # # @TEST-DOC: Validates helper functions in LDAP module. diff --git a/src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek b/testing/btest/scripts/base/protocols/ldap/log_policy.zeek similarity index 88% rename from src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek rename to testing/btest/scripts/base/protocols/ldap/log_policy.zeek index 0a642223db..0317fc6a7d 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/log_policy.zeek +++ b/testing/btest/scripts/base/protocols/ldap/log_policy.zeek @@ -1,6 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-simpleauth.pcap %INPUT >output 2>&1 +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth.pcap %INPUT >output 2>&1 # @TEST-EXEC: btest-diff output # @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 @@ -9,8 +9,6 @@ # # @TEST-DOC: Test LDAP analyzer with small trace using logging policies. -@load analyzer - hook LDAP::log_policy(rec: LDAP::Message, id: Log::ID, filter: Log::Filter) { break; diff --git a/src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek similarity index 83% rename from src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek rename to testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek index 52bbce73cb..f84f979237 100644 --- a/src/spicy/spicy-ldap/tests/analyzer/sasl-encrypted.zeek +++ b/testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek @@ -1,6 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. -# @TEST-EXEC: zeek -C -r ${TRACES}/ldap-krb5-sign-seal-01.pcap %INPUT +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/krb5-sign-seal-01.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 @@ -9,5 +9,3 @@ # @TEST-EXEC: ! test -f dpd.log # # @TEST-DOC: Test LDAP analyzer with SASL encrypted payloads. - -@load analyzer diff --git a/src/spicy/spicy-ldap/tests/analyzer/search_filter_extended.zeek b/testing/btest/scripts/base/protocols/ldap/search_filter_extended.zeek similarity index 100% rename from src/spicy/spicy-ldap/tests/analyzer/search_filter_extended.zeek rename to testing/btest/scripts/base/protocols/ldap/search_filter_extended.zeek From 20ae1129eaf6bc5b52aaa52cb331edccb726dce2 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 12:40:52 +0200 Subject: [PATCH 10/20] Bump zeek-testing-private --- testing/external/commit-hash.zeek-testing-private | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/external/commit-hash.zeek-testing-private b/testing/external/commit-hash.zeek-testing-private index 2772323aa6..a9a63fa39f 100644 --- a/testing/external/commit-hash.zeek-testing-private +++ b/testing/external/commit-hash.zeek-testing-private @@ -1 +1 @@ -e2bcf374b7f03f95f7280568eab31600d58812ae +718bc67ea10606ec29acfdae05c463518319e8f2 From 53d4052d682e9d22155da51840e5bc765dc86907 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Mon, 18 Sep 2023 14:26:15 +0200 Subject: [PATCH 11/20] Fix LDAP analyzer setup for when Spicy analyzers are disabled --- scripts/base/protocols/ldap/__load__.zeek | 2 ++ testing/btest/scripts/base/protocols/ldap/attributes.zeek | 1 + testing/btest/scripts/base/protocols/ldap/availability.zeek | 1 + testing/btest/scripts/base/protocols/ldap/basic.zeek | 1 + testing/btest/scripts/base/protocols/ldap/diff_port.zeek | 1 + testing/btest/scripts/base/protocols/ldap/functions.spicy | 2 +- testing/btest/scripts/base/protocols/ldap/log_policy.zeek | 1 + testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek | 1 + 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/base/protocols/ldap/__load__.zeek b/scripts/base/protocols/ldap/__load__.zeek index 4f7f22c492..ab87986c63 100644 --- a/scripts/base/protocols/ldap/__load__.zeek +++ b/scripts/base/protocols/ldap/__load__.zeek @@ -1,2 +1,4 @@ +@if ( have_spicy_analyzers() ) @load-sigs ./dpd.sig @load ./main.zeek +@endif diff --git a/testing/btest/scripts/base/protocols/ldap/attributes.zeek b/testing/btest/scripts/base/protocols/ldap/attributes.zeek index bc482ebbfa..cc31bce939 100644 --- a/testing/btest/scripts/base/protocols/ldap/attributes.zeek +++ b/testing/btest/scripts/base/protocols/ldap/attributes.zeek @@ -1,5 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +# @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth.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 diff --git a/testing/btest/scripts/base/protocols/ldap/availability.zeek b/testing/btest/scripts/base/protocols/ldap/availability.zeek index 44234ac15d..a24ff3f799 100644 --- a/testing/btest/scripts/base/protocols/ldap/availability.zeek +++ b/testing/btest/scripts/base/protocols/ldap/availability.zeek @@ -1,5 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +# @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -NN | grep -q ANALYZER_LDAP_TCP # # @TEST-DOC: Check that LDAP (TCP) is analyzer is available. diff --git a/testing/btest/scripts/base/protocols/ldap/basic.zeek b/testing/btest/scripts/base/protocols/ldap/basic.zeek index b5753b1fea..62bd3d817d 100644 --- a/testing/btest/scripts/base/protocols/ldap/basic.zeek +++ b/testing/btest/scripts/base/protocols/ldap/basic.zeek @@ -1,5 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +# @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth.pcap %INPUT >output 2>&1 # @TEST-EXEC: btest-diff output # @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log diff --git a/testing/btest/scripts/base/protocols/ldap/diff_port.zeek b/testing/btest/scripts/base/protocols/ldap/diff_port.zeek index 565903355d..2f76163f1b 100644 --- a/testing/btest/scripts/base/protocols/ldap/diff_port.zeek +++ b/testing/btest/scripts/base/protocols/ldap/diff_port.zeek @@ -1,5 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +# @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth-diff-port.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 diff --git a/testing/btest/scripts/base/protocols/ldap/functions.spicy b/testing/btest/scripts/base/protocols/ldap/functions.spicy index 4bcc721673..468e529f57 100644 --- a/testing/btest/scripts/base/protocols/ldap/functions.spicy +++ b/testing/btest/scripts/base/protocols/ldap/functions.spicy @@ -1,5 +1,5 @@ # This test can only run if we have the LDAP grammar available. -# @TEST-REQUIRES: [ -n ${DIST} ] +# @TEST-REQUIRES: have-spicy && [ -n ${DIST} ] # # @TEST-EXEC: spicyc -j -d -L ${DIST}/src/analyzer/protocol/ldap %INPUT # diff --git a/testing/btest/scripts/base/protocols/ldap/log_policy.zeek b/testing/btest/scripts/base/protocols/ldap/log_policy.zeek index 0317fc6a7d..6a9b0d6f14 100644 --- a/testing/btest/scripts/base/protocols/ldap/log_policy.zeek +++ b/testing/btest/scripts/base/protocols/ldap/log_policy.zeek @@ -1,5 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +# @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -C -r ${TRACES}/ldap/simpleauth.pcap %INPUT >output 2>&1 # @TEST-EXEC: btest-diff output # @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek index f84f979237..9e217bccb4 100644 --- a/testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek +++ b/testing/btest/scripts/base/protocols/ldap/sasl-encrypted.zeek @@ -1,5 +1,6 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +# @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -C -r ${TRACES}/ldap/krb5-sign-seal-01.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 From c0daacfbd1b8d5a243df093ca3706e8fc2cb971c Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Wed, 20 Sep 2023 09:09:06 +0200 Subject: [PATCH 12/20] Require have-spicy for tests which log spicy-ldap information --- testing/btest/coverage/find-bro-logs.test | 1 + testing/btest/scripts/base/files/x509/files.test | 1 + 2 files changed, 2 insertions(+) diff --git a/testing/btest/coverage/find-bro-logs.test b/testing/btest/coverage/find-bro-logs.test index 01e822deef..1dd68d1492 100644 --- a/testing/btest/coverage/find-bro-logs.test +++ b/testing/btest/coverage/find-bro-logs.test @@ -4,6 +4,7 @@ # # If this test fails, then the "Log Files" documentation page should be updated. +# @TEST-REQUIRES: ${SCRIPTS}/have-spicy # @TEST-REQUIRES: which python3 # @TEST-EXEC: bash %INPUT # @TEST-EXEC: btest-diff out diff --git a/testing/btest/scripts/base/files/x509/files.test b/testing/btest/scripts/base/files/x509/files.test index 494bdf5c2a..b51bf39d2a 100644 --- a/testing/btest/scripts/base/files/x509/files.test +++ b/testing/btest/scripts/base/files/x509/files.test @@ -1,5 +1,6 @@ # Test that checks that files.log is generated if the respective option is set. +# @TEST-REQUIRES: ${SCRIPTS}/have-spicy # @TEST-EXEC: zeek -b -r $TRACES/tls/google-duplicate.trace %INPUT # @TEST-EXEC: btest-diff files.log From 9b02b93889363ecd48afcf5ce3086ffcc10745e4 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Thu, 21 Sep 2023 13:13:32 +0200 Subject: [PATCH 13/20] Make ports for LDAP analyzers fully configurable This moves the ports the LDAP analyzers should be triggered on from the EVT file to the Zeek module. This gives users full control over which ports the analyzers are registered for while previously they could only register them for additional ports (there is no Zeek script equivalent of `Manager::UnregisterAnalyzerForPort`). The analyzers could still be triggered via DPD, but this is intentional. To fully disable analyzers users can use e.g., ```zeek event zeek_init() { Analyzer::disable_analyzer(Analyzer::ANALYZER_LDAP_TCP); } ``` --- scripts/base/protocols/ldap/main.zeek | 11 +++++++++++ src/analyzer/protocol/ldap/ldap.evt | 6 ++---- .../btest/Baseline/core.print-bpf-filters/output2 | 12 +++++++----- .../Baseline/spicy.port-range-one-port/out.filtered | 3 --- testing/btest/core/print-bpf-filters.zeek | 5 +++-- testing/external/commit-hash.zeek-testing-private | 2 +- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index 1cdff64292..7c09049d1b 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -6,6 +6,14 @@ export { redef enum Log::ID += { LDAP_LOG, LDAP_SEARCH_LOG }; + ## TCP ports which should be considered for analysis. + const ports_tcp = { 389/tcp, 3268/tcp } &redef; + + ## UDP ports which should be considered for analysis. + const ports_udp = { 389/udp } &redef; + + redef likely_server_ports += { LDAP::ports_tcp, LDAP::ports_udp }; + ## Whether clear text passwords are captured or not. option default_capture_password = F; @@ -260,6 +268,9 @@ redef record connection += { ############################################################################# event zeek_init() &priority=5 { + Analyzer::register_for_ports(Analyzer::ANALYZER_LDAP_TCP, LDAP::ports_tcp); + Analyzer::register_for_ports(Analyzer::ANALYZER_LDAP_UDP, LDAP::ports_udp); + Log::create_stream(LDAP::LDAP_LOG, [$columns=Message, $ev=log_ldap, $path="ldap", $policy=log_policy]); Log::create_stream(LDAP::LDAP_SEARCH_LOG, [$columns=Search, $ev=log_ldap_search, $path="ldap_search", $policy=log_policy_search]); } diff --git a/src/analyzer/protocol/ldap/ldap.evt b/src/analyzer/protocol/ldap/ldap.evt index 6b217348b1..c0fc25cdb0 100644 --- a/src/analyzer/protocol/ldap/ldap.evt +++ b/src/analyzer/protocol/ldap/ldap.evt @@ -1,12 +1,10 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. protocol analyzer LDAP_TCP over TCP: - parse with LDAP::Messages, - ports { 389/tcp, 3268/tcp}; + parse with LDAP::Messages; protocol analyzer LDAP_UDP over UDP: - parse with LDAP::Messages, - ports { 389/udp }; + parse with LDAP::Messages; import LDAP; diff --git a/testing/btest/Baseline/core.print-bpf-filters/output2 b/testing/btest/Baseline/core.print-bpf-filters/output2 index 939abe6f39..dcd56a5e77 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output2 +++ b/testing/btest/Baseline/core.print-bpf-filters/output2 @@ -18,9 +18,11 @@ 1 25 1 2811 1 3128 +1 3268 1 3306 2 3389 1 3544 +2 389 1 4011 2 443 1 445 @@ -60,8 +62,8 @@ 1 992 1 993 1 995 -67 and -66 or -67 port -44 tcp -23 udp +70 and +69 or +70 port +46 tcp +24 udp diff --git a/testing/btest/Baseline/spicy.port-range-one-port/out.filtered b/testing/btest/Baseline/spicy.port-range-one-port/out.filtered index 708e225624..293b1047f3 100644 --- a/testing/btest/Baseline/spicy.port-range-one-port/out.filtered +++ b/testing/btest/Baseline/spicy.port-range-one-port/out.filtered @@ -1,5 +1,2 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[zeek] Scheduling analyzer for port 389/tcp -[zeek] Scheduling analyzer for port 3268/tcp -[zeek] Scheduling analyzer for port 389/udp [zeek] Scheduling analyzer for port 31336/udp diff --git a/testing/btest/core/print-bpf-filters.zeek b/testing/btest/core/print-bpf-filters.zeek index fd86ce4f04..e755c4347f 100644 --- a/testing/btest/core/print-bpf-filters.zeek +++ b/testing/btest/core/print-bpf-filters.zeek @@ -1,3 +1,5 @@ +# @TEST-REQUIRES: have-spicy +# # @TEST-EXEC: zeek -r $TRACES/empty.trace >output # @TEST-EXEC: cat packet_filter.log >>output # @TEST-EXEC: zeek -r $TRACES/empty.trace -f "port 42" >>output @@ -6,10 +8,9 @@ # @TEST-EXEC: cat packet_filter.log >>output # @TEST-EXEC: btest-diff output # @TEST-EXEC: btest-diff conn.log -# +# # The order in the output of enable_auto_protocol_capture_filters isn't # stable, for reasons not clear. We canonify it first. # @TEST-EXEC: zeek -r $TRACES/empty.trace PacketFilter::enable_auto_protocol_capture_filters=T # @TEST-EXEC: cat packet_filter.log | zeek-cut filter | sed 's#[()]##g' | tr ' ' '\n' | sort | uniq -c | awk '{print $1, $2}' >output2 # @TEST-EXEC: btest-diff output2 - diff --git a/testing/external/commit-hash.zeek-testing-private b/testing/external/commit-hash.zeek-testing-private index a9a63fa39f..c6aa6e2c80 100644 --- a/testing/external/commit-hash.zeek-testing-private +++ b/testing/external/commit-hash.zeek-testing-private @@ -1 +1 @@ -718bc67ea10606ec29acfdae05c463518319e8f2 +5ac67a3895edf0ea6a757ae3ea8626621f57db41 From c43bc52e18080d7630cdac7deb88d0cd54774eb7 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 12:32:45 +0200 Subject: [PATCH 14/20] Name `LDAP::Message` and `LDAP::Search` `*Info` --- scripts/base/protocols/ldap/main.zeek | 18 ++++++++---------- .../coverage.record-fields/out.default | 8 ++++---- .../base/protocols/ldap/log_policy.zeek | 4 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index 7c09049d1b..c0067b702a 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -29,8 +29,7 @@ export { ############################################################################# # This is the format of ldap.log (ldap operations minus search-related) # Each line represents a unique connection+message_id (requests/responses) - type Message: record { - + type MessageInfo: record { # Timestamp for when the event happened. ts: time &log; @@ -68,8 +67,7 @@ export { ############################################################################# # This is the format of ldap_search.log (search-related messages only) # Each line represents a unique connection+message_id (requests/responses) - type Search: record { - + type SearchInfo: record { # Timestamp for when the event happened. ts: time &log; @@ -110,8 +108,8 @@ export { # Event that can be handled to access the ldap record as it is sent on # to the logging framework. - global log_ldap: event(rec: LDAP::Message); - global log_ldap_search: event(rec: LDAP::Search); + global log_ldap: event(rec: LDAP::MessageInfo); + global log_ldap_search: event(rec: LDAP::SearchInfo); # Event called for each LDAP message (either direction) global LDAP::message: event(c: connection, @@ -262,8 +260,8 @@ global OPCODES_SEARCH: set[LDAP::ProtocolOpcode] = { LDAP::ProtocolOpcode_SEARCH ############################################################################# redef record connection += { ldap_proto: string &optional; - ldap_messages: table[int] of Message &optional; - ldap_searches: table[int] of Search &optional; + ldap_messages: table[int] of MessageInfo &optional; + ldap_searches: table[int] of SearchInfo &optional; }; ############################################################################# @@ -271,8 +269,8 @@ event zeek_init() &priority=5 { Analyzer::register_for_ports(Analyzer::ANALYZER_LDAP_TCP, LDAP::ports_tcp); Analyzer::register_for_ports(Analyzer::ANALYZER_LDAP_UDP, LDAP::ports_udp); - Log::create_stream(LDAP::LDAP_LOG, [$columns=Message, $ev=log_ldap, $path="ldap", $policy=log_policy]); - Log::create_stream(LDAP::LDAP_SEARCH_LOG, [$columns=Search, $ev=log_ldap_search, $path="ldap_search", $policy=log_policy_search]); + Log::create_stream(LDAP::LDAP_LOG, [$columns=MessageInfo, $ev=log_ldap, $path="ldap", $policy=log_policy]); + Log::create_stream(LDAP::LDAP_SEARCH_LOG, [$columns=SearchInfo, $ev=log_ldap_search, $path="ldap_search", $policy=log_policy_search]); } ############################################################################# diff --git a/testing/btest/Baseline/coverage.record-fields/out.default b/testing/btest/Baseline/coverage.record-fields/out.default index 68d049e536..57eb1712bc 100644 --- a/testing/btest/Baseline/coverage.record-fields/out.default +++ b/testing/btest/Baseline/coverage.record-fields/out.default @@ -360,8 +360,8 @@ connection { * ts: time, log=T, optional=F * uid: string, log=T, optional=F } - * ldap_messages: table[int] of record LDAP::Message, log=F, optional=T - LDAP::Message { + * ldap_messages: table[int] of record LDAP::MessageInfo, log=F, optional=T + LDAP::MessageInfo { * argument: vector of string, log=T, optional=T * diagnostic_message: vector of string, log=T, optional=T * id: record conn_id, log=T, optional=F @@ -376,8 +376,8 @@ connection { * version: int, log=T, optional=T } * ldap_proto: string, log=F, optional=T - * ldap_searches: table[int] of record LDAP::Search, log=F, optional=T - LDAP::Search { + * ldap_searches: table[int] of record LDAP::SearchInfo, log=F, optional=T + LDAP::SearchInfo { * attributes: vector of string, log=T, optional=T * base_object: vector of string, log=T, optional=T * deref: set[string], log=T, optional=T diff --git a/testing/btest/scripts/base/protocols/ldap/log_policy.zeek b/testing/btest/scripts/base/protocols/ldap/log_policy.zeek index 6a9b0d6f14..b12adc8ebd 100644 --- a/testing/btest/scripts/base/protocols/ldap/log_policy.zeek +++ b/testing/btest/scripts/base/protocols/ldap/log_policy.zeek @@ -10,12 +10,12 @@ # # @TEST-DOC: Test LDAP analyzer with small trace using logging policies. -hook LDAP::log_policy(rec: LDAP::Message, id: Log::ID, filter: Log::Filter) +hook LDAP::log_policy(rec: LDAP::MessageInfo, id: Log::ID, filter: Log::Filter) { break; } -hook LDAP::log_policy_search(rec: LDAP::Search, id: Log::ID, +hook LDAP::log_policy_search(rec: LDAP::SearchInfo, id: Log::ID, filter: Log::Filter) { break; From 0c126f3c6bfb93a5f36ecdcc14524341526d9f77 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 12:36:01 +0200 Subject: [PATCH 15/20] Move LDAP script constants to their own file --- scripts/base/protocols/ldap/consts.zeek | 123 ++++++++++++++++++ scripts/base/protocols/ldap/main.zeek | 122 +---------------- .../canonified_loaded_scripts.log | 1 + 3 files changed, 128 insertions(+), 118 deletions(-) create mode 100644 scripts/base/protocols/ldap/consts.zeek diff --git a/scripts/base/protocols/ldap/consts.zeek b/scripts/base/protocols/ldap/consts.zeek new file mode 100644 index 0000000000..bbd378c7e8 --- /dev/null +++ b/scripts/base/protocols/ldap/consts.zeek @@ -0,0 +1,123 @@ +module LDAP; + +export { + const PROTOCOL_OPCODES = { [ LDAP::ProtocolOpcode_BIND_REQUEST ] = "bind", [ + LDAP::ProtocolOpcode_BIND_RESPONSE ] = "bind", [ + LDAP::ProtocolOpcode_UNBIND_REQUEST ] = "unbind", [ + LDAP::ProtocolOpcode_SEARCH_REQUEST ] = "search", [ + LDAP::ProtocolOpcode_SEARCH_RESULT_ENTRY ] = "search", [ + LDAP::ProtocolOpcode_SEARCH_RESULT_DONE ] = "search", [ + LDAP::ProtocolOpcode_MODIFY_REQUEST ] = "modify", [ + LDAP::ProtocolOpcode_MODIFY_RESPONSE ] = "modify", [ + LDAP::ProtocolOpcode_ADD_REQUEST ] = "add", [ + LDAP::ProtocolOpcode_ADD_RESPONSE ] = "add", [ + LDAP::ProtocolOpcode_DEL_REQUEST ] = "delete", [ + LDAP::ProtocolOpcode_DEL_RESPONSE ] = "delete", [ + LDAP::ProtocolOpcode_MOD_DN_REQUEST ] = "modify", [ + LDAP::ProtocolOpcode_MOD_DN_RESPONSE ] = "modify", [ + LDAP::ProtocolOpcode_COMPARE_REQUEST ] = "compare", [ + LDAP::ProtocolOpcode_COMPARE_RESPONSE ] = "compare", [ + LDAP::ProtocolOpcode_ABANDON_REQUEST ] = "abandon", [ + LDAP::ProtocolOpcode_SEARCH_RESULT_REFERENCE ] = "search", [ + LDAP::ProtocolOpcode_EXTENDED_REQUEST ] = "extended", [ + LDAP::ProtocolOpcode_EXTENDED_RESPONSE ] = "extended", [ + LDAP::ProtocolOpcode_INTERMEDIATE_RESPONSE ] = "intermediate" } + &default="unknown"; + + const BIND_SIMPLE = "bind simple"; + const BIND_SASL = "bind SASL"; + + const RESULT_CODES = { [ LDAP::ResultCode_SUCCESS ] = "success", [ + LDAP::ResultCode_OPERATIONS_ERROR ] = "operations error", [ + LDAP::ResultCode_PROTOCOL_ERROR ] = "protocol error", [ + LDAP::ResultCode_TIME_LIMIT_EXCEEDED ] = "time limit exceeded", [ + LDAP::ResultCode_SIZE_LIMIT_EXCEEDED ] = "size limit exceeded", [ + LDAP::ResultCode_COMPARE_FALSE ] = "compare false", [ + LDAP::ResultCode_COMPARE_TRUE ] = "compare true", [ + LDAP::ResultCode_AUTH_METHOD_NOT_SUPPORTED ] = + "auth method not supported", [ + LDAP::ResultCode_STRONGER_AUTH_REQUIRED ] = + "stronger auth required", [ LDAP::ResultCode_PARTIAL_RESULTS ] = + "partial results", [ LDAP::ResultCode_REFERRAL ] = "referral", [ + LDAP::ResultCode_ADMIN_LIMIT_EXCEEDED ] = "admin limit exceeded", [ + LDAP::ResultCode_UNAVAILABLE_CRITICAL_EXTENSION ] = + "unavailable critical extension", [ + LDAP::ResultCode_CONFIDENTIALITY_REQUIRED ] = + "confidentiality required", [ LDAP::ResultCode_SASL_BIND_IN_PROGRESS ] = + "SASL bind in progress", [ LDAP::ResultCode_NO_SUCH_ATTRIBUTE ] = + "no such attribute", [ LDAP::ResultCode_UNDEFINED_ATTRIBUTE_TYPE ] = + "undefined attribute type", [ + LDAP::ResultCode_INAPPROPRIATE_MATCHING ] = + "inappropriate matching", [ LDAP::ResultCode_CONSTRAINT_VIOLATION ] = + "constraint violation", [ LDAP::ResultCode_ATTRIBUTE_OR_VALUE_EXISTS ] = + "attribute or value exists", [ + LDAP::ResultCode_INVALID_ATTRIBUTE_SYNTAX ] = + "invalid attribute syntax", [ LDAP::ResultCode_NO_SUCH_OBJECT ] = + "no such object", [ LDAP::ResultCode_ALIAS_PROBLEM ] = + "alias problem", [ LDAP::ResultCode_INVALID_DNSYNTAX ] = + "invalid DN syntax", [ LDAP::ResultCode_ALIAS_DEREFERENCING_PROBLEM ] = + "alias dereferencing problem", [ + LDAP::ResultCode_INAPPROPRIATE_AUTHENTICATION ] = + "inappropriate authentication", [ + LDAP::ResultCode_INVALID_CREDENTIALS ] = "invalid credentials", [ + LDAP::ResultCode_INSUFFICIENT_ACCESS_RIGHTS ] = + "insufficient access rights", [ LDAP::ResultCode_BUSY ] = "busy", [ + LDAP::ResultCode_UNAVAILABLE ] = "unavailable", [ + LDAP::ResultCode_UNWILLING_TO_PERFORM ] = "unwilling to perform", [ + LDAP::ResultCode_LOOP_DETECT ] = "loop detect", [ + LDAP::ResultCode_SORT_CONTROL_MISSING ] = "sort control missing", [ + LDAP::ResultCode_OFFSET_RANGE_ERROR ] = "offset range error", [ + LDAP::ResultCode_NAMING_VIOLATION ] = "naming violation", [ + LDAP::ResultCode_OBJECT_CLASS_VIOLATION ] = + "object class violation", [ LDAP::ResultCode_NOT_ALLOWED_ON_NON_LEAF ] = + "not allowed on non-leaf", [ LDAP::ResultCode_NOT_ALLOWED_ON_RDN ] = + "not allowed on RDN", [ LDAP::ResultCode_ENTRY_ALREADY_EXISTS ] = + "entry already exists", [ + LDAP::ResultCode_OBJECT_CLASS_MODS_PROHIBITED ] = + "object class mods prohibited", [ LDAP::ResultCode_RESULTS_TOO_LARGE ] = + "results too large", [ LDAP::ResultCode_AFFECTS_MULTIPLE_DSAS ] = + "affects multiple DSAs", [ LDAP::ResultCode_CONTROL_ERROR ] = + "control error", [ LDAP::ResultCode_OTHER ] = "other", [ + LDAP::ResultCode_SERVER_DOWN ] = "server down", [ + LDAP::ResultCode_LOCAL_ERROR ] = "local error", [ + LDAP::ResultCode_ENCODING_ERROR ] = "encoding error", [ + LDAP::ResultCode_DECODING_ERROR ] = "decoding error", [ + LDAP::ResultCode_TIMEOUT ] = "timeout", [ + LDAP::ResultCode_AUTH_UNKNOWN ] = "auth unknown", [ + LDAP::ResultCode_FILTER_ERROR ] = "filter error", [ + LDAP::ResultCode_USER_CANCELED ] = "user canceled", [ + LDAP::ResultCode_PARAM_ERROR ] = "param error", [ + LDAP::ResultCode_NO_MEMORY ] = "no memory", [ + LDAP::ResultCode_CONNECT_ERROR ] = "connect error", [ + LDAP::ResultCode_NOT_SUPPORTED ] = "not supported", [ + LDAP::ResultCode_CONTROL_NOT_FOUND ] = "control not found", [ + LDAP::ResultCode_NO_RESULTS_RETURNED ] = "no results returned", [ + LDAP::ResultCode_MORE_RESULTS_TO_RETURN ] = + "more results to return", [ LDAP::ResultCode_CLIENT_LOOP ] = + "client loop", [ LDAP::ResultCode_REFERRAL_LIMIT_EXCEEDED ] = + "referral limit exceeded", [ LDAP::ResultCode_INVALID_RESPONSE ] = + "invalid response", [ LDAP::ResultCode_AMBIGUOUS_RESPONSE ] = + "ambiguous response", [ LDAP::ResultCode_TLS_NOT_SUPPORTED ] = + "TLS not supported", [ LDAP::ResultCode_INTERMEDIATE_RESPONSE ] = + "intermediate response", [ LDAP::ResultCode_UNKNOWN_TYPE ] = + "unknown type", [ LDAP::ResultCode_LCUP_INVALID_DATA ] = + "LCUP invalid data", [ LDAP::ResultCode_LCUP_UNSUPPORTED_SCHEME ] = + "LCUP unsupported scheme", [ LDAP::ResultCode_LCUP_RELOAD_REQUIRED ] = + "LCUP reload required", [ LDAP::ResultCode_CANCELED ] = + "canceled", [ LDAP::ResultCode_NO_SUCH_OPERATION ] = + "no such operation", [ LDAP::ResultCode_TOO_LATE ] = "too late", [ + LDAP::ResultCode_CANNOT_CANCEL ] = "cannot cancel", [ + LDAP::ResultCode_ASSERTION_FAILED ] = "assertion failed", [ + LDAP::ResultCode_AUTHORIZATION_DENIED ] = "authorization denied" } + &default="unknown"; + + const SEARCH_SCOPES = { [ LDAP::SearchScope_SEARCH_BASE ] = "base", [ + LDAP::SearchScope_SEARCH_SINGLE ] = "single", [ + LDAP::SearchScope_SEARCH_TREE ] = "tree", } &default="unknown"; + + const SEARCH_DEREF_ALIASES = { [ LDAP::SearchDerefAlias_DEREF_NEVER ] = + "never", [ LDAP::SearchDerefAlias_DEREF_IN_SEARCHING ] = + "searching", [ LDAP::SearchDerefAlias_DEREF_FINDING_BASE ] = + "finding", [ LDAP::SearchDerefAlias_DEREF_ALWAYS ] = "always", } + &default="unknown"; +} diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index c0067b702a..7992e05f6f 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -1,5 +1,9 @@ # Copyright (c) 2021 by the Zeek Project. See LICENSE for details. +@load base/protocols/conn/removal-hooks + +@load ./consts + module LDAP; export { @@ -120,124 +124,6 @@ export { diagnostic_message: string, object: string, argument: string); - - const PROTOCOL_OPCODES = { - [LDAP::ProtocolOpcode_BIND_REQUEST] = "bind", - [LDAP::ProtocolOpcode_BIND_RESPONSE] = "bind", - [LDAP::ProtocolOpcode_UNBIND_REQUEST] = "unbind", - [LDAP::ProtocolOpcode_SEARCH_REQUEST] = "search", - [LDAP::ProtocolOpcode_SEARCH_RESULT_ENTRY] = "search", - [LDAP::ProtocolOpcode_SEARCH_RESULT_DONE] = "search", - [LDAP::ProtocolOpcode_MODIFY_REQUEST] = "modify", - [LDAP::ProtocolOpcode_MODIFY_RESPONSE] = "modify", - [LDAP::ProtocolOpcode_ADD_REQUEST] = "add", - [LDAP::ProtocolOpcode_ADD_RESPONSE] = "add", - [LDAP::ProtocolOpcode_DEL_REQUEST] = "delete", - [LDAP::ProtocolOpcode_DEL_RESPONSE] = "delete", - [LDAP::ProtocolOpcode_MOD_DN_REQUEST] = "modify", - [LDAP::ProtocolOpcode_MOD_DN_RESPONSE] = "modify", - [LDAP::ProtocolOpcode_COMPARE_REQUEST] = "compare", - [LDAP::ProtocolOpcode_COMPARE_RESPONSE] = "compare", - [LDAP::ProtocolOpcode_ABANDON_REQUEST] = "abandon", - [LDAP::ProtocolOpcode_SEARCH_RESULT_REFERENCE] = "search", - [LDAP::ProtocolOpcode_EXTENDED_REQUEST] = "extended", - [LDAP::ProtocolOpcode_EXTENDED_RESPONSE] = "extended", - [LDAP::ProtocolOpcode_INTERMEDIATE_RESPONSE] = "intermediate" - } &default = "unknown"; - - const BIND_SIMPLE = "bind simple"; - const BIND_SASL = "bind SASL"; - - const RESULT_CODES = { - [LDAP::ResultCode_SUCCESS] = "success", - [LDAP::ResultCode_OPERATIONS_ERROR] = "operations error", - [LDAP::ResultCode_PROTOCOL_ERROR] = "protocol error", - [LDAP::ResultCode_TIME_LIMIT_EXCEEDED] = "time limit exceeded", - [LDAP::ResultCode_SIZE_LIMIT_EXCEEDED] = "size limit exceeded", - [LDAP::ResultCode_COMPARE_FALSE] = "compare false", - [LDAP::ResultCode_COMPARE_TRUE] = "compare true", - [LDAP::ResultCode_AUTH_METHOD_NOT_SUPPORTED] = "auth method not supported", - [LDAP::ResultCode_STRONGER_AUTH_REQUIRED] = "stronger auth required", - [LDAP::ResultCode_PARTIAL_RESULTS] = "partial results", - [LDAP::ResultCode_REFERRAL] = "referral", - [LDAP::ResultCode_ADMIN_LIMIT_EXCEEDED] = "admin limit exceeded", - [LDAP::ResultCode_UNAVAILABLE_CRITICAL_EXTENSION] = "unavailable critical extension", - [LDAP::ResultCode_CONFIDENTIALITY_REQUIRED] = "confidentiality required", - [LDAP::ResultCode_SASL_BIND_IN_PROGRESS] = "SASL bind in progress", - [LDAP::ResultCode_NO_SUCH_ATTRIBUTE] = "no such attribute", - [LDAP::ResultCode_UNDEFINED_ATTRIBUTE_TYPE] = "undefined attribute type", - [LDAP::ResultCode_INAPPROPRIATE_MATCHING] = "inappropriate matching", - [LDAP::ResultCode_CONSTRAINT_VIOLATION] = "constraint violation", - [LDAP::ResultCode_ATTRIBUTE_OR_VALUE_EXISTS] = "attribute or value exists", - [LDAP::ResultCode_INVALID_ATTRIBUTE_SYNTAX] = "invalid attribute syntax", - [LDAP::ResultCode_NO_SUCH_OBJECT] = "no such object", - [LDAP::ResultCode_ALIAS_PROBLEM] = "alias problem", - [LDAP::ResultCode_INVALID_DNSYNTAX] = "invalid DN syntax", - [LDAP::ResultCode_ALIAS_DEREFERENCING_PROBLEM] = "alias dereferencing problem", - [LDAP::ResultCode_INAPPROPRIATE_AUTHENTICATION] = "inappropriate authentication", - [LDAP::ResultCode_INVALID_CREDENTIALS] = "invalid credentials", - [LDAP::ResultCode_INSUFFICIENT_ACCESS_RIGHTS] = "insufficient access rights", - [LDAP::ResultCode_BUSY] = "busy", - [LDAP::ResultCode_UNAVAILABLE] = "unavailable", - [LDAP::ResultCode_UNWILLING_TO_PERFORM] = "unwilling to perform", - [LDAP::ResultCode_LOOP_DETECT] = "loop detect", - [LDAP::ResultCode_SORT_CONTROL_MISSING] = "sort control missing", - [LDAP::ResultCode_OFFSET_RANGE_ERROR] = "offset range error", - [LDAP::ResultCode_NAMING_VIOLATION] = "naming violation", - [LDAP::ResultCode_OBJECT_CLASS_VIOLATION] = "object class violation", - [LDAP::ResultCode_NOT_ALLOWED_ON_NON_LEAF] = "not allowed on non-leaf", - [LDAP::ResultCode_NOT_ALLOWED_ON_RDN] = "not allowed on RDN", - [LDAP::ResultCode_ENTRY_ALREADY_EXISTS] = "entry already exists", - [LDAP::ResultCode_OBJECT_CLASS_MODS_PROHIBITED] = "object class mods prohibited", - [LDAP::ResultCode_RESULTS_TOO_LARGE] = "results too large", - [LDAP::ResultCode_AFFECTS_MULTIPLE_DSAS] = "affects multiple DSAs", - [LDAP::ResultCode_CONTROL_ERROR] = "control error", - [LDAP::ResultCode_OTHER] = "other", - [LDAP::ResultCode_SERVER_DOWN] = "server down", - [LDAP::ResultCode_LOCAL_ERROR] = "local error", - [LDAP::ResultCode_ENCODING_ERROR] = "encoding error", - [LDAP::ResultCode_DECODING_ERROR] = "decoding error", - [LDAP::ResultCode_TIMEOUT] = "timeout", - [LDAP::ResultCode_AUTH_UNKNOWN] = "auth unknown", - [LDAP::ResultCode_FILTER_ERROR] = "filter error", - [LDAP::ResultCode_USER_CANCELED] = "user canceled", - [LDAP::ResultCode_PARAM_ERROR] = "param error", - [LDAP::ResultCode_NO_MEMORY] = "no memory", - [LDAP::ResultCode_CONNECT_ERROR] = "connect error", - [LDAP::ResultCode_NOT_SUPPORTED] = "not supported", - [LDAP::ResultCode_CONTROL_NOT_FOUND] = "control not found", - [LDAP::ResultCode_NO_RESULTS_RETURNED] = "no results returned", - [LDAP::ResultCode_MORE_RESULTS_TO_RETURN] = "more results to return", - [LDAP::ResultCode_CLIENT_LOOP] = "client loop", - [LDAP::ResultCode_REFERRAL_LIMIT_EXCEEDED] = "referral limit exceeded", - [LDAP::ResultCode_INVALID_RESPONSE] = "invalid response", - [LDAP::ResultCode_AMBIGUOUS_RESPONSE] = "ambiguous response", - [LDAP::ResultCode_TLS_NOT_SUPPORTED] = "TLS not supported", - [LDAP::ResultCode_INTERMEDIATE_RESPONSE] = "intermediate response", - [LDAP::ResultCode_UNKNOWN_TYPE] = "unknown type", - [LDAP::ResultCode_LCUP_INVALID_DATA] = "LCUP invalid data", - [LDAP::ResultCode_LCUP_UNSUPPORTED_SCHEME] = "LCUP unsupported scheme", - [LDAP::ResultCode_LCUP_RELOAD_REQUIRED] = "LCUP reload required", - [LDAP::ResultCode_CANCELED] = "canceled", - [LDAP::ResultCode_NO_SUCH_OPERATION] = "no such operation", - [LDAP::ResultCode_TOO_LATE] = "too late", - [LDAP::ResultCode_CANNOT_CANCEL] = "cannot cancel", - [LDAP::ResultCode_ASSERTION_FAILED] = "assertion failed", - [LDAP::ResultCode_AUTHORIZATION_DENIED] = "authorization denied" - } &default = "unknown"; - - const SEARCH_SCOPES = { - [LDAP::SearchScope_SEARCH_BASE] = "base", - [LDAP::SearchScope_SEARCH_SINGLE] = "single", - [LDAP::SearchScope_SEARCH_TREE] = "tree", - } &default = "unknown"; - - const SEARCH_DEREF_ALIASES = { - [LDAP::SearchDerefAlias_DEREF_NEVER] = "never", - [LDAP::SearchDerefAlias_DEREF_IN_SEARCHING] = "searching", - [LDAP::SearchDerefAlias_DEREF_FINDING_BASE] = "finding", - [LDAP::SearchDerefAlias_DEREF_ALWAYS] = "always", - } &default = "unknown"; } ############################################################################# 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 2b87b5796f..feb640ec3a 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 @@ -408,6 +408,7 @@ scripts/base/init-default.zeek scripts/base/protocols/krb/files.zeek scripts/base/protocols/ldap/__load__.zeek scripts/base/protocols/ldap/main.zeek + scripts/base/protocols/ldap/consts.zeek scripts/base/protocols/modbus/__load__.zeek scripts/base/protocols/modbus/consts.zeek scripts/base/protocols/modbus/main.zeek From 3a60a606190062689f627d46ac3b7a224c53c499 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 12:53:29 +0200 Subject: [PATCH 16/20] Pluralize container names in LDAP types --- scripts/base/protocols/ldap/main.zeek | 102 +++++++++--------- .../coverage.record-fields/out.default | 20 ++-- .../ldap.log | 2 +- .../ldap_search.log | 2 +- .../ldap.log | 2 +- .../ldap_search.log | 2 +- .../ldap.log | 2 +- .../ldap_search.log | 2 +- .../ldap.log | 2 +- .../ldap_search.log | 2 +- .../ldap_search.log | 2 +- .../ldap/search_filter_extended.zeek | 2 +- 12 files changed, 71 insertions(+), 71 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index 7992e05f6f..e5ecaf547a 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -53,19 +53,19 @@ export { version: int &log &optional; # normalized operations (e.g., bind_request and bind_response to "bind") - opcode: set[string] &log &optional; + opcodes: set[string] &log &optional; # Result code(s) - result: set[string] &log &optional; + results: set[string] &log &optional; # result diagnostic message(s) - diagnostic_message: vector of string &log &optional; + diagnostic_messages: vector of string &log &optional; # object(s) - object: vector of string &log &optional; + objects: vector of string &log &optional; # argument(s) - argument: vector of string &log &optional; + arguments: vector of string &log &optional; }; ############################################################################# @@ -88,20 +88,20 @@ export { message_id: int &log &optional; # sets of search scope and deref alias - scope: set[string] &log &optional; - deref: set[string] &log &optional; + scopes: set[string] &log &optional; + derefs: set[string] &log &optional; # base search objects - base_object: vector of string &log &optional; + base_objects: vector of string &log &optional; # number of results returned result_count: count &log &optional; # Result code (s) - result: set[string] &log &optional; + results: set[string] &log &optional; # result diagnostic message(s) - diagnostic_message: vector of string &log &optional; + diagnostic_messages: vector of string &log &optional; # a string representation of the search filter used in the query filter: string &log &optional; @@ -217,15 +217,15 @@ event LDAP::message(c: connection, set_session(c, message_id, opcode); if ( result != LDAP::ResultCode_Undef ) { - if ( ! c$ldap_searches[message_id]?$result ) - c$ldap_searches[message_id]$result = set(); - add c$ldap_searches[message_id]$result[RESULT_CODES[result]]; + if ( ! c$ldap_searches[message_id]?$results ) + c$ldap_searches[message_id]$results = set(); + add c$ldap_searches[message_id]$results[RESULT_CODES[result]]; } if ( diagnostic_message != "" ) { - if ( ! c$ldap_searches[message_id]?$diagnostic_message ) - c$ldap_searches[message_id]$diagnostic_message = vector(); - c$ldap_searches[message_id]$diagnostic_message += diagnostic_message; + if ( ! c$ldap_searches[message_id]?$diagnostic_messages ) + c$ldap_searches[message_id]$diagnostic_messages = vector(); + c$ldap_searches[message_id]$diagnostic_messages += diagnostic_message; } if (( ! c$ldap_searches[message_id]?$proto ) && c?$ldap_proto) @@ -237,43 +237,43 @@ event LDAP::message(c: connection, } else if (opcode !in OPCODES_SEARCH) { set_session(c, message_id, opcode); - if ( ! c$ldap_messages[message_id]?$opcode ) - c$ldap_messages[message_id]$opcode = set(); - add c$ldap_messages[message_id]$opcode[PROTOCOL_OPCODES[opcode]]; + if ( ! c$ldap_messages[message_id]?$opcodes ) + c$ldap_messages[message_id]$opcodes = set(); + add c$ldap_messages[message_id]$opcodes[PROTOCOL_OPCODES[opcode]]; if ( result != LDAP::ResultCode_Undef ) { - if ( ! c$ldap_messages[message_id]?$result ) - c$ldap_messages[message_id]$result = set(); - add c$ldap_messages[message_id]$result[RESULT_CODES[result]]; + if ( ! c$ldap_messages[message_id]?$results ) + c$ldap_messages[message_id]$results = set(); + add c$ldap_messages[message_id]$results[RESULT_CODES[result]]; } if ( diagnostic_message != "" ) { - if ( ! c$ldap_messages[message_id]?$diagnostic_message ) - c$ldap_messages[message_id]$diagnostic_message = vector(); - c$ldap_messages[message_id]$diagnostic_message += diagnostic_message; + if ( ! c$ldap_messages[message_id]?$diagnostic_messages ) + c$ldap_messages[message_id]$diagnostic_messages = vector(); + c$ldap_messages[message_id]$diagnostic_messages += diagnostic_message; } if ( object != "" ) { - if ( ! c$ldap_messages[message_id]?$object ) - c$ldap_messages[message_id]$object = vector(); - c$ldap_messages[message_id]$object += object; + if ( ! c$ldap_messages[message_id]?$objects ) + c$ldap_messages[message_id]$objects = vector(); + c$ldap_messages[message_id]$objects += object; } if ( argument != "" ) { - if ( ! c$ldap_messages[message_id]?$argument ) - c$ldap_messages[message_id]$argument = vector(); - if ("bind simple" in c$ldap_messages[message_id]$opcode && !default_capture_password) - c$ldap_messages[message_id]$argument += "REDACTED"; + if ( ! c$ldap_messages[message_id]?$arguments ) + c$ldap_messages[message_id]$arguments = vector(); + if ("bind simple" in c$ldap_messages[message_id]$opcodes && !default_capture_password) + c$ldap_messages[message_id]$arguments += "REDACTED"; else - c$ldap_messages[message_id]$argument += argument; + c$ldap_messages[message_id]$arguments += argument; } if (opcode in OPCODES_FINISHED) { - if ((BIND_SIMPLE in c$ldap_messages[message_id]$opcode) || - (BIND_SASL in c$ldap_messages[message_id]$opcode)) { + if ((BIND_SIMPLE in c$ldap_messages[message_id]$opcodes) || + (BIND_SASL in c$ldap_messages[message_id]$opcodes)) { # don't have both "bind" and "bind " in the operations list - delete c$ldap_messages[message_id]$opcode[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; + delete c$ldap_messages[message_id]$opcodes[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; } if (( ! c$ldap_messages[message_id]?$proto ) && c?$ldap_proto) @@ -301,21 +301,21 @@ event LDAP::searchreq(c: connection, set_session(c, message_id, LDAP::ProtocolOpcode_SEARCH_REQUEST); if ( scope != LDAP::SearchScope_Undef ) { - if ( ! c$ldap_searches[message_id]?$scope ) - c$ldap_searches[message_id]$scope = set(); - add c$ldap_searches[message_id]$scope[SEARCH_SCOPES[scope]]; + if ( ! c$ldap_searches[message_id]?$scopes ) + c$ldap_searches[message_id]$scopes = set(); + add c$ldap_searches[message_id]$scopes[SEARCH_SCOPES[scope]]; } if ( deref != LDAP::SearchDerefAlias_Undef ) { - if ( ! c$ldap_searches[message_id]?$deref ) - c$ldap_searches[message_id]$deref = set(); - add c$ldap_searches[message_id]$deref[SEARCH_DEREF_ALIASES[deref]]; + if ( ! c$ldap_searches[message_id]?$derefs ) + c$ldap_searches[message_id]$derefs = set(); + add c$ldap_searches[message_id]$derefs[SEARCH_DEREF_ALIASES[deref]]; } if ( base_object != "" ) { - if ( ! c$ldap_searches[message_id]?$base_object ) - c$ldap_searches[message_id]$base_object = vector(); - c$ldap_searches[message_id]$base_object += base_object; + if ( ! c$ldap_searches[message_id]?$base_objects ) + c$ldap_searches[message_id]$base_objects = vector(); + c$ldap_searches[message_id]$base_objects += base_object; } c$ldap_searches[message_id]$filter = filter; @@ -347,13 +347,13 @@ event LDAP::bindreq(c: connection, if ( ! c$ldap_messages[message_id]?$version ) c$ldap_messages[message_id]$version = version; - if ( ! c$ldap_messages[message_id]?$opcode ) - c$ldap_messages[message_id]$opcode = set(); + if ( ! c$ldap_messages[message_id]?$opcodes ) + c$ldap_messages[message_id]$opcodes = set(); if (authType == LDAP::BindAuthType_BIND_AUTH_SIMPLE) { - add c$ldap_messages[message_id]$opcode[BIND_SIMPLE]; + add c$ldap_messages[message_id]$opcodes[BIND_SIMPLE]; } else if (authType == LDAP::BindAuthType_BIND_AUTH_SASL) { - add c$ldap_messages[message_id]$opcode[BIND_SASL]; + add c$ldap_messages[message_id]$opcodes[BIND_SASL]; } } @@ -367,9 +367,9 @@ event connection_state_remove(c: connection) { for ( [mid], m in c$ldap_messages ) { if (mid > 0) { - if ((BIND_SIMPLE in m$opcode) || (BIND_SASL in m$opcode)) { + if ((BIND_SIMPLE in m$opcodes) || (BIND_SASL in m$opcodes)) { # don't have both "bind" and "bind " in the operations list - delete m$opcode[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; + delete m$opcodes[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; } if (( ! m?$proto ) && c?$ldap_proto) diff --git a/testing/btest/Baseline/coverage.record-fields/out.default b/testing/btest/Baseline/coverage.record-fields/out.default index 57eb1712bc..6c054e555f 100644 --- a/testing/btest/Baseline/coverage.record-fields/out.default +++ b/testing/btest/Baseline/coverage.record-fields/out.default @@ -362,15 +362,15 @@ connection { } * ldap_messages: table[int] of record LDAP::MessageInfo, log=F, optional=T LDAP::MessageInfo { - * argument: vector of string, log=T, optional=T - * diagnostic_message: vector of string, log=T, optional=T + * arguments: vector of string, log=T, optional=T + * diagnostic_messages: vector of string, log=T, optional=T * id: record conn_id, log=T, optional=F conn_id { ... } * message_id: int, log=T, optional=T - * object: vector of string, log=T, optional=T - * opcode: set[string], log=T, optional=T + * objects: vector of string, log=T, optional=T + * opcodes: set[string], log=T, optional=T * proto: string, log=T, optional=T - * result: set[string], log=T, optional=T + * results: set[string], log=T, optional=T * ts: time, log=T, optional=F * uid: string, log=T, optional=F * version: int, log=T, optional=T @@ -379,17 +379,17 @@ connection { * ldap_searches: table[int] of record LDAP::SearchInfo, log=F, optional=T LDAP::SearchInfo { * attributes: vector of string, log=T, optional=T - * base_object: vector of string, log=T, optional=T - * deref: set[string], log=T, optional=T - * diagnostic_message: vector of string, log=T, optional=T + * base_objects: vector of string, log=T, optional=T + * derefs: set[string], log=T, optional=T + * diagnostic_messages: vector of string, log=T, optional=T * filter: string, log=T, optional=T * id: record conn_id, log=T, optional=F conn_id { ... } * message_id: int, log=T, optional=T * proto: string, log=T, optional=T - * result: set[string], log=T, optional=T * result_count: count, log=T, optional=T - * scope: set[string], log=T, optional=T + * results: set[string], log=T, optional=T + * scopes: set[string], log=T, optional=T * ts: time, log=T, optional=F * uid: string, log=T, optional=F } diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log index 8f50988763..035015d428 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log @@ -5,7 +5,7 @@ #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 proto message_id version opcode result diagnostic_message object argument +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcodes results diagnostic_messages objects arguments #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log index ad4567a0a2..7ddae0eedc 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) sAMAccountName #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log index 8f50988763..035015d428 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log @@ -5,7 +5,7 @@ #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 proto message_id version opcode result diagnostic_message object argument +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcodes results diagnostic_messages objects arguments #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log index 1497e67a58..0950708786 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log index 5c2ec47c69..b0986d5cb3 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log @@ -5,7 +5,7 @@ #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 proto message_id version opcode result diagnostic_message object argument +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcodes results diagnostic_messages objects arguments #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log index 5113c76d90..ce8ef1ccab 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log index a1f0e5f0b8..3f3e88269b 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log @@ -5,7 +5,7 @@ #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 proto message_id version opcode result diagnostic_message object argument +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id version opcodes results diagnostic_messages objects arguments #types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 215 3 bind SASL success - - GSS-SPNEGO #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log index 0436cc9f1c..f1d2a151c9 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scope deref base_object result_count result diagnostic_message filter attributes +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes #types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 213 base never - 1 success - (objectclass=*) - #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log index c63d2dea35..e208fdd3c8 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.search_filter_extended/ldap_search.log @@ -5,7 +5,7 @@ #unset_field - #path ldap_search #open XXXX-XX-XX-XX-XX-XX -#fields uid filter base_object +#fields uid filter base_objects #types string string vector[string] CHhAvVGS1DHFjwGM9 (departmentNumber:2.16.840.1.113730.3.3.2.46.1:=>=N4709) DC=matrix\x2cDC=local #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/scripts/base/protocols/ldap/search_filter_extended.zeek b/testing/btest/scripts/base/protocols/ldap/search_filter_extended.zeek index 924e1ab09a..f5c1e82378 100644 --- a/testing/btest/scripts/base/protocols/ldap/search_filter_extended.zeek +++ b/testing/btest/scripts/base/protocols/ldap/search_filter_extended.zeek @@ -4,7 +4,7 @@ # # @TEST-REQUIRES: have-spicy # @TEST-EXEC: zeek -C -r ${TRACES}/ldap/issue-32.pcapng %INPUT -# @TEST-EXEC: cat ldap_search.log | zeek-cut -C uid filter base_object > ldap_search.log2 && mv ldap_search.log2 ldap_search.log +# @TEST-EXEC: cat ldap_search.log | zeek-cut -C uid filter base_objects > ldap_search.log2 && mv ldap_search.log2 ldap_search.log # @TEST-EXEC: btest-diff ldap_search.log # # @TEST-DOC: Test LDAP analyzer with small trace. From 1d4412a9e7a93ee6906deabc24250251ada23c04 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 12:58:32 +0200 Subject: [PATCH 17/20] Tidy up LDAP code by using local references --- scripts/base/protocols/ldap/main.zeek | 68 ++++++++++++++------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index e5ecaf547a..fb3efb5bb3 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -216,70 +216,74 @@ event LDAP::message(c: connection, if (opcode == LDAP::ProtocolOpcode_SEARCH_RESULT_DONE) { set_session(c, message_id, opcode); + local searches = c$ldap_searches[message_id]; + if ( result != LDAP::ResultCode_Undef ) { - if ( ! c$ldap_searches[message_id]?$results ) - c$ldap_searches[message_id]$results = set(); - add c$ldap_searches[message_id]$results[RESULT_CODES[result]]; + if ( ! searches?$results ) + searches$results = set(); + add searches$results[RESULT_CODES[result]]; } if ( diagnostic_message != "" ) { - if ( ! c$ldap_searches[message_id]?$diagnostic_messages ) - c$ldap_searches[message_id]$diagnostic_messages = vector(); - c$ldap_searches[message_id]$diagnostic_messages += diagnostic_message; + if ( ! searches?$diagnostic_messages ) + searches$diagnostic_messages = vector(); + searches$diagnostic_messages += diagnostic_message; } - if (( ! c$ldap_searches[message_id]?$proto ) && c?$ldap_proto) - c$ldap_searches[message_id]$proto = c$ldap_proto; + if (( ! searches?$proto ) && c?$ldap_proto) + searches$proto = c$ldap_proto; - Log::write(LDAP::LDAP_SEARCH_LOG, c$ldap_searches[message_id]); + Log::write(LDAP::LDAP_SEARCH_LOG, searches); delete c$ldap_searches[message_id]; } else if (opcode !in OPCODES_SEARCH) { set_session(c, message_id, opcode); - if ( ! c$ldap_messages[message_id]?$opcodes ) - c$ldap_messages[message_id]$opcodes = set(); - add c$ldap_messages[message_id]$opcodes[PROTOCOL_OPCODES[opcode]]; + local messages = c$ldap_messages[message_id]; + + if ( ! messages?$opcodes ) + messages$opcodes = set(); + add messages$opcodes[PROTOCOL_OPCODES[opcode]]; if ( result != LDAP::ResultCode_Undef ) { - if ( ! c$ldap_messages[message_id]?$results ) - c$ldap_messages[message_id]$results = set(); - add c$ldap_messages[message_id]$results[RESULT_CODES[result]]; + if ( ! messages?$results ) + messages$results = set(); + add messages$results[RESULT_CODES[result]]; } if ( diagnostic_message != "" ) { - if ( ! c$ldap_messages[message_id]?$diagnostic_messages ) - c$ldap_messages[message_id]$diagnostic_messages = vector(); - c$ldap_messages[message_id]$diagnostic_messages += diagnostic_message; + if ( ! messages?$diagnostic_messages ) + messages$diagnostic_messages = vector(); + messages$diagnostic_messages += diagnostic_message; } if ( object != "" ) { - if ( ! c$ldap_messages[message_id]?$objects ) - c$ldap_messages[message_id]$objects = vector(); - c$ldap_messages[message_id]$objects += object; + if ( ! messages?$objects ) + messages$objects = vector(); + messages$objects += object; } if ( argument != "" ) { - if ( ! c$ldap_messages[message_id]?$arguments ) - c$ldap_messages[message_id]$arguments = vector(); - if ("bind simple" in c$ldap_messages[message_id]$opcodes && !default_capture_password) - c$ldap_messages[message_id]$arguments += "REDACTED"; + if ( ! messages?$arguments ) + messages$arguments = vector(); + if ("bind simple" in messages$opcodes && !default_capture_password) + messages$arguments += "REDACTED"; else - c$ldap_messages[message_id]$arguments += argument; + messages$arguments += argument; } if (opcode in OPCODES_FINISHED) { - if ((BIND_SIMPLE in c$ldap_messages[message_id]$opcodes) || - (BIND_SASL in c$ldap_messages[message_id]$opcodes)) { + if ((BIND_SIMPLE in messages$opcodes) || + (BIND_SASL in messages$opcodes)) { # don't have both "bind" and "bind " in the operations list - delete c$ldap_messages[message_id]$opcodes[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; + delete messages$opcodes[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; } - if (( ! c$ldap_messages[message_id]?$proto ) && c?$ldap_proto) - c$ldap_messages[message_id]$proto = c$ldap_proto; + if (( ! messages?$proto ) && c?$ldap_proto) + messages$proto = c$ldap_proto; - Log::write(LDAP::LDAP_LOG, c$ldap_messages[message_id]); + Log::write(LDAP::LDAP_LOG, messages); delete c$ldap_messages[message_id]; } } From 82b3a4048feee81169b09a8f4cfc70c429e53354 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 13:05:35 +0200 Subject: [PATCH 18/20] Use LDAP `RemovalHook` instead of implementing `connection_state_remove` --- scripts/base/protocols/ldap/main.zeek | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index fb3efb5bb3..e4453f58c6 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -30,6 +30,9 @@ export { ## Default logging policy hook for LDAP_SEARCH_LOG. global log_policy_search: Log::PolicyHook; + ## LDAP finalization hook. + global finalize_ldap: Conn::RemovalHook; + ############################################################################# # This is the format of ldap.log (ldap operations minus search-related) # Each line represents a unique connection+message_id (requests/responses) @@ -161,6 +164,7 @@ event zeek_init() &priority=5 { ############################################################################# function set_session(c: connection, message_id: int, opcode: LDAP::ProtocolOpcode) { + Conn::register_removal_hook(c, finalize_ldap); if (! c?$ldap_messages ) c$ldap_messages = table(); @@ -363,8 +367,7 @@ event LDAP::bindreq(c: connection, } ############################################################################# -event connection_state_remove(c: connection) { - +hook finalize_ldap(c: connection) { # log any "pending" unlogged LDAP messages/searches if ( c?$ldap_messages && (|c$ldap_messages| > 0) ) { From 301d8722bfe0fc32c9ec427045c6fd890a42b5dc Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 13:21:06 +0200 Subject: [PATCH 19/20] Remove redundant storing of protocol in LDAP logs --- scripts/base/protocols/ldap/main.zeek | 40 ------------------- .../coverage.record-fields/out.default | 3 -- .../ldap.log | 8 ++-- .../ldap_search.log | 6 +-- .../ldap.log | 8 ++-- .../ldap_search.log | 6 +-- .../ldap.log | 8 ++-- .../ldap_search.log | 6 +-- .../ldap.log | 6 +-- .../ldap_search.log | 6 +-- 10 files changed, 27 insertions(+), 70 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index e4453f58c6..02dd6307c2 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -46,9 +46,6 @@ export { # The connection's 4-tuple of endpoint addresses/ports. id: conn_id &log; - # transport protocol - proto: string &log &optional; - # Message ID message_id: int &log &optional; @@ -84,9 +81,6 @@ export { # The connection's 4-tuple of endpoint addresses/ports. id: conn_id &log; - # transport protocol - proto: string &log &optional; - # Message ID message_id: int &log &optional; @@ -148,7 +142,6 @@ global OPCODES_SEARCH: set[LDAP::ProtocolOpcode] = { LDAP::ProtocolOpcode_SEARCH ############################################################################# redef record connection += { - ldap_proto: string &optional; ldap_messages: table[int] of MessageInfo &optional; ldap_searches: table[int] of SearchInfo &optional; }; @@ -185,28 +178,8 @@ function set_session(c: connection, message_id: int, opcode: LDAP::ProtocolOpcod $id=c$id, $message_id=message_id]; } - } -############################################################################# -@if (Version::at_least("5.2.0")) -event analyzer_confirmation_info(atype: AllAnalyzers::Tag, info: AnalyzerConfirmationInfo) { - if ( atype == Analyzer::ANALYZER_LDAP_TCP ) { - info$c$ldap_proto = "tcp"; - } -} -@else @if (Version::at_least("4.2.0")) -event analyzer_confirmation(c: connection, atype: AllAnalyzers::Tag, aid: count) { -@else -event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) { -@endif - - if ( atype == Analyzer::ANALYZER_LDAP_TCP ) { - c$ldap_proto = "tcp"; - } - -} -@endif ############################################################################# event LDAP::message(c: connection, message_id: int, @@ -234,9 +207,6 @@ event LDAP::message(c: connection, searches$diagnostic_messages += diagnostic_message; } - if (( ! searches?$proto ) && c?$ldap_proto) - searches$proto = c$ldap_proto; - Log::write(LDAP::LDAP_SEARCH_LOG, searches); delete c$ldap_searches[message_id]; @@ -284,9 +254,6 @@ event LDAP::message(c: connection, delete messages$opcodes[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; } - if (( ! messages?$proto ) && c?$ldap_proto) - messages$proto = c$ldap_proto; - Log::write(LDAP::LDAP_LOG, messages); delete c$ldap_messages[message_id]; } @@ -379,9 +346,6 @@ hook finalize_ldap(c: connection) { delete m$opcodes[PROTOCOL_OPCODES[LDAP::ProtocolOpcode_BIND_REQUEST]]; } - if (( ! m?$proto ) && c?$ldap_proto) - m$proto = c$ldap_proto; - Log::write(LDAP::LDAP_LOG, m); } } @@ -391,10 +355,6 @@ hook finalize_ldap(c: connection) { if ( c?$ldap_searches && (|c$ldap_searches| > 0) ) { for ( [mid], s in c$ldap_searches ) { if (mid > 0) { - - if (( ! s?$proto ) && c?$ldap_proto) - s$proto = c$ldap_proto; - Log::write(LDAP::LDAP_SEARCH_LOG, s); } } diff --git a/testing/btest/Baseline/coverage.record-fields/out.default b/testing/btest/Baseline/coverage.record-fields/out.default index 6c054e555f..2d238e9489 100644 --- a/testing/btest/Baseline/coverage.record-fields/out.default +++ b/testing/btest/Baseline/coverage.record-fields/out.default @@ -369,13 +369,11 @@ connection { * message_id: int, log=T, optional=T * objects: vector of string, log=T, optional=T * opcodes: set[string], log=T, optional=T - * proto: string, log=T, optional=T * results: set[string], log=T, optional=T * ts: time, log=T, optional=F * uid: string, log=T, optional=F * version: int, log=T, optional=T } - * ldap_proto: string, log=F, optional=T * ldap_searches: table[int] of record LDAP::SearchInfo, log=F, optional=T LDAP::SearchInfo { * attributes: vector of string, log=T, optional=T @@ -386,7 +384,6 @@ connection { * id: record conn_id, log=T, optional=F conn_id { ... } * message_id: int, log=T, optional=T - * proto: string, log=T, optional=T * result_count: count, log=T, optional=T * results: set[string], log=T, optional=T * scopes: set[string], log=T, optional=T diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log index 035015d428..281b0cbcd1 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap.log @@ -5,8 +5,8 @@ #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 proto message_id version opcodes results diagnostic_messages objects arguments -#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcodes results diagnostic_messages objects arguments +#types time string addr port addr port int int set[string] set[string] vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log index 7ddae0eedc..018acb7c16 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.attributes/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes -#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) sAMAccountName +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes +#types time string addr port addr port int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) sAMAccountName #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log index 035015d428..281b0cbcd1 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap.log @@ -5,8 +5,8 @@ #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 proto message_id version opcodes results diagnostic_messages objects arguments -#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcodes results diagnostic_messages objects arguments +#types time string addr port addr port int int set[string] set[string] vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log index 0950708786..33922f0dea 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.basic/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes -#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes +#types time string addr port addr port int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 3268 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log index b0986d5cb3..4661b1bf3f 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap.log @@ -5,8 +5,8 @@ #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 proto message_id version opcodes results diagnostic_messages objects arguments -#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcodes results diagnostic_messages objects arguments +#types time string addr port addr port int int set[string] set[string] vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 1 3 bind simple success - xxxxxxxxxxx@xx.xxx.xxxxx.net REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 3 3 bind simple success - CN=xxxxxxxx\x2cOU=Users\x2cOU=Accounts\x2cDC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net REDACTED #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log index ce8ef1ccab..4bb7c32ec7 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.diff_port/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes -#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 tcp 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes +#types time string addr port addr port int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.0.0.1 25936 10.0.0.2 32681 2 tree always DC=xx\x2cDC=xxx\x2cDC=xxxxx\x2cDC=net 1 success - (&(objectclass=*)(sAMAccountName=xxxxxxxx)) - #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log index 3f3e88269b..e38f28a9f7 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap.log @@ -5,7 +5,7 @@ #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 proto message_id version opcodes results diagnostic_messages objects arguments -#types time string addr port addr port string int int set[string] set[string] vector[string] vector[string] vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 215 3 bind SASL success - - GSS-SPNEGO +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcodes results diagnostic_messages objects arguments +#types time string addr port addr port int int set[string] set[string] vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 215 3 bind SASL success - - GSS-SPNEGO #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log index f1d2a151c9..f2fd183303 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-encrypted/ldap_search.log @@ -5,7 +5,7 @@ #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 proto message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes -#types time string addr port addr port string int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 tcp 213 base never - 1 success - (objectclass=*) - +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scopes derefs base_objects result_count results diagnostic_messages filter attributes +#types time string addr port addr port int set[string] set[string] vector[string] count set[string] vector[string] string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.31.1.104 3116 172.31.1.101 389 213 base never - 1 success - (objectclass=*) - #close XXXX-XX-XX-XX-XX-XX From 346d2c49a9b9c8521714d4592f4cc9b05b6ce92f Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 10 Oct 2023 14:25:22 +0200 Subject: [PATCH 20/20] Introduce dedicated `LDAP::Info` --- scripts/base/protocols/ldap/main.zeek | 93 ++++++++++--------- .../coverage.record-fields/out.default | 61 ++++++------ 2 files changed, 79 insertions(+), 75 deletions(-) diff --git a/scripts/base/protocols/ldap/main.zeek b/scripts/base/protocols/ldap/main.zeek index 02dd6307c2..ecd30dc83e 100644 --- a/scripts/base/protocols/ldap/main.zeek +++ b/scripts/base/protocols/ldap/main.zeek @@ -7,8 +7,7 @@ module LDAP; export { - redef enum Log::ID += { LDAP_LOG, - LDAP_SEARCH_LOG }; + redef enum Log::ID += { LDAP_LOG, LDAP_SEARCH_LOG }; ## TCP ports which should be considered for analysis. const ports_tcp = { 389/tcp, 3268/tcp } &redef; @@ -107,6 +106,13 @@ export { attributes: vector of string &log &optional; }; + type State: record { + messages: table[int] of MessageInfo &optional; + searches: table[int] of SearchInfo &optional; + }; + + redef record connection += { ldap: State &optional; }; + # Event that can be handled to access the ldap record as it is sent on # to the logging framework. global log_ldap: event(rec: LDAP::MessageInfo); @@ -140,12 +146,6 @@ global OPCODES_SEARCH: set[LDAP::ProtocolOpcode] = { LDAP::ProtocolOpcode_SEARCH LDAP::ProtocolOpcode_SEARCH_RESULT_DONE, LDAP::ProtocolOpcode_SEARCH_RESULT_REFERENCE }; -############################################################################# -redef record connection += { - ldap_messages: table[int] of MessageInfo &optional; - ldap_searches: table[int] of SearchInfo &optional; -}; - ############################################################################# event zeek_init() &priority=5 { Analyzer::register_for_ports(Analyzer::ANALYZER_LDAP_TCP, LDAP::ports_tcp); @@ -159,21 +159,24 @@ event zeek_init() &priority=5 { function set_session(c: connection, message_id: int, opcode: LDAP::ProtocolOpcode) { Conn::register_removal_hook(c, finalize_ldap); - if (! c?$ldap_messages ) - c$ldap_messages = table(); + if (! c?$ldap ) + c$ldap = State(); - if (! c?$ldap_searches ) - c$ldap_searches = table(); + if (! c$ldap?$messages ) + c$ldap$messages = table(); - if ((opcode in OPCODES_SEARCH) && (message_id !in c$ldap_searches)) { - c$ldap_searches[message_id] = [$ts=network_time(), + if (! c$ldap?$searches ) + c$ldap$searches = table(); + + if ((opcode in OPCODES_SEARCH) && (message_id !in c$ldap$searches)) { + c$ldap$searches[message_id] = [$ts=network_time(), $uid=c$uid, $id=c$id, $message_id=message_id, $result_count=0]; - } else if ((opcode !in OPCODES_SEARCH) && (message_id !in c$ldap_messages)) { - c$ldap_messages[message_id] = [$ts=network_time(), + } else if ((opcode !in OPCODES_SEARCH) && (message_id !in c$ldap$messages)) { + c$ldap$messages[message_id] = [$ts=network_time(), $uid=c$uid, $id=c$id, $message_id=message_id]; @@ -193,7 +196,7 @@ event LDAP::message(c: connection, if (opcode == LDAP::ProtocolOpcode_SEARCH_RESULT_DONE) { set_session(c, message_id, opcode); - local searches = c$ldap_searches[message_id]; + local searches = c$ldap$searches[message_id]; if ( result != LDAP::ResultCode_Undef ) { if ( ! searches?$results ) @@ -208,12 +211,12 @@ event LDAP::message(c: connection, } Log::write(LDAP::LDAP_SEARCH_LOG, searches); - delete c$ldap_searches[message_id]; + delete c$ldap$searches[message_id]; } else if (opcode !in OPCODES_SEARCH) { set_session(c, message_id, opcode); - local messages = c$ldap_messages[message_id]; + local messages = c$ldap$messages[message_id]; if ( ! messages?$opcodes ) messages$opcodes = set(); @@ -255,7 +258,7 @@ event LDAP::message(c: connection, } Log::write(LDAP::LDAP_LOG, messages); - delete c$ldap_messages[message_id]; + delete c$ldap$messages[message_id]; } } @@ -276,26 +279,26 @@ event LDAP::searchreq(c: connection, set_session(c, message_id, LDAP::ProtocolOpcode_SEARCH_REQUEST); if ( scope != LDAP::SearchScope_Undef ) { - if ( ! c$ldap_searches[message_id]?$scopes ) - c$ldap_searches[message_id]$scopes = set(); - add c$ldap_searches[message_id]$scopes[SEARCH_SCOPES[scope]]; + if ( ! c$ldap$searches[message_id]?$scopes ) + c$ldap$searches[message_id]$scopes = set(); + add c$ldap$searches[message_id]$scopes[SEARCH_SCOPES[scope]]; } if ( deref != LDAP::SearchDerefAlias_Undef ) { - if ( ! c$ldap_searches[message_id]?$derefs ) - c$ldap_searches[message_id]$derefs = set(); - add c$ldap_searches[message_id]$derefs[SEARCH_DEREF_ALIASES[deref]]; + if ( ! c$ldap$searches[message_id]?$derefs ) + c$ldap$searches[message_id]$derefs = set(); + add c$ldap$searches[message_id]$derefs[SEARCH_DEREF_ALIASES[deref]]; } if ( base_object != "" ) { - if ( ! c$ldap_searches[message_id]?$base_objects ) - c$ldap_searches[message_id]$base_objects = vector(); - c$ldap_searches[message_id]$base_objects += base_object; + if ( ! c$ldap$searches[message_id]?$base_objects ) + c$ldap$searches[message_id]$base_objects = vector(); + c$ldap$searches[message_id]$base_objects += base_object; } - c$ldap_searches[message_id]$filter = filter; + c$ldap$searches[message_id]$filter = filter; if ( default_log_search_attributes ) { - c$ldap_searches[message_id]$attributes = attributes; + c$ldap$searches[message_id]$attributes = attributes; } } @@ -306,7 +309,7 @@ event LDAP::searchres(c: connection, set_session(c, message_id, LDAP::ProtocolOpcode_SEARCH_RESULT_ENTRY); - c$ldap_searches[message_id]$result_count += 1; + c$ldap$searches[message_id]$result_count += 1; } ############################################################################# @@ -316,29 +319,27 @@ event LDAP::bindreq(c: connection, name: string, authType: LDAP::BindAuthType, authInfo: string) { - set_session(c, message_id, LDAP::ProtocolOpcode_BIND_REQUEST); - if ( ! c$ldap_messages[message_id]?$version ) - c$ldap_messages[message_id]$version = version; + if ( ! c$ldap$messages[message_id]?$version ) + c$ldap$messages[message_id]$version = version; - if ( ! c$ldap_messages[message_id]?$opcodes ) - c$ldap_messages[message_id]$opcodes = set(); + if ( ! c$ldap$messages[message_id]?$opcodes ) + c$ldap$messages[message_id]$opcodes = set(); if (authType == LDAP::BindAuthType_BIND_AUTH_SIMPLE) { - add c$ldap_messages[message_id]$opcodes[BIND_SIMPLE]; + add c$ldap$messages[message_id]$opcodes[BIND_SIMPLE]; } else if (authType == LDAP::BindAuthType_BIND_AUTH_SASL) { - add c$ldap_messages[message_id]$opcodes[BIND_SASL]; + add c$ldap$messages[message_id]$opcodes[BIND_SASL]; } - } ############################################################################# hook finalize_ldap(c: connection) { # log any "pending" unlogged LDAP messages/searches - if ( c?$ldap_messages && (|c$ldap_messages| > 0) ) { - for ( [mid], m in c$ldap_messages ) { + if ( c$ldap?$messages && (|c$ldap$messages| > 0) ) { + for ( [mid], m in c$ldap$messages ) { if (mid > 0) { if ((BIND_SIMPLE in m$opcodes) || (BIND_SASL in m$opcodes)) { @@ -349,16 +350,16 @@ hook finalize_ldap(c: connection) { Log::write(LDAP::LDAP_LOG, m); } } - delete c$ldap_messages; + delete c$ldap$messages; } - if ( c?$ldap_searches && (|c$ldap_searches| > 0) ) { - for ( [mid], s in c$ldap_searches ) { + if ( c$ldap?$searches && (|c$ldap$searches| > 0) ) { + for ( [mid], s in c$ldap$searches ) { if (mid > 0) { Log::write(LDAP::LDAP_SEARCH_LOG, s); } } - delete c$ldap_searches; + delete c$ldap$searches; } } diff --git a/testing/btest/Baseline/coverage.record-fields/out.default b/testing/btest/Baseline/coverage.record-fields/out.default index 2d238e9489..b53dbd29b1 100644 --- a/testing/btest/Baseline/coverage.record-fields/out.default +++ b/testing/btest/Baseline/coverage.record-fields/out.default @@ -360,35 +360,38 @@ connection { * ts: time, log=T, optional=F * uid: string, log=T, optional=F } - * ldap_messages: table[int] of record LDAP::MessageInfo, log=F, optional=T - LDAP::MessageInfo { - * arguments: vector of string, log=T, optional=T - * diagnostic_messages: vector of string, log=T, optional=T - * id: record conn_id, log=T, optional=F - conn_id { ... } - * message_id: int, log=T, optional=T - * objects: vector of string, log=T, optional=T - * opcodes: set[string], log=T, optional=T - * results: set[string], log=T, optional=T - * ts: time, log=T, optional=F - * uid: string, log=T, optional=F - * version: int, log=T, optional=T - } - * ldap_searches: table[int] of record LDAP::SearchInfo, log=F, optional=T - LDAP::SearchInfo { - * attributes: vector of string, log=T, optional=T - * base_objects: vector of string, log=T, optional=T - * derefs: set[string], log=T, optional=T - * diagnostic_messages: vector of string, log=T, optional=T - * filter: string, log=T, optional=T - * id: record conn_id, log=T, optional=F - conn_id { ... } - * message_id: int, log=T, optional=T - * result_count: count, log=T, optional=T - * results: set[string], log=T, optional=T - * scopes: set[string], log=T, optional=T - * ts: time, log=T, optional=F - * uid: string, log=T, optional=F + * ldap: record LDAP::State, log=F, optional=T + LDAP::State { + * messages: table[int] of record LDAP::MessageInfo, log=F, optional=T + LDAP::MessageInfo { + * arguments: vector of string, log=T, optional=T + * diagnostic_messages: vector of string, log=T, optional=T + * id: record conn_id, log=T, optional=F + conn_id { ... } + * message_id: int, log=T, optional=T + * objects: vector of string, log=T, optional=T + * opcodes: set[string], log=T, optional=T + * results: set[string], log=T, optional=T + * ts: time, log=T, optional=F + * uid: string, log=T, optional=F + * version: int, log=T, optional=T + } + * searches: table[int] of record LDAP::SearchInfo, log=F, optional=T + LDAP::SearchInfo { + * attributes: vector of string, log=T, optional=T + * base_objects: vector of string, log=T, optional=T + * derefs: set[string], log=T, optional=T + * diagnostic_messages: vector of string, log=T, optional=T + * filter: string, log=T, optional=T + * id: record conn_id, log=T, optional=F + conn_id { ... } + * message_id: int, log=T, optional=T + * result_count: count, log=T, optional=T + * results: set[string], log=T, optional=T + * scopes: set[string], log=T, optional=T + * ts: time, log=T, optional=F + * uid: string, log=T, optional=F + } } * modbus: record Modbus::Info, log=F, optional=T Modbus::Info {