Initial
This commit is contained in:
commit
bd2d73ef4f
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.28.0-rc5 FATAL_ERROR)
|
||||
|
||||
project(Plugin)
|
||||
|
||||
include(ZeekPlugin)
|
||||
|
||||
zeek_plugin_begin(Zeek TDS)
|
||||
zeek_plugin_cc(src/TDS.cc src/Plugin.cc)
|
||||
zeek_plugin_bif(src/events.bif)
|
||||
zeek_plugin_pac(src/tds.pac src/tds-analyzer.pac src/tds-protocol.pac)
|
||||
zeek_plugin_dist_files(README CHANGES COPYING VERSION)
|
||||
zeek_plugin_end()
|
||||
4
CODE_OF_CONDUCT.md
Normal file
4
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,4 @@
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
61
CONTRIBUTING.md
Normal file
61
CONTRIBUTING.md
Normal file
@ -0,0 +1,61 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
|
||||
documentation, we greatly value feedback and contributions from our community.
|
||||
|
||||
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
|
||||
information to effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Reporting Bugs/Feature Requests
|
||||
|
||||
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
|
||||
|
||||
When filing an issue, please check [existing open](https://github.com/amzn/zeek-plugin-tds/issues), or [recently closed](https://github.com/amzn/zeek-plugin-tds/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
|
||||
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
|
||||
|
||||
* A reproducible test case or series of steps
|
||||
* The version of our code being used
|
||||
* Any modifications you've made relevant to the bug
|
||||
* Anything unusual about your environment or deployment
|
||||
|
||||
|
||||
## Contributing via Pull Requests
|
||||
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
|
||||
|
||||
1. You are working against the latest source on the *master* branch.
|
||||
2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
|
||||
3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
|
||||
|
||||
To send us a pull request, please:
|
||||
|
||||
1. Fork the repository.
|
||||
2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
|
||||
3. Ensure local tests pass.
|
||||
4. Commit to your fork using clear commit messages.
|
||||
5. Send us a pull request, answering any default questions in the pull request interface.
|
||||
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
|
||||
|
||||
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
|
||||
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
|
||||
|
||||
|
||||
## Finding contributions to work on
|
||||
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/amzn/zeek-plugin-tds/labels/help%20wanted) issues is a great place to start.
|
||||
|
||||
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
|
||||
|
||||
## Security issue notifications
|
||||
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
|
||||
|
||||
|
||||
## Licensing
|
||||
|
||||
See the [LICENSE](https://github.com/amzn/zeek-plugin-tds/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
|
||||
|
||||
We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
|
||||
49
Dockerfile
Normal file
49
Dockerfile
Normal file
@ -0,0 +1,49 @@
|
||||
FROM public.ecr.aws/amazonlinux/amazonlinux:latest
|
||||
MAINTAINER https://github.com/amzn/
|
||||
|
||||
# Metadata
|
||||
LABEL program=zeek
|
||||
|
||||
# Specify program
|
||||
ENV PROG zeek
|
||||
# Specify source extension
|
||||
ENV EXT tar.gz
|
||||
# Specify Zeek version to download and install (e.g. 3.0.0)
|
||||
ENV VERS 3.2.4
|
||||
|
||||
# Specify Cmake version
|
||||
ENV CMAKEVERSMAIN 3.10
|
||||
ENV CMAKEVERSSUB .0
|
||||
|
||||
# Install directory
|
||||
ENV PREFIX /opt/zeek
|
||||
# Path should include prefix
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PREFIX/bin
|
||||
|
||||
# Install dependencies
|
||||
RUN yum -y update
|
||||
RUN yum -y install cronie epel-release gcc gcc-c++ make libpcap-devel openssl-devel bind-devel zlib-devel git perl libcurl-devel GeoIP-devel python-devel jemalloc-devel swig libpcap bind-libs zlib bash python3 libcurl gawk GeoIP jemalloc wget flex bison python3-pip tar iproute procps-ng kernel-devel clang gdb && yum clean all
|
||||
|
||||
# Zeek 3.1.0 needs Cmake 3.0 or higher
|
||||
WORKDIR /tmp
|
||||
RUN wget https://cmake.org/files/v$CMAKEVERSMAIN/cmake-$CMAKEVERSMAIN$CMAKEVERSSUB.tar.gz
|
||||
RUN tar -xvzf cmake-$CMAKEVERSMAIN$CMAKEVERSSUB.tar.gz
|
||||
WORKDIR /tmp/cmake-$CMAKEVERSMAIN$CMAKEVERSSUB
|
||||
RUN /tmp/cmake-$CMAKEVERSMAIN$CMAKEVERSSUB/bootstrap
|
||||
RUN make -j$((`nproc`-1))
|
||||
RUN make install
|
||||
|
||||
# Compile and install Zeek
|
||||
WORKDIR /tmp
|
||||
RUN wget https://old.zeek.org/downloads/$PROG-$VERS.$EXT && tar -xzf $PROG-$VERS.$EXT
|
||||
WORKDIR /tmp/$PROG-$VERS
|
||||
RUN ./configure --build-type=RelWithDebInfo --prefix=$PREFIX --disable-python
|
||||
RUN make -j$((`nproc`-1))
|
||||
RUN make install
|
||||
|
||||
USER root
|
||||
RUN pip3 install zkg
|
||||
RUN zkg autoconfig
|
||||
COPY [--chown=bro:bro] . /tmp/zeek-plugin-tds
|
||||
WORKDIR /tmp/zeek-plugin-tds
|
||||
RUN zkg install --force .
|
||||
23
LICENSE
Normal file
23
LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its 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 HOLDER 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.
|
||||
29
Makefile
Normal file
29
Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# Convenience Makefile providing a few common top-level targets.
|
||||
#
|
||||
|
||||
cmake_build_dir=build
|
||||
arch=`uname -s | tr A-Z a-z`-`uname -m`
|
||||
|
||||
all: build-it
|
||||
|
||||
build-it:
|
||||
@test -e $(cmake_build_dir)/config.status || ./configure
|
||||
-@test -e $(cmake_build_dir)/CMakeCache.txt && \
|
||||
test $(cmake_build_dir)/CMakeCache.txt -ot `cat $(cmake_build_dir)/CMakeCache.txt | grep ZEEK_DIST | cut -d '=' -f 2`/build/CMakeCache.txt && \
|
||||
echo Updating stale CMake cache && \
|
||||
touch $(cmake_build_dir)/CMakeCache.txt
|
||||
|
||||
( cd $(cmake_build_dir) && make )
|
||||
|
||||
install:
|
||||
( cd $(cmake_build_dir) && make install )
|
||||
|
||||
clean:
|
||||
( cd $(cmake_build_dir) && make clean )
|
||||
|
||||
distclean:
|
||||
rm -rf $(cmake_build_dir)
|
||||
|
||||
test:
|
||||
if [ -f build/lib/Zeek-* ]; then make -C tests; else echo "Plugin not built."; fi
|
||||
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
||||
## Zeek Plugin TDS
|
||||
|
||||
When running as part of your Zeek installation this plugin will produce three log files containing metadata extracted from any [Tabular Data Stream](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/b46a581a-39de-4745-b076-ec4dbb7d13ec) (TDS) traffic observed on TCP port 1433.
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
`zeek-plugin-tds` is distributed as a Zeek package and is compatible with the [`zkg`](https://docs.zeek.org/projects/package-manager/en/stable/zkg.html) command line tool.
|
||||
|
||||
## Sharing and Contributing
|
||||
|
||||
This code is made available under the [BSD-3-Clause license](https://github.com/amzn/zeek-plugin-tds/blob/master/LICENSE). [Guidelines for contributing](https://github.com/amzn/zeek-plugin-tds/blob/master/CONTRIBUTING.md) are available as well as a [pull request template](https://github.com/amzn/zeek-plugin-tds/blob/master/.github/PULL_REQUEST_TEMPLATE.md). A [Dockerfile](https://github.com/amzn/zeek-plugin-tds/blob/master/Dockerfile) has been included in the repository to assist with setting up an environment for testing any changes to the plugin.
|
||||
188
configure
vendored
Executable file
188
configure
vendored
Executable file
@ -0,0 +1,188 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Wrapper for viewing/setting options that the plugin's CMake
|
||||
# scripts will recognize.
|
||||
#
|
||||
# Don't edit this. Edit configure.plugin to add plugin-specific options.
|
||||
#
|
||||
|
||||
set -e
|
||||
command="$0 $*"
|
||||
|
||||
if [ -e `dirname $0`/configure.plugin ]; then
|
||||
# Include custom additions.
|
||||
. `dirname $0`/configure.plugin
|
||||
fi
|
||||
|
||||
usage() {
|
||||
|
||||
cat 1>&2 <<EOF
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Plugin Options:
|
||||
--cmake=PATH Path to CMake binary
|
||||
--zeek-dist=DIR Path to Zeek source tree
|
||||
--install-root=DIR Path where to install plugin into
|
||||
--with-binpac=DIR Path to BinPAC installation root
|
||||
--with-broker=DIR Path to Broker installation root
|
||||
--with-caf=DIR Path to CAF installation root
|
||||
--with-bifcl=PATH Path to bifcl executable
|
||||
--enable-debug Compile in debugging mode
|
||||
EOF
|
||||
|
||||
if type plugin_usage >/dev/null 2>&1; then
|
||||
plugin_usage 1>&2
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to append a CMake cache entry definition to the
|
||||
# CMakeCacheEntries variable
|
||||
# $1 is the cache entry variable name
|
||||
# $2 is the cache entry variable type
|
||||
# $3 is the cache entry variable value
|
||||
append_cache_entry () {
|
||||
CMakeCacheEntries="$CMakeCacheEntries -D $1:$2=$3"
|
||||
}
|
||||
|
||||
# set defaults
|
||||
builddir=build
|
||||
zeekdist=""
|
||||
installroot="default"
|
||||
CMakeCacheEntries=""
|
||||
|
||||
while [ $# -ne 0 ]; do
|
||||
case "$1" in
|
||||
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
|
||||
*) optarg= ;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
--help|-h)
|
||||
usage
|
||||
;;
|
||||
|
||||
--cmake=*)
|
||||
CMakeCommand=$optarg
|
||||
;;
|
||||
|
||||
--zeek-dist=*)
|
||||
zeekdist=`cd $optarg && pwd`
|
||||
;;
|
||||
|
||||
--install-root=*)
|
||||
installroot=$optarg
|
||||
;;
|
||||
|
||||
--with-binpac=*)
|
||||
append_cache_entry BinPAC_ROOT_DIR PATH $optarg
|
||||
binpac_root=$optarg
|
||||
;;
|
||||
|
||||
--with-broker=*)
|
||||
append_cache_entry BROKER_ROOT_DIR PATH $optarg
|
||||
broker_root=$optarg
|
||||
;;
|
||||
|
||||
--with-caf=*)
|
||||
append_cache_entry CAF_ROOT_DIR PATH $optarg
|
||||
caf_root=$optarg
|
||||
;;
|
||||
|
||||
--with-bifcl=*)
|
||||
append_cache_entry BifCl_EXE PATH $optarg
|
||||
;;
|
||||
|
||||
--enable-debug)
|
||||
append_cache_entry BRO_PLUGIN_ENABLE_DEBUG BOOL true
|
||||
;;
|
||||
|
||||
*)
|
||||
if type plugin_option >/dev/null 2>&1; then
|
||||
plugin_option $1 && shift && continue;
|
||||
fi
|
||||
|
||||
echo "Invalid option '$1'. Try $0 --help to see available options."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$CMakeCommand" ]; then
|
||||
# prefer cmake3 over "regular" cmake (cmake == cmake2 on RHEL)
|
||||
if command -v cmake3 >/dev/null 2>&1 ; then
|
||||
CMakeCommand="cmake3"
|
||||
elif command -v cmake >/dev/null 2>&1 ; then
|
||||
CMakeCommand="cmake"
|
||||
else
|
||||
echo "This package requires CMake, please install it first."
|
||||
echo "Then you may use this script to configure the CMake build."
|
||||
echo "Note: pass --cmake=PATH to use cmake in non-standard locations."
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$zeekdist" ]; then
|
||||
if type zeek-config >/dev/null 2>&1; then
|
||||
zeek_config="zeek-config"
|
||||
else
|
||||
echo "Either 'zeek-config' must be in PATH or '--zeek-dist=<path>' used"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
append_cache_entry BRO_CONFIG_PREFIX PATH `${zeek_config} --prefix`
|
||||
append_cache_entry BRO_CONFIG_INCLUDE_DIR PATH `${zeek_config} --include_dir`
|
||||
append_cache_entry BRO_CONFIG_PLUGIN_DIR PATH `${zeek_config} --plugin_dir`
|
||||
append_cache_entry BRO_CONFIG_CMAKE_DIR PATH `${zeek_config} --cmake_dir`
|
||||
append_cache_entry CMAKE_MODULE_PATH PATH `${zeek_config} --cmake_dir`
|
||||
|
||||
build_type=`${zeek_config} --build_type`
|
||||
|
||||
if [ "$build_type" = "debug" ]; then
|
||||
append_cache_entry BRO_PLUGIN_ENABLE_DEBUG BOOL true
|
||||
fi
|
||||
|
||||
if [ -z "$binpac_root" ]; then
|
||||
append_cache_entry BinPAC_ROOT_DIR PATH `${zeek_config} --binpac_root`
|
||||
fi
|
||||
|
||||
if [ -z "$broker_root" ]; then
|
||||
append_cache_entry BROKER_ROOT_DIR PATH `${zeek_config} --broker_root`
|
||||
fi
|
||||
|
||||
if [ -z "$caf_root" ]; then
|
||||
append_cache_entry CAF_ROOT_DIR PATH `${zeek_config} --caf_root`
|
||||
fi
|
||||
else
|
||||
if [ ! -e "$zeekdist/zeek-path-dev.in" ]; then
|
||||
echo "$zeekdist does not appear to be a valid Zeek source tree."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# BRO_DIST is the canonical/historical name used by plugin CMake scripts
|
||||
# ZEEK_DIST doesn't serve a function at the moment, but set/provided anyway
|
||||
append_cache_entry BRO_DIST PATH $zeekdist
|
||||
append_cache_entry ZEEK_DIST PATH $zeekdist
|
||||
append_cache_entry CMAKE_MODULE_PATH PATH $zeekdist/cmake
|
||||
fi
|
||||
|
||||
if [ "$installroot" != "default" ]; then
|
||||
mkdir -p $installroot
|
||||
append_cache_entry BRO_PLUGIN_INSTALL_ROOT PATH $installroot
|
||||
fi
|
||||
|
||||
echo "Build Directory : $builddir"
|
||||
echo "Zeek Source Directory : $zeekdist"
|
||||
|
||||
mkdir -p $builddir
|
||||
cd $builddir
|
||||
|
||||
"$CMakeCommand" $CMakeCacheEntries ..
|
||||
|
||||
echo "# This is the command used to configure this build" > config.status
|
||||
echo $command >> config.status
|
||||
chmod u+x config.status
|
||||
26
configure.plugin
Normal file
26
configure.plugin
Normal file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Hooks to add custom options to the configure script.
|
||||
#
|
||||
|
||||
plugin_usage()
|
||||
{
|
||||
: # Do nothing
|
||||
# cat <<EOF
|
||||
# --with-foo=DIR Path to foo
|
||||
# EOF
|
||||
}
|
||||
|
||||
plugin_option()
|
||||
{
|
||||
case "$1" in
|
||||
# --with-foo=*)
|
||||
# append_cache_entry FOO_DIR PATH $optarg
|
||||
# return 0
|
||||
# ;;
|
||||
|
||||
*)
|
||||
return 1;
|
||||
;;
|
||||
esac
|
||||
}
|
||||
3
scripts/TDS/__load__.zeek
Normal file
3
scripts/TDS/__load__.zeek
Normal file
@ -0,0 +1,3 @@
|
||||
@load ./consts.zeek
|
||||
@load ./main.zeek
|
||||
|
||||
30
scripts/TDS/consts.zeek
Normal file
30
scripts/TDS/consts.zeek
Normal file
@ -0,0 +1,30 @@
|
||||
## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
## SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
module TDS;
|
||||
|
||||
export {
|
||||
## TDS default commands
|
||||
const commands = {
|
||||
[0x00] = "NOP",
|
||||
[0x01] = "SQL Batch",
|
||||
[0x02] = "Pre TDS7 Login",
|
||||
[0x03] = "Remote Procedure Call",
|
||||
[0x04] = "SQL Batch Server Response",
|
||||
[0x05] = "Unused",
|
||||
[0x06] = "Attention Request",
|
||||
[0x07] = "Bulk Load Data",
|
||||
[0x0E] = "Transcation Manager Request",
|
||||
[0x0F] = "TDS5 Query",
|
||||
[0x10] = "TDS7 Login",
|
||||
[0x11] = "SSPI Message",
|
||||
[0x12] = "Pre-Login Request",
|
||||
} &default=function(i: count):string { return fmt("command (%d)", i); } &redef;
|
||||
|
||||
## TDS header types
|
||||
const header_types = {
|
||||
[0x0000] = "NOP",
|
||||
[0x0001] = "Query notifications",
|
||||
[0x0002] = "Transaction Descriptor",
|
||||
} &default=function(i: count):string { return fmt("command (%d)", i); } &redef;
|
||||
}
|
||||
217
scripts/TDS/main.zeek
Normal file
217
scripts/TDS/main.zeek
Normal file
@ -0,0 +1,217 @@
|
||||
##! Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
##! SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
##! Implements base functionality for TDS analysis.
|
||||
##! Generates the tds.log file, containing some information about the TDS headers.
|
||||
##! Generates the tds_rpc.log file, containing some information about rpc data.
|
||||
##! Generates the tds_sql_batch.log file, containing some information about sql batch data.
|
||||
|
||||
module TDS;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += {
|
||||
Log_TDS,
|
||||
Log_TDS_RPC,
|
||||
Log_TDS_SQL_Batch
|
||||
};
|
||||
|
||||
## header info
|
||||
type TDS: record {
|
||||
ts : time &log; ## Timestamp for when the event happened.
|
||||
uid : string &log; ## Unique ID for the connection.
|
||||
id : conn_id &log; ## The connection's 4-tuple of endpoint addresses/ports.
|
||||
|
||||
command : string &optional &log; ## Name of the sent TDS command.
|
||||
};
|
||||
## Event that can be handled to access the tds record as it is sent to the loggin framework.
|
||||
global log_tds: event(rec: TDS);
|
||||
|
||||
## Remote Procedure Call
|
||||
type TDS_RPC: record {
|
||||
ts : time &log; ## Timestamp for when the event happened.
|
||||
uid : string &log; ## Unique ID for the connection.
|
||||
id : conn_id &log; ## The connection's 4-tuple of endpoint addresses/ports.
|
||||
|
||||
procedure_name : string &optional &log;
|
||||
parameters : string_vec &optional &log;
|
||||
};
|
||||
## Event that can be handled to access the tds record as it is sent to the loggin framework.
|
||||
global log_tds_rpc: event(rec: TDS_RPC);
|
||||
|
||||
## SQL Batch
|
||||
type TDS_SQL_Batch: record {
|
||||
ts : time &log; ## Timestamp for when the event happened.
|
||||
uid : string &log; ## Unique ID for the connection.
|
||||
id : conn_id &log; ## The connection's 4-tuple of endpoint addresses/ports.
|
||||
|
||||
header_type : string &optional &log;
|
||||
query : string &optional &log;
|
||||
};
|
||||
## Event that can be handled to access the tds record as it is sent to the loggin framework.
|
||||
global log_tds_sql_batch: event(rec: TDS_SQL_Batch);
|
||||
}
|
||||
|
||||
redef record connection += {
|
||||
tds : TDS &optional;
|
||||
tds_rpc : TDS_RPC &optional;
|
||||
tds_sql_batch : TDS_SQL_Batch &optional;
|
||||
};
|
||||
|
||||
## define listening ports
|
||||
const ports = {
|
||||
1433/tcp
|
||||
};
|
||||
redef likely_server_ports += {
|
||||
ports
|
||||
};
|
||||
|
||||
event zeek_init() &priority=5 {
|
||||
Log::create_stream(TDS::Log_TDS,
|
||||
[$columns=TDS,
|
||||
$ev=log_tds,
|
||||
$path="tds"]);
|
||||
Log::create_stream(TDS::Log_TDS_RPC,
|
||||
[$columns=TDS_RPC,
|
||||
$ev=log_tds_rpc,
|
||||
$path="tds_rpc"]);
|
||||
Log::create_stream(TDS::Log_TDS_SQL_Batch,
|
||||
[$columns=TDS_SQL_Batch,
|
||||
$ev=log_tds_sql_batch,
|
||||
$path="tds_sql_batch"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_TDS, ports);
|
||||
}
|
||||
|
||||
##! general tds header
|
||||
event tds(c: connection, is_orig: bool, command: count) {
|
||||
if(!c?$tds) {
|
||||
c$tds = [$ts=network_time(), $uid=c$uid, $id=c$id];
|
||||
}
|
||||
|
||||
c$tds$ts = network_time();
|
||||
c$tds$command = commands[command];
|
||||
|
||||
Log::write(Log_TDS, c$tds);
|
||||
delete c$tds;
|
||||
}
|
||||
|
||||
##! general tds rpc
|
||||
event tds_rpc(c: connection, is_orig: bool,
|
||||
procedure_name: string,
|
||||
parameters: string) {
|
||||
if(!c?$tds_rpc) {
|
||||
c$tds_rpc = [$ts=network_time(), $uid=c$uid, $id=c$id];
|
||||
}
|
||||
|
||||
c$tds_rpc$ts = network_time();
|
||||
c$tds_rpc$procedure_name = subst_string(procedure_name, "\x00", "");
|
||||
local params_size: count = |parameters|;
|
||||
if (params_size > 0) {
|
||||
local params: string_vec;
|
||||
local params_index: count=0;
|
||||
local param_index: count=0;
|
||||
local param_name: string="";
|
||||
local param_type: count=0;
|
||||
local param_data: string;
|
||||
local param_len: count=0;
|
||||
while (param_index < params_size) {
|
||||
param_len = bytestring_to_count(parameters[param_index])*2;
|
||||
param_index += 1;
|
||||
param_name = subst_string(parameters[param_index: param_index+param_len], "\x00", "");
|
||||
param_index += param_len;
|
||||
param_index += 1; ##! status
|
||||
param_type = bytestring_to_count(parameters[param_index]);
|
||||
param_index += 1;
|
||||
param_data = "";
|
||||
switch (param_type) {
|
||||
case 0x24, ##! GUID
|
||||
0x26, ##! int
|
||||
0x68, ##! bit
|
||||
0x6d, ##! float
|
||||
0x6f: ##! DateTime
|
||||
param_index += 1; ##! max length
|
||||
param_len = bytestring_to_count(parameters[param_index]);
|
||||
param_index += 1;
|
||||
switch (param_type) {
|
||||
case 0x24: ##! GUID
|
||||
param_data = bytestring_to_hexstr(parameters[param_index+3]);
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+2]);
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+1]);
|
||||
param_data += bytestring_to_hexstr(parameters[param_index]);
|
||||
param_data += "-";
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+5]);
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+4]);
|
||||
param_data += "-";
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+7]);
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+6]);
|
||||
param_data += "-";
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+8:param_index+10]);
|
||||
param_data += "-";
|
||||
param_data += bytestring_to_hexstr(parameters[param_index+10:param_index+param_len]);
|
||||
break;
|
||||
case 0x68: ##! bit
|
||||
if (bytestring_to_count(parameters[param_index]) == 1) {
|
||||
param_data = "True";
|
||||
}
|
||||
else {
|
||||
param_data = "False";
|
||||
}
|
||||
break;
|
||||
case 0x6d: ##! float
|
||||
param_data = fmt("%f", bytestring_to_double(parameters[param_index:param_index+param_len]));
|
||||
break;
|
||||
default:
|
||||
if (param_index >= params_size) {
|
||||
break;
|
||||
}
|
||||
param_data = fmt("%d", bytestring_to_count(parameters[param_index:param_index+param_len], T));
|
||||
break;
|
||||
}
|
||||
param_index += param_len;
|
||||
params[params_index] = fmt("%s=%s", param_name, param_data);
|
||||
params_index += 1;
|
||||
break;
|
||||
case 0xa7, ##! VarChar
|
||||
0xe7: ##! NVarChar
|
||||
param_index += 2; ##! max length
|
||||
param_index += 5; ##! collation
|
||||
param_len = bytestring_to_count(parameters[param_index:param_index+2], T);
|
||||
param_index += 2;
|
||||
##! NULL is 65535
|
||||
if (param_len > 0 && param_len < 65535) {
|
||||
param_data = subst_string(parameters[param_index:param_index+param_len], "\x00", "");
|
||||
param_index += param_len;
|
||||
}
|
||||
params[params_index] = fmt("%s=%s", param_name, param_data);
|
||||
params_index += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c$tds_rpc$parameters = params;
|
||||
}
|
||||
|
||||
Log::write(Log_TDS_RPC, c$tds_rpc);
|
||||
delete c$tds_rpc;
|
||||
}
|
||||
|
||||
event tds_sql_batch(c: connection, is_orig: bool,
|
||||
header_type: count,
|
||||
query: string) {
|
||||
if(!c?$tds_sql_batch) {
|
||||
c$tds_sql_batch = [$ts=network_time(), $uid=c$uid, $id=c$id];
|
||||
}
|
||||
|
||||
c$tds_sql_batch$ts = network_time();
|
||||
c$tds_sql_batch$header_type = header_types[header_type];
|
||||
query = subst_string(query, "\x00", "");
|
||||
c$tds_sql_batch$query = query;
|
||||
|
||||
Log::write(Log_TDS_SQL_Batch, c$tds_sql_batch);
|
||||
delete c$tds_sql_batch;
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection) &priority=-5 {
|
||||
if(c?$tds) {
|
||||
delete c$tds;
|
||||
}
|
||||
}
|
||||
19
src/Plugin.cc
Normal file
19
src/Plugin.cc
Normal file
@ -0,0 +1,19 @@
|
||||
#include "Plugin.h"
|
||||
#include "zeek/analyzer/Component.h"
|
||||
|
||||
namespace plugin {
|
||||
namespace Zeek_TDS {
|
||||
Plugin plugin;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace plugin::Zeek_TDS;
|
||||
|
||||
zeek::plugin::Configuration Plugin::Configure() {
|
||||
AddComponent(new zeek::analyzer::Component("TDS", analyzer::tds::TDS_Analyzer::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::TDS";
|
||||
config.description = "MS-SQL TDS protocol analyzer";
|
||||
return config;
|
||||
}
|
||||
19
src/Plugin.h
Normal file
19
src/Plugin.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef ZEEK_PLUGIN_ZEEK_TDS
|
||||
#define ZEEK_PLUGIN_ZEEK_TDS
|
||||
|
||||
#include <zeek/plugin/Plugin.h>
|
||||
#include "TDS.h"
|
||||
|
||||
namespace plugin {
|
||||
namespace Zeek_TDS {
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
protected:
|
||||
// Overridden from plugin::Plugin.
|
||||
virtual zeek::plugin::Configuration Configure();
|
||||
};
|
||||
|
||||
extern Plugin plugin;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/TDS.cc
Normal file
50
src/TDS.cc
Normal file
@ -0,0 +1,50 @@
|
||||
#include "TDS.h"
|
||||
#include <zeek/analyzer/protocol/tcp/TCP_Reassembler.h>
|
||||
#include <zeek/Reporter.h>
|
||||
#include "events.bif.h"
|
||||
|
||||
using namespace analyzer::tds;
|
||||
|
||||
TDS_Analyzer::TDS_Analyzer(zeek::Connection* c): zeek::analyzer::tcp::TCP_ApplicationAnalyzer("TDS", c) {
|
||||
interp = new binpac::TDS::TDS_Conn(this);
|
||||
had_gap = false;
|
||||
}
|
||||
|
||||
TDS_Analyzer::~TDS_Analyzer() {
|
||||
delete interp;
|
||||
}
|
||||
|
||||
void TDS_Analyzer::Done() {
|
||||
zeek::analyzer::tcp::TCP_ApplicationAnalyzer::Done();
|
||||
interp->FlowEOF(true);
|
||||
interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void TDS_Analyzer::EndpointEOF(bool is_orig) {
|
||||
zeek::analyzer::tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void TDS_Analyzer::DeliverStream(int len, const u_char* data, bool orig) {
|
||||
zeek::analyzer::tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||
assert(TCP());
|
||||
//if(TCP()->IsPartial())
|
||||
// return;
|
||||
// If only one side had a content gap, we could still try to
|
||||
// deliver data to the other side if the script layer can handle this.
|
||||
if(had_gap)
|
||||
return;
|
||||
|
||||
try {
|
||||
interp->NewData(orig, data, data + len);
|
||||
}
|
||||
catch(const binpac::Exception& e) {
|
||||
AnalyzerViolation(zeek::util::fmt("Binpac exception: %s", e.c_msg()));
|
||||
}
|
||||
}
|
||||
|
||||
void TDS_Analyzer::Undelivered(uint64_t seq, int len, bool orig) {
|
||||
zeek::analyzer::tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||
had_gap = true;
|
||||
interp->NewGap(orig, len);
|
||||
}
|
||||
31
src/TDS.h
Normal file
31
src/TDS.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef ANALYZER_PROTOCOL_TDS_H
|
||||
#define ANALYZER_PROTOCOL_TDS_H
|
||||
|
||||
#include <zeek/analyzer/protocol/tcp/TCP.h>
|
||||
#include "tds_pac.h"
|
||||
|
||||
namespace analyzer {
|
||||
namespace tds {
|
||||
class TDS_Analyzer : public zeek::analyzer::tcp::TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
TDS_Analyzer(zeek::Connection* conn);
|
||||
virtual ~TDS_Analyzer();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(uint64_t seq, int len, bool orig);
|
||||
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static zeek::analyzer::Analyzer* Instantiate(zeek::Connection* conn) {
|
||||
return new TDS_Analyzer(conn);
|
||||
}
|
||||
|
||||
protected:
|
||||
binpac::TDS::TDS_Conn* interp;
|
||||
bool had_gap;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
40
src/events.bif
Normal file
40
src/events.bif
Normal file
@ -0,0 +1,40 @@
|
||||
## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
## SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
######################################
|
||||
## Generated for all the TDS headers #
|
||||
######################################
|
||||
## c: The connection the TDS communication is part of.
|
||||
## is_orig: True if this reflects originator-side activity.
|
||||
## command: uint16 of either request/response
|
||||
## index: index# of the packet.
|
||||
##
|
||||
event tds%(c: connection, is_orig: bool,
|
||||
command: count
|
||||
%);
|
||||
|
||||
############################################
|
||||
## Generated for the remote procedure call #
|
||||
############################################
|
||||
## c: The connection the TDS communication is part of.
|
||||
## is_orig: True if this reflects originator-side activity.
|
||||
## product_name: product name.
|
||||
## serial_number: serial number.
|
||||
##
|
||||
event tds_rpc%(c: connection, is_orig: bool,
|
||||
procedure_name: string,
|
||||
parameters: string
|
||||
%);
|
||||
|
||||
####################################
|
||||
## Generated for the identity info #
|
||||
####################################
|
||||
## c: The connection the TDS communication is part of.
|
||||
## is_orig: True if this reflects originator-side activity.
|
||||
## product_name: product name.
|
||||
## serial_number: serial number.
|
||||
##
|
||||
event tds_sql_batch%(c: connection, is_orig: bool,
|
||||
header_type: count,
|
||||
query: string
|
||||
%);
|
||||
101
src/tds-analyzer.pac
Normal file
101
src/tds-analyzer.pac
Normal file
@ -0,0 +1,101 @@
|
||||
## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
## SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
connection TDS_Conn(zeek_analyzer: ZeekAnalyzer) {
|
||||
upflow = TDS_Flow(true);
|
||||
downflow = TDS_Flow(false);
|
||||
};
|
||||
|
||||
%header{
|
||||
#define SQL_BATCH 0x01
|
||||
#define PRE_TDS7_LOGIN 0x02
|
||||
#define REMOTE_PROCEDURE_CALL 0x03
|
||||
#define RESPONSE 0x04
|
||||
#define UNUSED 0x05
|
||||
#define ATTENTION_REQUEST 0x06
|
||||
#define BULK_LOAD_DATA 0x07
|
||||
#define TRANSACTION_MANAGER 0x0e
|
||||
#define TDS5_QUERY 0x0F
|
||||
#define TDS7_LOGIN 0x10
|
||||
#define SSPI_MESSAGE 0x11
|
||||
#define TDS7_PRELOGIN 0x12
|
||||
|
||||
#define QUERY_NOTIFICATIONS 0x0001
|
||||
#define TRANSACTION_DESCRIPTOR 0x0002
|
||||
%}
|
||||
|
||||
flow TDS_Flow(is_orig: bool) {
|
||||
# flowunit ?
|
||||
datagram = TDS_PDU(is_orig) withcontext(connection, this);
|
||||
|
||||
function tds(header: TDS): bool %{
|
||||
if(::tds) {
|
||||
if (${header.command} != SQL_BATCH &&
|
||||
${header.command} != PRE_TDS7_LOGIN &&
|
||||
${header.command} != REMOTE_PROCEDURE_CALL &&
|
||||
${header.command} != RESPONSE &&
|
||||
${header.command} != UNUSED &&
|
||||
${header.command} != ATTENTION_REQUEST &&
|
||||
${header.command} != BULK_LOAD_DATA &&
|
||||
${header.command} != TRANSACTION_MANAGER &&
|
||||
${header.command} != TDS5_QUERY &&
|
||||
${header.command} != TDS7_LOGIN &&
|
||||
${header.command} != SSPI_MESSAGE &&
|
||||
${header.command} != TDS7_PRELOGIN) {
|
||||
return false;
|
||||
}
|
||||
connection()->zeek_analyzer()->AnalyzerConfirmation();
|
||||
zeek::BifEvent::enqueue_tds(connection()->zeek_analyzer(),
|
||||
connection()->zeek_analyzer()->Conn(),
|
||||
is_orig(),
|
||||
${header.command}
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function tds_rpc(rpc: TDS_RPC): bool %{
|
||||
if(::tds_rpc) {
|
||||
connection()->zeek_analyzer()->AnalyzerConfirmation();
|
||||
zeek::BifEvent::enqueue_tds_rpc(connection()->zeek_analyzer(),
|
||||
connection()->zeek_analyzer()->Conn(),
|
||||
is_orig(),
|
||||
to_stringval(${rpc.procedure_name}),
|
||||
to_stringval(${rpc.parameters})
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function tds_sql_batch(sqlBatch: TDS_SQL_BATCH): bool %{
|
||||
if(::tds_sql_batch) {
|
||||
if (${sqlBatch.stream_header.header_type} != QUERY_NOTIFICATIONS &&
|
||||
${sqlBatch.stream_header.header_type} != TRANSACTION_DESCRIPTOR) {
|
||||
return false;
|
||||
}
|
||||
connection()->zeek_analyzer()->AnalyzerConfirmation();
|
||||
zeek::BifEvent::enqueue_tds_sql_batch(connection()->zeek_analyzer(),
|
||||
connection()->zeek_analyzer()->Conn(),
|
||||
is_orig(),
|
||||
${sqlBatch.stream_header.header_type},
|
||||
to_stringval(${sqlBatch.query})
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
refine typeattr TDS += &let {
|
||||
tds: bool = $context.flow.tds(this);
|
||||
};
|
||||
|
||||
refine typeattr TDS_RPC += &let {
|
||||
tds_rpc: bool = $context.flow.tds_rpc(this);
|
||||
};
|
||||
|
||||
refine typeattr TDS_SQL_BATCH += &let {
|
||||
tds_sql_batch: bool = $context.flow.tds_sql_batch(this);
|
||||
};
|
||||
92
src/tds-protocol.pac
Normal file
92
src/tds-protocol.pac
Normal file
@ -0,0 +1,92 @@
|
||||
## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
## SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#
|
||||
# Binpac for Microsoft TDS analyser.
|
||||
# More information from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/b46a581a-39de-4745-b076-ec4dbb7d13ec
|
||||
#
|
||||
|
||||
##############################
|
||||
# CONSTANTS #
|
||||
##############################
|
||||
|
||||
enum cmd_codes {
|
||||
SQL_BATCH = 0x01,
|
||||
PRE_TDS7_LOGIN = 0x02,
|
||||
REMOTE_PROCEDURE_CALL = 0x03,
|
||||
RESPONSE = 0x04,
|
||||
UNUSED = 0x05,
|
||||
ATTENTION_REQUEST = 0x06,
|
||||
BULK_LOAD_DATA = 0x07,
|
||||
TRANSACTION_MANAGER = 0x0e,
|
||||
TDS5_QUERY = 0x0F,
|
||||
TDS7_LOGIN = 0x10,
|
||||
SSPI_MESSAGE = 0x11,
|
||||
TDS7_PRELOGIN = 0x12
|
||||
};
|
||||
|
||||
##############################
|
||||
## RECORD TYPES #
|
||||
##############################
|
||||
|
||||
## All multiple byte fields are set in little endian order
|
||||
## Packets are set in big endian order
|
||||
|
||||
type TDS_PDU(is_orig: bool) = case is_orig of {
|
||||
true -> request : TDS_Request;
|
||||
false -> response : TDS_Response;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
# switch for the request portion
|
||||
type TDS_Request = record {
|
||||
header: TDS;
|
||||
data: case(header.command) of {
|
||||
REMOTE_PROCEDURE_CALL -> remoteProcedureCall : TDS_RPC;
|
||||
SQL_BATCH -> sqlBatch : TDS_SQL_BATCH;
|
||||
default -> unknown : bytestring &restofdata;
|
||||
};
|
||||
} &byteorder=bigendian;
|
||||
|
||||
# switch for the response portion
|
||||
type TDS_Response = record {
|
||||
header: TDS;
|
||||
data: case(header.command) of {
|
||||
RESPONSE -> response : TDS_RESPONSE;
|
||||
##! SQL_BATCH -> sqlBatch : TDS_SQL_BATCH;
|
||||
default -> unknown : bytestring &restofdata;
|
||||
};
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type TDS = record {
|
||||
command : uint8;
|
||||
status : uint8;
|
||||
len : uint16;
|
||||
channel : uint16;
|
||||
packet_number : uint8;
|
||||
window : uint8;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type TDS_RPC = record {
|
||||
stream_header : Stream_Header;
|
||||
name_len : uint16 &byteorder=littleendian;
|
||||
procedure_name : bytestring &length=name_len*2;
|
||||
option_flags : uint16 &byteorder=littleendian;
|
||||
parameters : bytestring &restofdata;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type TDS_SQL_BATCH = record {
|
||||
stream_header : Stream_Header;
|
||||
query : bytestring &restofdata;
|
||||
} &byteorder=bigendian;
|
||||
|
||||
type Stream_Header = record {
|
||||
total_len : uint32;
|
||||
header_len : uint32;
|
||||
header_type : uint16;
|
||||
descriptor : uint64;
|
||||
request_count : uint32;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
type TDS_RESPONSE = record {
|
||||
tokens : bytestring &restofdata;
|
||||
} &byteorder=bigendian;
|
||||
14
src/tds.pac
Normal file
14
src/tds.pac
Normal file
@ -0,0 +1,14 @@
|
||||
%include zeek/binpac.pac
|
||||
%include zeek/zeek.pac
|
||||
|
||||
%extern{
|
||||
#include "events.bif.h"
|
||||
%}
|
||||
|
||||
analyzer TDS withcontext {
|
||||
connection: TDS_Conn;
|
||||
flow: TDS_Flow;
|
||||
};
|
||||
|
||||
%include tds-protocol.pac
|
||||
%include tds-analyzer.pac
|
||||
Loading…
x
Reference in New Issue
Block a user