diff options
Diffstat (limited to 'framework/src/suricata/scripts')
8 files changed, 605 insertions, 0 deletions
diff --git a/framework/src/suricata/scripts/Makefile.am b/framework/src/suricata/scripts/Makefile.am new file mode 100644 index 00000000..96bd2221 --- /dev/null +++ b/framework/src/suricata/scripts/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=suricatasc diff --git a/framework/src/suricata/scripts/setup_decoder.sh b/framework/src/suricata/scripts/setup_decoder.sh new file mode 100644 index 00000000..9af4104e --- /dev/null +++ b/framework/src/suricata/scripts/setup_decoder.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Script to setup a new decoder. +# Written by Victor Julien <victor@inliniac.net> +# + +set -e +#set -x + +function Usage { + echo + echo "$(basename $0) -- script to provision a decoder. The script" + echo "makes a copy of the decode-template, sets the name and updates" + echo " the build system." + echo + echo "Call from the 'src' directory, with one argument: the decoder name." + echo + echo "E.g. inside 'src': ../scripts/$(basename $0) ipv7" + echo +} + +function Done { + echo + echo "Decoder $NR has been set up in $FILE_C and $FILE_H and the" + echo "build system has been updated." + echo + echo "The decoder should now compile cleanly. Try running 'make'." + echo + echo "Next steps are to edit the files to implement the actual" + echo "decoding of $NR." + echo +} + +if [ $# -ne "1" ]; then + Usage + echo "ERROR: call with one argument" + exit 1 +fi + +INPUT=$1 +# lowercase +LC=${INPUT,,} +#echo $LC +# UPPERCASE +UC=${LC^^} +#echo $UC +# Normal +NR=${LC^} +#echo $NR + +FILE_C="decode-${LC}.c" +FILE_H="decode-${LC}.h" +#echo $FILE_C +#echo $FILE_H + +if [ ! -e ../configure.ac ] || [ ! -e Makefile.am ]; then + Usage + echo "ERROR: call from src/ directory" + exit 1 +fi +if [ ! -e decode-template.c ] || [ ! -e decode-template.h ]; then + Usage + echo "ERROR: input files decode-template.c and/or decode-template.h are missing" + exit 1 +fi +if [ -e $FILE_C ] || [ -e $FILE_H ]; then + Usage + echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" + exit 1 +fi + +cp decode-template.c $FILE_C +cp decode-template.h $FILE_H + +# search and replaces +sed -i "s/TEMPLATE/${UC}/g" $FILE_C +sed -i "s/TEMPLATE/${UC}/g" $FILE_H +sed -i "s/Template/${NR}/g" $FILE_C +sed -i "s/Template/${NR}/g" $FILE_H +sed -i "s/template/${LC}/g" $FILE_C +sed -i "s/template/${LC}/g" $FILE_H +sed -i "s/decode-template.c decode-template.h \\\/decode-template.c decode-template.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am + +Done +exit 0 diff --git a/framework/src/suricata/scripts/setup_simple_detect.sh b/framework/src/suricata/scripts/setup_simple_detect.sh new file mode 100644 index 00000000..309b47cc --- /dev/null +++ b/framework/src/suricata/scripts/setup_simple_detect.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# +# Script to setup a new 'simple' detect module. +# Written by Victor Julien <victor@inliniac.net> +# + +set -e +#set -x + +function Usage { + echo + echo "$(basename $0) -- script to provision a detect module. The script" + echo "makes a copy of detect-template, sets the name and updates" + echo "the build system." + echo + echo "Call from the 'src' directory, with one argument: the detect module" + echo "name." + echo + echo "E.g. inside 'src': ../scripts/$(basename $0) helloworld" + echo +} + +function Done { + echo + echo "Detect module $NR has been set up in $FILE_C and $FILE_H" + echo "and the build system has been updated." + echo + echo "The detect module should now compile cleanly. Try running 'make'." + echo + echo "Next steps are to edit the files to implement the actual" + echo "detection logic of $NR." + echo +} + +if [ $# -ne "1" ]; then + Usage + echo "ERROR: call with one argument" + exit 1 +fi + +INPUT=$1 +# lowercase +LC=${INPUT,,} +#echo $LC +# UPPERCASE +UC=${LC^^} +#echo $UC +# Normal +NR=${LC^} +#echo $NR + +FILE_C="detect-${LC}.c" +FILE_H="detect-${LC}.h" +#echo $FILE_C +#echo $FILE_H + +if [ ! -e ../configure.ac ] || [ ! -e Makefile.am ]; then + Usage + echo "ERROR: call from src/ directory" + exit 1 +fi +if [ ! -e detect-template.c ] || [ ! -e detect-template.h ]; then + Usage + echo "ERROR: input files detect-template.c and/or detect-template.h are missing" + exit 1 +fi +if [ -e $FILE_C ] || [ -e $FILE_H ]; then + Usage + echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" + exit 1 +fi + +cp detect-template.c $FILE_C +cp detect-template.h $FILE_H + +# search and replaces +sed -i "s/TEMPLATE/${UC}/g" $FILE_C +sed -i "s/TEMPLATE/${UC}/g" $FILE_H +sed -i "s/Template/${NR}/g" $FILE_C +sed -i "s/Template/${NR}/g" $FILE_H +sed -i "s/template/${LC}/g" $FILE_C +sed -i "s/template/${LC}/g" $FILE_H +# add to Makefile.am +sed -i "s/detect-template.c detect-template.h \\\/detect-template.c detect-template.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am +# update enum +sed -i "s/DETECT_TEMPLATE,/DETECT_TEMPLATE,\\n DETECT_${UC},/g" detect.h +# add include to detect.c +sed -i "s/#include \"detect-template.h\"/#include \"detect-template.h\"\\n#include \"${FILE_H}\"/g" detect.c +# add reg func to detect.c +sed -i "s/DetectTemplateRegister();/DetectTemplateRegister();\\n Detect${NR}Register();/g" detect.c + +Done +exit 0 diff --git a/framework/src/suricata/scripts/suricatasc/Makefile.am b/framework/src/suricata/scripts/suricatasc/Makefile.am new file mode 100644 index 00000000..63989347 --- /dev/null +++ b/framework/src/suricata/scripts/suricatasc/Makefile.am @@ -0,0 +1,19 @@ +EXTRA_DIST = setup.py suricatasc.in src/__init__.py src/suricatasc.py + +if HAVE_PYTHON +all-local: + mkdir -p $(top_builddir)/scripts/suricatasc/src + $(PYTHON) $(srcdir)/setup.py build; + +install-exec-local: + $(PYTHON) $(srcdir)/setup.py install --prefix $(DESTDIR)$(prefix) + +clean-local: + $(PYTHON) $(srcdir)/setup.py clean; + rm -rf $(top_builddir)/scripts/suricatasc/build + +uninstall-local: + [ ! -f "$(DESTDIR)$(prefix)/bin/suricatasc" ] || rm -f "$(DESTDIR)$(prefix)/bin/suricatasc" + find "$(DESTDIR)$(prefix)/lib" -name "suricatasc-*.egg-info" -delete ||true + +endif diff --git a/framework/src/suricata/scripts/suricatasc/setup.py b/framework/src/suricata/scripts/suricatasc/setup.py new file mode 100755 index 00000000..2d37919b --- /dev/null +++ b/framework/src/suricata/scripts/suricatasc/setup.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +from distutils.core import setup + +SURICATASC_VERSION = "0.9" + +setup(name='suricatasc', + version=SURICATASC_VERSION, + description='Suricata unix socket client', + author='Eric Leblond', + author_email='eric@regit.org', + url='https://www.suricata-ids.org/', + scripts=['suricatasc'], + packages=['suricatasc'], + package_dir={'suricatasc':'src'}, + provides=['suricatasc'], + requires=['argparse','simplejson'], + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Operating System :: POSIX', + 'Programming Language :: Python', + 'Topic :: System :: Systems Administration', + ], + ) diff --git a/framework/src/suricata/scripts/suricatasc/src/__init__.py b/framework/src/suricata/scripts/suricatasc/src/__init__.py new file mode 100644 index 00000000..1a61f426 --- /dev/null +++ b/framework/src/suricata/scripts/suricatasc/src/__init__.py @@ -0,0 +1,2 @@ + +from suricatasc import * diff --git a/framework/src/suricata/scripts/suricatasc/src/suricatasc.py b/framework/src/suricata/scripts/suricatasc/src/suricatasc.py new file mode 100644 index 00000000..1a776a29 --- /dev/null +++ b/framework/src/suricata/scripts/suricatasc/src/suricatasc.py @@ -0,0 +1,314 @@ +#!/usr/bin/python +# Copyright(C) 2012 Open Information Security Foundation + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +try: + import simplejson as json +except: + import json +import re +import readline +from socket import socket, AF_UNIX, error +from time import sleep +import select +import sys + +SURICATASC_VERSION = "0.9" + +VERSION = "0.1" +SIZE = 4096 + +class SuricataException(Exception): + """ + Generic class for suricatasc exception + """ + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + +class SuricataNetException(SuricataException): + """ + Exception raised when network error occur. + """ + pass + +class SuricataCommandException(SuricataException): + """ + Exception raised when command is not correct. + """ + pass + +class SuricataReturnException(SuricataException): + """ + Exception raised when return message is not correct. + """ + pass + + +class SuricataCompleter: + def __init__(self, words): + self.words = words + self.generator = None + + def complete(self, text): + for word in self.words: + if word.startswith(text): + yield word + + def __call__(self, text, state): + if state == 0: + self.generator = self.complete(text) + try: + return next(self.generator) + except StopIteration: + return None + return None + +class SuricataSC: + def __init__(self, sck_path, verbose=False): + self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler','unregister-tenant-handler'] + self.sck_path = sck_path + self.verbose = verbose + + def json_recv(self): + cmdret = None + i = 0 + data = "" + while i < 5: + i += 1 + if sys.version < '3': + data += self.socket.recv(SIZE) + else: + data += self.socket.recv(SIZE).decode('iso-8859-1') + try: + cmdret = json.loads(data) + break + except: + sleep(0.3) + return cmdret + + def send_command(self, command, arguments = None): + if command not in self.cmd_list and command != 'command-list': + raise SuricataCommandException("No such command: %s", command) + + cmdmsg = {} + cmdmsg['command'] = command + if (arguments != None): + cmdmsg['arguments'] = arguments + if self.verbose: + print("SND: " + json.dumps(cmdmsg)) + if sys.version < '3': + self.socket.send(json.dumps(cmdmsg)) + else: + self.socket.send(bytes(json.dumps(cmdmsg), 'iso-8859-1')) + + ready = select.select([self.socket], [], [], 600) + if ready[0]: + cmdret = self.json_recv() + else: + cmdret = None + + if cmdret == None: + raise SuricataReturnException("Unable to get message from server") + + if self.verbose: + print("RCV: "+ json.dumps(cmdret)) + + return cmdret + + def connect(self): + try: + self.socket = socket(AF_UNIX) + self.socket.connect(self.sck_path) + except error as err: + raise SuricataNetException(err) + + self.socket.settimeout(10) + #send version + if self.verbose: + print("SND: " + json.dumps({"version": VERSION})) + if sys.version < '3': + self.socket.send(json.dumps({"version": VERSION})) + else: + self.socket.send(bytes(json.dumps({"version": VERSION}), 'iso-8859-1')) + + ready = select.select([self.socket], [], [], 600) + if ready[0]: + cmdret = self.json_recv() + else: + cmdret = None + + if cmdret == None: + raise SuricataReturnException("Unable to get message from server") + + if self.verbose: + print("RCV: "+ json.dumps(cmdret)) + + if cmdret["return"] == "NOK": + raise SuricataReturnException("Error: %s" % (cmdret["message"])) + + cmdret = self.send_command("command-list") + + # we silently ignore NOK as this means server is old + if cmdret["return"] == "OK": + self.cmd_list = cmdret["message"]["commands"] + self.cmd_list.append("quit") + + + def close(self): + self.socket.close() + + def parse_command(self, command): + arguments = None + if command.split(' ', 2)[0] in self.cmd_list: + if "pcap-file " in command: + try: + parts = command.split(' '); + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, filename, output = parts[0], parts[1], parts[2] + tenant = None + if len(parts) > 3: + tenant = parts[3] + if cmd != "pcap-file": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["filename"] = filename + arguments["output-dir"] = output + if tenant != None: + arguments["tenant"] = int(tenant) + elif "iface-stat" in command: + try: + [cmd, iface] = command.split(' ', 1) + except: + raise SuricataCommandException("Unable to split command '%s'" % (command)) + if cmd != "iface-stat": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["iface"] = iface + elif "conf-get" in command: + try: + [cmd, variable] = command.split(' ', 1) + except: + raise SuricataCommandException("Unable to split command '%s'" % (command)) + if cmd != "conf-get": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["variable"] = variable + elif "unregister-tenant-handler" in command: + try: + parts = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, tenantid, htype = parts[0], parts[1], parts[2] + hargs = None + if len(parts) > 3: + hargs = parts[3] + if cmd != "unregister-tenant-handler": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["htype"] = htype + if hargs != None: + arguments["hargs"] = int(hargs) + elif "register-tenant-handler" in command: + try: + parts = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, tenantid, htype = parts[0], parts[1], parts[2] + hargs = None + if len(parts) > 3: + hargs = parts[3] + if cmd != "register-tenant-handler": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["htype"] = htype + if hargs != None: + arguments["hargs"] = int(hargs) + elif "unregister-tenant" in command: + try: + [cmd, tenantid] = command.split(' ', 1) + except: + raise SuricataCommandException("Unable to split command '%s'" % (command)) + if cmd != "unregister-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + elif "register-tenant" in command: + try: + [cmd, tenantid, filename] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "register-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["filename"] = filename + elif "reload-tenant" in command: + try: + [cmd, tenantid, filename] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "reload-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["filename"] = filename + else: + cmd = command + else: + raise SuricataCommandException("Unknown command '%s'" % (command)) + return (cmd, arguments) + + def interactive(self): + print("Command list: " + ", ".join(self.cmd_list)) + try: + readline.set_completer(SuricataCompleter(self.cmd_list)) + readline.set_completer_delims(";") + readline.parse_and_bind('tab: complete') + while True: + if sys.version < '3': + command = raw_input(">>> ").strip() + else: + command = input(">>> ").strip() + if command == "quit": + break; + try: + (cmd, arguments) = self.parse_command(command) + except SuricataCommandException as err: + print(err) + continue + cmdret = self.send_command(cmd, arguments) + #decode json message + if cmdret["return"] == "NOK": + print("Error:") + print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) + else: + print("Success:") + print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) + except KeyboardInterrupt: + print("[!] Interrupted") diff --git a/framework/src/suricata/scripts/suricatasc/suricatasc.in b/framework/src/suricata/scripts/suricatasc/suricatasc.in new file mode 100755 index 00000000..63b4ebfa --- /dev/null +++ b/framework/src/suricata/scripts/suricatasc/suricatasc.in @@ -0,0 +1,65 @@ +#!/usr/bin/python +# Copyright(C) 2013 Open Information Security Foundation + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from __future__ import print_function +import sys +import argparse +from suricatasc import * + +parser = argparse.ArgumentParser(prog='suricatasc', description='Client for Suricata unix socket') +parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output (including JSON dump)') +parser.add_argument('-c', '--command', default=None, help='execute on single command and return JSON') +parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to connnect to', default=None) +args = parser.parse_args() + +if args.socket != None: + SOCKET_PATH = args.socket +else: + SOCKET_PATH = "@e_localstatedir@/suricata-command.socket" + +sc = SuricataSC(SOCKET_PATH, verbose=args.verbose) +try: + sc.connect() +except SuricataNetException as err: + print("Unable to connect to socket %s: %s" % (SOCKET_PATH, err), file=sys.stderr) + sys.exit(1) +except SuricataReturnException as err: + print("Unable to negotiate version with server: %s" % (err), file=sys.stderr) + sys.exit(1) + +if args.command: + (command, arguments) = sc.parse_command(args.command) + res = sc.send_command(command, arguments) + print(json.dumps(res)) + sc.close() + if res['return'] == 'OK': + sys.exit(0) + else: + sys.exit(1) + +try: + sc.interactive() +except SuricataNetException as err: + print("Communication error: %s" % (err)) + sys.exit(1) +except SuricataReturnException as err: + print("Invalid return from server: %s" % (err)) + sys.exit(1) + +print("[+] Quit command client") + +sc.close() |