[PATCH] prelude plugin for specter
Maik Hentsche <[email protected]>
| Newsgroups | gmane.comp.security.ids.prelude.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi, I'm currently working on getting firewall (netfilter/iptables) logmessages into prelude. For this is wrote a plugin for specter (http://joker.linuxstuff.pl/specter/), a daemon, that handles logging through the ULOG target (as ulogd does, if anyone knows that). This plugin is not yet finished, but it reached a stable state, where I feel stuck a little. I send this patch in hope, someone will try it out and send me usefull comments. Main goal is to have specter_PRELUDE log everything syslog log (dest IP, source IP, ports, flags, ...). I'm not sure, if the classification of this data into IDMEF is appropriate in every case, so positive and negative comments on this are welcome too. ATM prewikka does not show all information it's supposed to have, I'm not nure if thats intentionally, a mistake in my prewikka configuration or my plugin. I'm still working on it. Please tell me, if you experience similar problems. A few words to installing the patch: You need specter-1.4, downloadable at the above mentioned webpage. I built it with libprelude-0.9.10, but you will need a version, that has _config_open() instead of config_open() (not the leading underscore), which, as I am told, is already in SVN. After patching specter, you need to call autoconf, since I only changed configure.ac. Call configure with --with-prelude, then do the typical make; make install. You will have to add the prelude plugin into the specter configuration and need at least one iptables rule, that logs to ULOG. I hope to hear of you, thanks to everyone, who tests my code. Maik _______________________________________________ Prelude-devel site list [email protected] http://www.prelude-ids.org/mailman/listinfo/prelude-devel
specter_prelude_configure.diff
(text/x-patch, 1.3 KB)
--- specter-1.4/configure.ac 2005-07-03 13:58:17.000000000 +0200
+++ specter-1.4.new/configure.ac 2006-07-20 14:03:41.000000000 +0200
@@ -222,6 +222,57 @@
EXTRA_PGSQL_DEF="-DIP_AS_STRING=1"
])
+dnl
+dnl test for Prelude
+dnl
+AC_ARG_WITH(prelude,
+[ --with-prelude=<directory> prelude installed in <directory>],[
+if test $withval != yes
+then
+ dir=$withval
+else
+ dir="/usr/local"
+fi
+preludedir=""
+AC_MSG_CHECKING(for prelude files)
+for d in $dir /usr /usr/local /usr/local/prelude /opt/prelude /opt/packages/prelude
+do
+ if test -f $d/lib/libprelude.so
+ then
+ AC_MSG_RESULT(found prelude in $d)
+ preludedir=$d
+ break
+ fi
+done
+
+if test x$preludedir = x
+then
+ AC_MSG_WARN(PRELUDE IDS not used - couldn't find libprelude.so)
+else
+ AC_DEFINE(HAVE_PRELUDE)
+ for i in include include/libprelude
+ do
+ if test -f ${preludedir}/$i/prelude.h
+ then
+ PRELUDEINCLUDES=${preludedir}/$i
+ break
+ fi
+ done
+ if test x$PRELUDEINCLUDES = x
+ then
+ AC_MSG_WARN(PRELUDE IDS not used - couldn't find prelude.h)
+ fi
+ PRELUDELIBS=${preludedir}/lib
+
+ PRELUDE_LIB="-L${PRELUDELIBS} -lprelude"
+
+ AC_SUBST(PRELUDEINCLUDES)
+ AC_SUBST(PRELUDE_LIB)
+
+fi
+])
+
+
specter_prelude_plugin_dir.diff
(text/x-patch, 9.6 KB)
diff -U 3 -b -B -d -i -r -N -x .svn -- specter-1.4/plugins/Makefile.in specter-1.4.new/plugins/Makefile.in
--- specter-1.4/plugins/Makefile.in 2005-07-03 13:58:17.000000000 +0200
+++ specter-1.4.new/plugins/Makefile.in 2006-09-06 08:16:08.000000000 +0200
@@ -24,6 +24,13 @@
PGSQL_CFLAGS=-I@PGSQLINCLUDES@ @EXTRA_PGSQL_DEF@
endif
+ifeq (x@PRELUDEINCLUDES@,x)
+else
+OBJECTS+=specter_PRELUDE.so
+PRELUDE_CFLAGS=-I@PRELUDEINCLUDES@
+endif
+
+
ifeq (x@HAVE_PCAP_H@,x)
else
OBJECTS+=specter_PCAP.so
@@ -66,6 +73,11 @@
$(LD) -shared -lc printpkt.o specter_SYSLOG.o -o $@
$(RM) specter_SYSLOG.o
+specter_PRELUDE.so: specter_PRELUDE.c
+ $(CC) $(CFLAGS) $(TARGET_ARCH) $(PRELUDE_CFLAGS) -c specter_PRELUDE.c -o specter_PRELUDE.o
+ $(LD) -shared -lc @PRELUDE_LIB@ specter_PRELUDE.o -o $@
+ $(RM) specter_PRELUDE.o
+
specter_LOGEMU.so: printpkt.o specter_LOGEMU.c
$(CC) $(CFLAGS) $(TARGET_ARCH) -c specter_LOGEMU.c -o specter_LOGEMU.o
$(LD) -shared -lc printpkt.o specter_LOGEMU.o -o $@
diff -U 3 -b -B -d -i -r -N -x .svn -- specter-1.4/plugins/specter_PRELUDE.c specter-1.4.new/plugins/specter_PRELUDE.c
--- specter-1.4/plugins/specter_PRELUDE.c 1970-01-01 01:00:00.000000000 +0100
+++ specter-1.4.new/plugins/specter_PRELUDE.c 2006-09-08 10:51:43.000000000 +0200
@@ -0,0 +1,269 @@
+/* specter_PRELUDE.c
+ * specter output target for logging to prelude IDS
+ * Author: Maik Hentsche
+ *
+ *
+ * based on specter_OPRINT.c
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <libprelude/prelude.h>
+#include <specter/specter.h>
+#include <conffile/conffile.h>
+#include "lret.h"
+
+
+
+#define HIPQUAD(addr) \
+ ((unsigned char *)&addr)[3], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[0]
+
+/* sorting is important */
+static config_entry_t prelude_config[] = {
+ { .key = "prelude_name", .type = CONFIG_TYPE_STRING, .options = CONFIG_OPT_NONE, .u = {.string = "specter"}},
+ { .key = "report", .type = CONFIG_TYPE_STRING, .options = CONFIG_OPT_NONE, .u = { .string = "default" }},
+ { .key = "classification_text", .type = CONFIG_TYPE_STRING, .options = CONFIG_OPT_NONE, .u = {.string = "packet hit firewall"}},
+};
+
+
+static specter_local_ret_t local_ret[] = {
+ { "*", NULL }
+};
+
+
+/* abstraction for generation of prelude messages */
+static int add_idmef_object(idmef_message_t *message, const char *object, const char *value)
+{
+ int ret;
+ idmef_value_t *val;
+ idmef_path_t *path;
+
+ ret = idmef_path_new(&path, object);
+ if ( ret < 0 )
+ return -1;
+
+ ret = idmef_value_new_from_path(&val, path, value);
+ if ( ret < 0 ) {
+ idmef_path_destroy(path);
+ return -1;
+ }
+
+ ret = idmef_path_set(path, message, val);
+
+ idmef_value_destroy(val);
+ idmef_path_destroy(path);
+
+ return ret;
+}
+
+/* set up connection to prelude-manager */
+static void *init_prelude(config_entry_t *ce)
+{
+ prelude_client_t *client;
+ int ret;
+
+
+ if (fill_local_ret(local_ret, 1) == -1)
+ return(NULL);
+
+ /* initialize prelude, always has to be the first */
+ ret = prelude_init(NULL, NULL);
+ if ( ret < 0 ) {
+ specter_log(SPECTER_FATAL, prelude_strerror(ret));
+ return(NULL);
+ }
+
+ /* create a new client */
+ ret = prelude_client_new(&client, GET_CE(ce,0)->u.string);
+ if ( (! client) || (ret < 0) ) {
+ specter_log(SPECTER_FATAL, prelude_strerror(ret));
+ return(NULL);
+ }
+
+ ret = prelude_client_start(client);
+ if ( ret < 0 ) {
+ specter_log(SPECTER_FATAL, prelude_strerror(ret));
+
+ return(NULL);
+ }
+
+
+ ret = prelude_client_set_flags(client, PRELUDE_CLIENT_FLAGS_ASYNC_SEND|PRELUDE_CLIENT_FLAGS_ASYNC_TIMER);
+ if ( ret < 0 ) {
+ specter_log(SPECTER_ERROR, prelude_strerror(ret));
+ return(NULL);
+ }
+
+
+
+ return((void * )client);
+}
+
+static void fini_prelude(config_entry_t *ce, void *data)
+{
+ prelude_client_t *client = data;
+
+ prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS);
+}
+#define PRELUDE_FLAG_NONE 0x00
+#define PRELUDE_HAS_PREFIX 0x01
+
+
+static int output_prelude(config_entry_t *ce, void *data)
+{
+ prelude_client_t *client = data;
+ unsigned int flags=PRELUDE_FLAG_NONE, i=0;
+ idmef_message_t *idmef;
+ specter_iret_t *ret;
+ char num[]="4294967296";
+ char tmpstring[]="alert.additionaldata(4294967296).meaning";
+ /* HACK: tmpstring is initialised to the biggest value ever *
+ * used, so overflows should be impossible (Note: 4294967296 *
+ * is 2^32 == uint_max). No userinput is saved in here, so *
+ * an intentionally overwrite is impossible to. Always *
+ * recheck the size if you use tmpstring for new keys. If *
+ * you doubt this, change all sprintf to snprintf. */
+
+ struct protoent *protocol;
+ struct servent *service;
+
+
+
+ if ( idmef_message_new(&idmef) < 0 ){
+ specter_log(SPECTER_ERROR,"Unable to allocate new prelude message.\n");
+ return(-1);
+ }
+
+ /* maybe it would be better to have an inline function for every *
+ * key and thus make this loop more easily to understand */
+ for (ret = local_ret[0].p; ret; ret = ret->next) {
+ if (! IS_VALID(ret))
+ continue;
+ if ( ! strcmp(ret->name,"oob.prefix")){
+ if ( strlen(ret->value.ptr) ){ /* workaround, bug reported */
+ add_idmef_object(idmef, "alert.classification.text", ret->value.ptr);
+ flags |=PRELUDE_HAS_PREFIX;
+ }
+ }
+ else if (! strcmp(ret->name,"ip.saddr") ){
+ sprintf(tmpstring, "%d",IDMEF_ADDRESS_CATEGORY_IPV4_ADDR);
+ add_idmef_object(idmef, "alert.source(0).node.Address(0).category", tmpstring);
+ sprintf(tmpstring, "%d.%d.%d.%d",HIPQUAD(ret->value.ui32));
+ add_idmef_object(idmef, "alert.source(0).node.Address(0).address", tmpstring);
+ }
+ else if (! strcmp(ret->name,"ip.daddr") ){
+ sprintf(tmpstring, "%d",IDMEF_ADDRESS_CATEGORY_IPV4_ADDR);
+ add_idmef_object(idmef, "alert.target(0).node.Address(0).category", tmpstring);
+ sprintf(tmpstring, "%d.%d.%d.%d",HIPQUAD(ret->value.ui32));
+ add_idmef_object(idmef, "alert.target(0).node.Address(0).address", tmpstring);
+ }
+ else if (! strcmp(ret->name,"ip.protocol") ){
+ protocol=getprotobynumber(ret->value.ui32);
+ add_idmef_object(idmef, "alert.source(0).service.iana_protocol_name",protocol->p_name);
+ }
+ else if (! strcmp(ret->name,"raw.mac") ){
+ sprintf(tmpstring, "%d",IDMEF_ADDRESS_CATEGORY_MAC);
+ add_idmef_object(idmef, "alert.target(0).node.Address(1).category", tmpstring);
+ add_idmef_object(idmef, "alert.target(0).node.Address(1).address",ret->value.ptr);
+ }
+ else if (! strcmp(ret->name,"oob.in") )
+ add_idmef_object(idmef, "alert.target(0).interface", ret->value.ptr);
+ else if (! strcmp(ret->name,"oob.out") )
+ add_idmef_object(idmef, "alert.source(0).interface", ret->value.ptr);
+ else if ( (! strcmp(ret->name,"tcp.sport")) || (! strcmp(ret->name,"udp.sport")) ){
+ sprintf(tmpstring, "%d",ret->value.ui16);
+ add_idmef_object(idmef, "alert.source(0).service.port", tmpstring);
+ service=getservbyport(htons(ret->value.ui16),NULL);
+ if ( service != NULL){
+ add_idmef_object(idmef, "alert.source(0).service.name", service->s_name);
+ }
+ }
+ else if ( (! strcmp(ret->name,"tcp.dport")) || (! strcmp(ret->name,"udp.dport")) ){
+ sprintf(tmpstring, "%d",ret->value.ui16);
+ add_idmef_object(idmef, "alert.target(0).service.port", tmpstring);
+ service=getservbyport(htons(ret->value.ui16),NULL);
+ if ( service != NULL){
+ add_idmef_object(idmef, "alert.target(0).service.name", service->s_name);
+ }
+ }
+ /* everything following from here is alert.additionaldata *
+ * because it does not fit anywhere else */
+ else if (! strcmp(ret->name,"ip.ttl") ){
+ sprintf(tmpstring, "alert.additionaldata(%u).type",i);
+ add_idmef_object(idmef, tmpstring, "time to live");
+ sprintf(tmpstring, "alert.additionaldata(%u).meaning",i++);
+ sprintf(num, "%d",ret->value.ui8);
+ add_idmef_object(idmef, tmpstring, num);
+ specter_log(SPECTER_DEBUG, "TTL found, i = %d",i);
+ }
+
+ }
+
+ if (! (flags & PRELUDE_HAS_PREFIX))
+ add_idmef_object(idmef, "alert.classification.text", GET_CE(ce,2)->u.string);
+
+ prelude_client_send_idmef(client, idmef);
+ idmef_message_destroy(idmef);
+
+ return 0;
+}
+
+
+/* when implemented, this function is supposed *
+ * to reread the config file, reconnect to *
+ * prelude and maybe something else */
+static int sighup_handler_prelude(config_entry_t *ce, void *data, int signal)
+{
+
+ switch (signal) {
+ case SIGHUP:
+ specter_log(SPECTER_NOTICE, "Not implemented yet\n");
+ break;
+ default:
+ break;
+ }
+ return(0);
+}
+
+static specter_output_t prelude_op = {
+ .name = "prelude",
+ .ce_base = prelude_config,
+ .ce_num = 3,
+ .init = &init_prelude,
+ .fini = &fini_prelude,
+ .output = &output_prelude,
+ .signal = &sighup_handler_prelude
+};
+
+
+void _init(void)
+{
+ if (register_output(&prelude_op, 0) == -1) {
+ specter_log(SPECTER_FATAL, "Couldn't register.\n");
+ exit(EXIT_FAILURE);
+ }
+}
+