[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);
+	}
+}
+
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.