├── .github └── PULL_REQUEST_TEMPLATE.md ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── configure ├── configure.plugin ├── scripts └── TDS │ ├── __load__.zeek │ ├── consts.zeek │ └── main.zeek ├── src ├── Plugin.cc ├── Plugin.h ├── TDS.cc ├── TDS.h ├── events.bif ├── tds-analyzer.pac ├── tds-protocol.pac └── tds.pac └── zkg.meta /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.15 FATAL_ERROR) 3 | 4 | project(Plugin) 5 | 6 | include(ZeekPlugin) 7 | 8 | zeek_plugin_begin(Zeek TDS) 9 | zeek_plugin_cc(src/TDS.cc src/Plugin.cc) 10 | zeek_plugin_bif(src/events.bif) 11 | zeek_plugin_pac(src/tds.pac src/tds-analyzer.pac src/tds-protocol.pac) 12 | zeek_plugin_dist_files(README CHANGES COPYING VERSION) 13 | zeek_plugin_end() 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | 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 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 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. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | 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. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | 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. 55 | 56 | 57 | ## Licensing 58 | 59 | 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. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/amazonlinux/amazonlinux:latest 2 | MAINTAINER https://github.com/amzn/ 3 | 4 | # Metadata 5 | LABEL program=zeek 6 | 7 | # Specify program 8 | ENV PROG zeek 9 | # Specify source extension 10 | ENV EXT tar.gz 11 | # Specify Zeek version to download and install (e.g. 3.0.0) 12 | ENV VERS 3.2.4 13 | 14 | # Specify Cmake version 15 | ENV CMAKEVERSMAIN 3.10 16 | ENV CMAKEVERSSUB .0 17 | 18 | # Install directory 19 | ENV PREFIX /opt/zeek 20 | # Path should include prefix 21 | ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PREFIX/bin 22 | 23 | # Install dependencies 24 | RUN yum -y update 25 | 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 26 | 27 | # Zeek 3.1.0 needs Cmake 3.0 or higher 28 | WORKDIR /tmp 29 | RUN wget https://cmake.org/files/v$CMAKEVERSMAIN/cmake-$CMAKEVERSMAIN$CMAKEVERSSUB.tar.gz 30 | RUN tar -xvzf cmake-$CMAKEVERSMAIN$CMAKEVERSSUB.tar.gz 31 | WORKDIR /tmp/cmake-$CMAKEVERSMAIN$CMAKEVERSSUB 32 | RUN /tmp/cmake-$CMAKEVERSMAIN$CMAKEVERSSUB/bootstrap 33 | RUN make -j$((`nproc`-1)) 34 | RUN make install 35 | 36 | # Compile and install Zeek 37 | WORKDIR /tmp 38 | RUN wget https://old.zeek.org/downloads/$PROG-$VERS.$EXT && tar -xzf $PROG-$VERS.$EXT 39 | WORKDIR /tmp/$PROG-$VERS 40 | RUN ./configure --build-type=RelWithDebInfo --prefix=$PREFIX --disable-python 41 | RUN make -j$((`nproc`-1)) 42 | RUN make install 43 | 44 | USER root 45 | RUN pip3 install zkg 46 | RUN zkg autoconfig 47 | COPY [--chown=bro:bro] . /tmp/zeek-plugin-tds 48 | WORKDIR /tmp/zeek-plugin-tds 49 | RUN zkg install --force . 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | * Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | * Neither the name of the copyright holder nor the 11 | names of its contributors may be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 18 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Convenience Makefile providing a few common top-level targets. 3 | # 4 | 5 | cmake_build_dir=build 6 | arch=`uname -s | tr A-Z a-z`-`uname -m` 7 | 8 | all: build-it 9 | 10 | build-it: 11 | @test -e $(cmake_build_dir)/config.status || ./configure 12 | -@test -e $(cmake_build_dir)/CMakeCache.txt && \ 13 | test $(cmake_build_dir)/CMakeCache.txt -ot `cat $(cmake_build_dir)/CMakeCache.txt | grep ZEEK_DIST | cut -d '=' -f 2`/build/CMakeCache.txt && \ 14 | echo Updating stale CMake cache && \ 15 | touch $(cmake_build_dir)/CMakeCache.txt 16 | 17 | ( cd $(cmake_build_dir) && make ) 18 | 19 | install: 20 | ( cd $(cmake_build_dir) && make install ) 21 | 22 | clean: 23 | ( cd $(cmake_build_dir) && make clean ) 24 | 25 | distclean: 26 | rm -rf $(cmake_build_dir) 27 | 28 | test: 29 | if [ -f build/lib/Zeek-* ]; then make -C tests; else echo "Plugin not built."; fi 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Zeek Plugin TDS 2 | 3 | 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. 4 | 5 | ## Installation and Usage 6 | 7 | `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. 8 | 9 | ## Sharing and Contributing 10 | 11 | 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. 12 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.1 2 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Wrapper for viewing/setting options that the plugin's CMake 4 | # scripts will recognize. 5 | # 6 | # Don't edit this. Edit configure.plugin to add plugin-specific options. 7 | # 8 | 9 | set -e 10 | command="$0 $*" 11 | 12 | if [ -e `dirname $0`/configure.plugin ]; then 13 | # Include custom additions. 14 | . `dirname $0`/configure.plugin 15 | fi 16 | 17 | usage() { 18 | 19 | cat 1>&2 </dev/null 2>&1; then 33 | plugin_usage 1>&2 34 | fi 35 | 36 | echo 37 | 38 | exit 1 39 | } 40 | 41 | # Function to append a CMake cache entry definition to the 42 | # CMakeCacheEntries variable 43 | # $1 is the cache entry variable name 44 | # $2 is the cache entry variable type 45 | # $3 is the cache entry variable value 46 | append_cache_entry () { 47 | CMakeCacheEntries="$CMakeCacheEntries -D $1:$2=$3" 48 | } 49 | 50 | # set defaults 51 | builddir=build 52 | zeekdist="" 53 | installroot="default" 54 | CMakeCacheEntries="" 55 | 56 | while [ $# -ne 0 ]; do 57 | case "$1" in 58 | -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; 59 | *) optarg= ;; 60 | esac 61 | 62 | case "$1" in 63 | --help|-h) 64 | usage 65 | ;; 66 | 67 | --cmake=*) 68 | CMakeCommand=$optarg 69 | ;; 70 | 71 | --zeek-dist=*) 72 | zeekdist=`cd $optarg && pwd` 73 | ;; 74 | 75 | --install-root=*) 76 | installroot=$optarg 77 | ;; 78 | 79 | --with-binpac=*) 80 | append_cache_entry BinPAC_ROOT_DIR PATH $optarg 81 | binpac_root=$optarg 82 | ;; 83 | 84 | --with-broker=*) 85 | append_cache_entry BROKER_ROOT_DIR PATH $optarg 86 | broker_root=$optarg 87 | ;; 88 | 89 | --with-bifcl=*) 90 | append_cache_entry BifCl_EXE PATH $optarg 91 | ;; 92 | 93 | --enable-debug) 94 | append_cache_entry BRO_PLUGIN_ENABLE_DEBUG BOOL true 95 | ;; 96 | 97 | *) 98 | if type plugin_option >/dev/null 2>&1; then 99 | plugin_option $1 && shift && continue; 100 | fi 101 | 102 | echo "Invalid option '$1'. Try $0 --help to see available options." 103 | exit 1 104 | ;; 105 | esac 106 | shift 107 | done 108 | 109 | if [ -z "$CMakeCommand" ]; then 110 | # prefer cmake3 over "regular" cmake (cmake == cmake2 on RHEL) 111 | if command -v cmake3 >/dev/null 2>&1 ; then 112 | CMakeCommand="cmake3" 113 | elif command -v cmake >/dev/null 2>&1 ; then 114 | CMakeCommand="cmake" 115 | else 116 | echo "This package requires CMake, please install it first." 117 | echo "Then you may use this script to configure the CMake build." 118 | echo "Note: pass --cmake=PATH to use cmake in non-standard locations." 119 | exit 1; 120 | fi 121 | fi 122 | 123 | if [ -z "$zeekdist" ]; then 124 | if type zeek-config >/dev/null 2>&1; then 125 | zeek_config="zeek-config" 126 | else 127 | echo "Either 'zeek-config' must be in PATH or '--zeek-dist=' used" 128 | exit 1 129 | fi 130 | 131 | append_cache_entry BRO_CONFIG_PREFIX PATH `${zeek_config} --prefix` 132 | append_cache_entry BRO_CONFIG_INCLUDE_DIR PATH `${zeek_config} --include_dir` 133 | append_cache_entry BRO_CONFIG_PLUGIN_DIR PATH `${zeek_config} --plugin_dir` 134 | append_cache_entry BRO_CONFIG_CMAKE_DIR PATH `${zeek_config} --cmake_dir` 135 | append_cache_entry CMAKE_MODULE_PATH PATH `${zeek_config} --cmake_dir` 136 | 137 | build_type=`${zeek_config} --build_type` 138 | 139 | if [ "$build_type" = "debug" ]; then 140 | append_cache_entry BRO_PLUGIN_ENABLE_DEBUG BOOL true 141 | fi 142 | 143 | if [ -z "$binpac_root" ]; then 144 | append_cache_entry BinPAC_ROOT_DIR PATH `${zeek_config} --binpac_root` 145 | fi 146 | 147 | if [ -z "$broker_root" ]; then 148 | append_cache_entry BROKER_ROOT_DIR PATH `${zeek_config} --broker_root` 149 | fi 150 | 151 | else 152 | if [ ! -e "$zeekdist/zeek-path-dev.in" ]; then 153 | echo "$zeekdist does not appear to be a valid Zeek source tree." 154 | exit 1 155 | fi 156 | 157 | # BRO_DIST is the canonical/historical name used by plugin CMake scripts 158 | # ZEEK_DIST doesn't serve a function at the moment, but set/provided anyway 159 | append_cache_entry BRO_DIST PATH $zeekdist 160 | append_cache_entry ZEEK_DIST PATH $zeekdist 161 | append_cache_entry CMAKE_MODULE_PATH PATH $zeekdist/cmake 162 | fi 163 | 164 | if [ "$installroot" != "default" ]; then 165 | mkdir -p $installroot 166 | append_cache_entry BRO_PLUGIN_INSTALL_ROOT PATH $installroot 167 | fi 168 | 169 | echo "Build Directory : $builddir" 170 | echo "Zeek Source Directory : $zeekdist" 171 | 172 | mkdir -p $builddir 173 | cd $builddir 174 | 175 | "$CMakeCommand" $CMakeCacheEntries .. 176 | 177 | echo "# This is the command used to configure this build" > config.status 178 | echo $command >> config.status 179 | chmod u+x config.status 180 | -------------------------------------------------------------------------------- /configure.plugin: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Hooks to add custom options to the configure script. 4 | # 5 | 6 | plugin_usage() 7 | { 8 | : # Do nothing 9 | # cat < 0) { 115 | local params: string_vec; 116 | local params_index: count=0; 117 | local param_index: count=0; 118 | local param_name: string=""; 119 | local param_type: count=0; 120 | local param_data: string; 121 | local param_len: count=0; 122 | while (param_index < params_size) { 123 | param_len = bytestring_to_count(parameters[param_index])*2; 124 | param_index += 1; 125 | param_name = subst_string(parameters[param_index: param_index+param_len], "\x00", ""); 126 | param_index += param_len; 127 | param_index += 1; ##! status 128 | param_type = bytestring_to_count(parameters[param_index]); 129 | param_index += 1; 130 | param_data = ""; 131 | switch (param_type) { 132 | case 0x24, ##! GUID 133 | 0x26, ##! int 134 | 0x68, ##! bit 135 | 0x6d, ##! float 136 | 0x6f: ##! DateTime 137 | param_index += 1; ##! max length 138 | param_len = bytestring_to_count(parameters[param_index]); 139 | param_index += 1; 140 | switch (param_type) { 141 | case 0x24: ##! GUID 142 | param_data = bytestring_to_hexstr(parameters[param_index+3]); 143 | param_data += bytestring_to_hexstr(parameters[param_index+2]); 144 | param_data += bytestring_to_hexstr(parameters[param_index+1]); 145 | param_data += bytestring_to_hexstr(parameters[param_index]); 146 | param_data += "-"; 147 | param_data += bytestring_to_hexstr(parameters[param_index+5]); 148 | param_data += bytestring_to_hexstr(parameters[param_index+4]); 149 | param_data += "-"; 150 | param_data += bytestring_to_hexstr(parameters[param_index+7]); 151 | param_data += bytestring_to_hexstr(parameters[param_index+6]); 152 | param_data += "-"; 153 | param_data += bytestring_to_hexstr(parameters[param_index+8:param_index+10]); 154 | param_data += "-"; 155 | param_data += bytestring_to_hexstr(parameters[param_index+10:param_index+param_len]); 156 | break; 157 | case 0x68: ##! bit 158 | if (bytestring_to_count(parameters[param_index]) == 1) { 159 | param_data = "True"; 160 | } 161 | else { 162 | param_data = "False"; 163 | } 164 | break; 165 | case 0x6d: ##! float 166 | param_data = fmt("%f", bytestring_to_double(parameters[param_index:param_index+param_len])); 167 | break; 168 | default: 169 | if (param_index >= params_size) { 170 | break; 171 | } 172 | param_data = fmt("%d", bytestring_to_count(parameters[param_index:param_index+param_len], T)); 173 | break; 174 | } 175 | param_index += param_len; 176 | params[params_index] = fmt("%s=%s", param_name, param_data); 177 | params_index += 1; 178 | break; 179 | case 0xa7, ##! VarChar 180 | 0xe7: ##! NVarChar 181 | param_index += 2; ##! max length 182 | param_index += 5; ##! collation 183 | param_len = bytestring_to_count(parameters[param_index:param_index+2], T); 184 | param_index += 2; 185 | ##! NULL is 65535 186 | if (param_len > 0 && param_len < 65535) { 187 | param_data = subst_string(parameters[param_index:param_index+param_len], "\x00", ""); 188 | param_index += param_len; 189 | } 190 | params[params_index] = fmt("%s=%s", param_name, param_data); 191 | params_index += 1; 192 | break; 193 | } 194 | } 195 | 196 | c$tds_rpc$parameters = params; 197 | } 198 | 199 | Log::write(Log_TDS_RPC, c$tds_rpc); 200 | delete c$tds_rpc; 201 | } 202 | 203 | event tds_sql_batch(c: connection, is_orig: bool, 204 | header_type: count, 205 | query: string) { 206 | if(!c?$tds_sql_batch) { 207 | c$tds_sql_batch = [$ts=network_time(), $uid=c$uid, $id=c$id]; 208 | } 209 | 210 | c$tds_sql_batch$ts = network_time(); 211 | c$tds_sql_batch$header_type = header_types[header_type]; 212 | query = subst_string(query, "\x00", ""); 213 | c$tds_sql_batch$query = query; 214 | 215 | Log::write(Log_TDS_SQL_Batch, c$tds_sql_batch); 216 | delete c$tds_sql_batch; 217 | } 218 | 219 | event connection_state_remove(c: connection) &priority=-5 { 220 | if(c?$tds) { 221 | delete c$tds; 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/Plugin.cc: -------------------------------------------------------------------------------- 1 | #include "Plugin.h" 2 | #include "zeek/analyzer/Component.h" 3 | 4 | namespace plugin { 5 | namespace Zeek_TDS { 6 | Plugin plugin; 7 | } 8 | } 9 | 10 | using namespace plugin::Zeek_TDS; 11 | 12 | zeek::plugin::Configuration Plugin::Configure() { 13 | AddComponent(new zeek::analyzer::Component("TDS", analyzer::tds::TDS_Analyzer::Instantiate)); 14 | 15 | zeek::plugin::Configuration config; 16 | config.name = "Zeek::TDS"; 17 | config.description = "MS-SQL TDS protocol analyzer"; 18 | return config; 19 | } 20 | -------------------------------------------------------------------------------- /src/Plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEEK_PLUGIN_ZEEK_TDS 2 | #define ZEEK_PLUGIN_ZEEK_TDS 3 | 4 | #include 5 | #include "TDS.h" 6 | 7 | namespace plugin { 8 | namespace Zeek_TDS { 9 | class Plugin : public zeek::plugin::Plugin { 10 | protected: 11 | // Overridden from plugin::Plugin. 12 | virtual zeek::plugin::Configuration Configure(); 13 | }; 14 | 15 | extern Plugin plugin; 16 | } 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/TDS.cc: -------------------------------------------------------------------------------- 1 | #include "TDS.h" 2 | #include 3 | #include 4 | #include "events.bif.h" 5 | 6 | using namespace analyzer::tds; 7 | 8 | TDS_Analyzer::TDS_Analyzer(zeek::Connection* c): zeek::analyzer::tcp::TCP_ApplicationAnalyzer("TDS", c) { 9 | interp = new binpac::TDS::TDS_Conn(this); 10 | had_gap = false; 11 | } 12 | 13 | TDS_Analyzer::~TDS_Analyzer() { 14 | delete interp; 15 | } 16 | 17 | void TDS_Analyzer::Done() { 18 | zeek::analyzer::tcp::TCP_ApplicationAnalyzer::Done(); 19 | interp->FlowEOF(true); 20 | interp->FlowEOF(false); 21 | } 22 | 23 | void TDS_Analyzer::EndpointEOF(bool is_orig) { 24 | zeek::analyzer::tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig); 25 | interp->FlowEOF(is_orig); 26 | } 27 | 28 | void TDS_Analyzer::DeliverStream(int len, const u_char* data, bool orig) { 29 | zeek::analyzer::tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig); 30 | assert(TCP()); 31 | //if(TCP()->IsPartial()) 32 | // return; 33 | // If only one side had a content gap, we could still try to 34 | // deliver data to the other side if the script layer can handle this. 35 | if(had_gap) 36 | return; 37 | 38 | try { 39 | interp->NewData(orig, data, data + len); 40 | } 41 | catch(const binpac::Exception& e) { 42 | AnalyzerViolation(zeek::util::fmt("Binpac exception: %s", e.c_msg())); 43 | } 44 | } 45 | 46 | void TDS_Analyzer::Undelivered(uint64_t seq, int len, bool orig) { 47 | zeek::analyzer::tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); 48 | had_gap = true; 49 | interp->NewGap(orig, len); 50 | } 51 | -------------------------------------------------------------------------------- /src/TDS.h: -------------------------------------------------------------------------------- 1 | #ifndef ANALYZER_PROTOCOL_TDS_H 2 | #define ANALYZER_PROTOCOL_TDS_H 3 | 4 | #include 5 | #include "tds_pac.h" 6 | 7 | namespace analyzer { 8 | namespace tds { 9 | class TDS_Analyzer : public zeek::analyzer::tcp::TCP_ApplicationAnalyzer { 10 | public: 11 | TDS_Analyzer(zeek::Connection* conn); 12 | virtual ~TDS_Analyzer(); 13 | 14 | virtual void Done(); 15 | virtual void DeliverStream(int len, const u_char* data, bool orig); 16 | virtual void Undelivered(uint64_t seq, int len, bool orig); 17 | 18 | virtual void EndpointEOF(bool is_orig); 19 | 20 | static zeek::analyzer::Analyzer* Instantiate(zeek::Connection* conn) { 21 | return new TDS_Analyzer(conn); 22 | } 23 | 24 | protected: 25 | binpac::TDS::TDS_Conn* interp; 26 | bool had_gap; 27 | }; 28 | } 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/events.bif: -------------------------------------------------------------------------------- 1 | ## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | ## SPDX-License-Identifier: BSD-3-Clause 3 | 4 | ###################################### 5 | ## Generated for all the TDS headers # 6 | ###################################### 7 | ## c: The connection the TDS communication is part of. 8 | ## is_orig: True if this reflects originator-side activity. 9 | ## command: uint16 of either request/response 10 | ## index: index# of the packet. 11 | ## 12 | event tds%(c: connection, is_orig: bool, 13 | command: count 14 | %); 15 | 16 | ############################################ 17 | ## Generated for the remote procedure call # 18 | ############################################ 19 | ## c: The connection the TDS communication is part of. 20 | ## is_orig: True if this reflects originator-side activity. 21 | ## product_name: product name. 22 | ## serial_number: serial number. 23 | ## 24 | event tds_rpc%(c: connection, is_orig: bool, 25 | procedure_name: string, 26 | parameters: string 27 | %); 28 | 29 | #################################### 30 | ## Generated for the identity info # 31 | #################################### 32 | ## c: The connection the TDS communication is part of. 33 | ## is_orig: True if this reflects originator-side activity. 34 | ## product_name: product name. 35 | ## serial_number: serial number. 36 | ## 37 | event tds_sql_batch%(c: connection, is_orig: bool, 38 | header_type: count, 39 | query: string 40 | %); 41 | -------------------------------------------------------------------------------- /src/tds-analyzer.pac: -------------------------------------------------------------------------------- 1 | ## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | ## SPDX-License-Identifier: BSD-3-Clause 3 | 4 | connection TDS_Conn(zeek_analyzer: ZeekAnalyzer) { 5 | upflow = TDS_Flow(true); 6 | downflow = TDS_Flow(false); 7 | }; 8 | 9 | %header{ 10 | #define SQL_BATCH 0x01 11 | #define PRE_TDS7_LOGIN 0x02 12 | #define REMOTE_PROCEDURE_CALL 0x03 13 | #define RESPONSE 0x04 14 | #define UNUSED 0x05 15 | #define ATTENTION_REQUEST 0x06 16 | #define BULK_LOAD_DATA 0x07 17 | #define TRANSACTION_MANAGER 0x0e 18 | #define TDS5_QUERY 0x0F 19 | #define TDS7_LOGIN 0x10 20 | #define SSPI_MESSAGE 0x11 21 | #define TDS7_PRELOGIN 0x12 22 | 23 | #define QUERY_NOTIFICATIONS 0x0001 24 | #define TRANSACTION_DESCRIPTOR 0x0002 25 | %} 26 | 27 | flow TDS_Flow(is_orig: bool) { 28 | # flowunit ? 29 | datagram = TDS_PDU(is_orig) withcontext(connection, this); 30 | 31 | function tds(header: TDS): bool %{ 32 | if(::tds) { 33 | if (${header.command} != SQL_BATCH && 34 | ${header.command} != PRE_TDS7_LOGIN && 35 | ${header.command} != REMOTE_PROCEDURE_CALL && 36 | ${header.command} != RESPONSE && 37 | ${header.command} != UNUSED && 38 | ${header.command} != ATTENTION_REQUEST && 39 | ${header.command} != BULK_LOAD_DATA && 40 | ${header.command} != TRANSACTION_MANAGER && 41 | ${header.command} != TDS5_QUERY && 42 | ${header.command} != TDS7_LOGIN && 43 | ${header.command} != SSPI_MESSAGE && 44 | ${header.command} != TDS7_PRELOGIN) { 45 | return false; 46 | } 47 | connection()->zeek_analyzer()->AnalyzerConfirmation(); 48 | zeek::BifEvent::enqueue_tds(connection()->zeek_analyzer(), 49 | connection()->zeek_analyzer()->Conn(), 50 | is_orig(), 51 | ${header.command} 52 | ); 53 | } 54 | 55 | return true; 56 | %} 57 | 58 | function tds_rpc(rpc: TDS_RPC): bool %{ 59 | if(::tds_rpc) { 60 | connection()->zeek_analyzer()->AnalyzerConfirmation(); 61 | zeek::BifEvent::enqueue_tds_rpc(connection()->zeek_analyzer(), 62 | connection()->zeek_analyzer()->Conn(), 63 | is_orig(), 64 | to_stringval(${rpc.procedure_name}), 65 | to_stringval(${rpc.parameters}) 66 | ); 67 | } 68 | 69 | return true; 70 | %} 71 | 72 | function tds_sql_batch(sqlBatch: TDS_SQL_BATCH): bool %{ 73 | if(::tds_sql_batch) { 74 | if (${sqlBatch.stream_header.header_type} != QUERY_NOTIFICATIONS && 75 | ${sqlBatch.stream_header.header_type} != TRANSACTION_DESCRIPTOR) { 76 | return false; 77 | } 78 | connection()->zeek_analyzer()->AnalyzerConfirmation(); 79 | zeek::BifEvent::enqueue_tds_sql_batch(connection()->zeek_analyzer(), 80 | connection()->zeek_analyzer()->Conn(), 81 | is_orig(), 82 | ${sqlBatch.stream_header.header_type}, 83 | to_stringval(${sqlBatch.query}) 84 | ); 85 | } 86 | 87 | return true; 88 | %} 89 | }; 90 | 91 | refine typeattr TDS += &let { 92 | tds: bool = $context.flow.tds(this); 93 | }; 94 | 95 | refine typeattr TDS_RPC += &let { 96 | tds_rpc: bool = $context.flow.tds_rpc(this); 97 | }; 98 | 99 | refine typeattr TDS_SQL_BATCH += &let { 100 | tds_sql_batch: bool = $context.flow.tds_sql_batch(this); 101 | }; 102 | -------------------------------------------------------------------------------- /src/tds-protocol.pac: -------------------------------------------------------------------------------- 1 | ## Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | ## SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # 5 | # Binpac for Microsoft TDS analyser. 6 | # More information from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/b46a581a-39de-4745-b076-ec4dbb7d13ec 7 | # 8 | 9 | ############################## 10 | # CONSTANTS # 11 | ############################## 12 | 13 | enum cmd_codes { 14 | SQL_BATCH = 0x01, 15 | PRE_TDS7_LOGIN = 0x02, 16 | REMOTE_PROCEDURE_CALL = 0x03, 17 | RESPONSE = 0x04, 18 | UNUSED = 0x05, 19 | ATTENTION_REQUEST = 0x06, 20 | BULK_LOAD_DATA = 0x07, 21 | TRANSACTION_MANAGER = 0x0e, 22 | TDS5_QUERY = 0x0F, 23 | TDS7_LOGIN = 0x10, 24 | SSPI_MESSAGE = 0x11, 25 | TDS7_PRELOGIN = 0x12 26 | }; 27 | 28 | ############################## 29 | ## RECORD TYPES # 30 | ############################## 31 | 32 | ## All multiple byte fields are set in little endian order 33 | ## Packets are set in big endian order 34 | 35 | type TDS_PDU(is_orig: bool) = case is_orig of { 36 | true -> request : TDS_Request; 37 | false -> response : TDS_Response; 38 | } &byteorder=bigendian; 39 | 40 | # switch for the request portion 41 | type TDS_Request = record { 42 | header: TDS; 43 | data: case(header.command) of { 44 | REMOTE_PROCEDURE_CALL -> remoteProcedureCall : TDS_RPC; 45 | SQL_BATCH -> sqlBatch : TDS_SQL_BATCH; 46 | default -> unknown : bytestring &restofdata; 47 | }; 48 | } &byteorder=bigendian; 49 | 50 | # switch for the response portion 51 | type TDS_Response = record { 52 | header: TDS; 53 | data: case(header.command) of { 54 | RESPONSE -> response : TDS_RESPONSE; 55 | ##! SQL_BATCH -> sqlBatch : TDS_SQL_BATCH; 56 | default -> unknown : bytestring &restofdata; 57 | }; 58 | } &byteorder=bigendian; 59 | 60 | type TDS = record { 61 | command : uint8; 62 | status : uint8; 63 | len : uint16; 64 | channel : uint16; 65 | packet_number : uint8; 66 | window : uint8; 67 | } &byteorder=bigendian; 68 | 69 | type TDS_RPC = record { 70 | stream_header : Stream_Header; 71 | name_len : uint16 &byteorder=littleendian; 72 | procedure_name : bytestring &length=name_len*2; 73 | option_flags : uint16 &byteorder=littleendian; 74 | parameters : bytestring &restofdata; 75 | } &byteorder=bigendian; 76 | 77 | type TDS_SQL_BATCH = record { 78 | stream_header : Stream_Header; 79 | query : bytestring &restofdata; 80 | } &byteorder=bigendian; 81 | 82 | type Stream_Header = record { 83 | total_len : uint32; 84 | header_len : uint32; 85 | header_type : uint16; 86 | descriptor : uint64; 87 | request_count : uint32; 88 | } &byteorder=littleendian; 89 | 90 | type TDS_RESPONSE = record { 91 | tokens : bytestring &restofdata; 92 | } &byteorder=bigendian; 93 | -------------------------------------------------------------------------------- /src/tds.pac: -------------------------------------------------------------------------------- 1 | %include zeek/binpac.pac 2 | %include zeek/zeek.pac 3 | 4 | %extern{ 5 | #include "events.bif.h" 6 | %} 7 | 8 | analyzer TDS withcontext { 9 | connection: TDS_Conn; 10 | flow: TDS_Flow; 11 | }; 12 | 13 | %include tds-protocol.pac 14 | %include tds-analyzer.pac 15 | -------------------------------------------------------------------------------- /zkg.meta: -------------------------------------------------------------------------------- 1 | [package] 2 | script_dir = scripts/TDS 3 | build_command = ./configure && make 4 | tags = zeek plugin, protocol analyzer, log writer, tds 5 | description = Plugin that enables parsing of the Tabular Data Stream (TDS) protocol 6 | depends = 7 | zkg >=2.0 8 | zeek >=3.0.0 9 | 10 | --------------------------------------------------------------------------------