[Snort-devel] Patch: exec option for starting programs triggered by rules

Stefan Schlott stefan.schlott at ...2052...
Fri Jun 27 06:39:20 EDT 2003


Hi all,

I had the need to run a program when snort matched a specific signature (I
wanted to find out more about the attacker's host, e.g. by running nmap).
I didn't find a function in snort, so I wrote a new detection plugin 
(analogous to react and respond). It uses a comma-separated list of
option=value touples as syntax. I implemented the following options:

program=programname option option...
ratelimit=i
output=file

program denotes the command to be executed. Options will be passed to the
program; the special options "#s" and "#d" are replaced with the source/
destination IP of the triggering packet.
ratelimit limits the rule to be triggered at most i times per second.
output redirects stdout and stderr of the forked process to the given
file.

In my example, I used the following options:
  exec:program=/usr/local/snort/nmap -sS -O #s,ratelimit=3,output=/var/log/snort/nmap.log

The plugin is enabled with the --enable-flexresp option in the configure
script, just like react and respond.

Patch against today's snapshot is attached; hope you find it useful.

Stefan.

-- 
*--- please cut here... -------------------------------------- thanks! ---*
|-> E-Mail: stefan.schlott at ...2052...    PGP-Key: 0x2F36F4FE <-|
| There are only 10 types of people in this world -- those that           |
| understand binary and those that don't.                                 |
*-------------------------------------------------------------------------*
-------------- next part --------------
diff -Nur snort-orig/src/detection-plugins/Makefile.am snort-new/src/detection-plugins/Makefile.am
--- snort-orig/src/detection-plugins/Makefile.am	2002-11-05 15:49:22.000000000 +0100
+++ snort-new/src/detection-plugins/Makefile.am	2003-06-26 11:19:08.000000000 +0200
@@ -9,7 +9,7 @@
 sp_ip_fragbits.h sp_ip_id_check.c sp_ip_id_check.h sp_ip_proto.c sp_ip_proto.h \
 sp_ip_same_check.c sp_ip_same_check.h sp_ip_tos_check.c sp_ip_tos_check.h      \
 sp_ipoption_check.c sp_ipoption_check.h sp_pattern_match.c sp_pattern_match.h  \
-sp_react.c sp_react.h \
+sp_react.c sp_react.h sp_exec.c sp_exec.h \
 sp_respond.c sp_respond.h sp_rpc_check.c sp_rpc_check.h         \
 sp_session.c sp_session.h sp_tcp_ack_check.c sp_tcp_ack_check.h                \
 sp_tcp_flag_check.h sp_tcp_flag_check.c sp_tcp_seq_check.c sp_tcp_seq_check.h  \
diff -Nur snort-orig/src/detection-plugins/sp_exec.c snort-new/src/detection-plugins/sp_exec.c
--- snort-orig/src/detection-plugins/sp_exec.c	1970-01-01 01:00:00.000000000 +0100
+++ snort-new/src/detection-plugins/sp_exec.c	2003-06-26 11:19:09.000000000 +0200
@@ -0,0 +1,224 @@
+/* $Id: sp_exec.c,v 1.0 2003/06/24 21:59:34 sts Exp $ */
+/*
+** Copyright (C) 1998-2002 Martin Roesch <roesch at ...402...>
+** Copyright (C) 2003 Stefan Schlott <stefan at ...2056...>
+**
+** 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; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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 <unistd.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "decode.h"
+#include "rules.h"
+#include "plugbase.h"
+#include "parser.h"
+#include "debug.h"
+#include "util.h"
+#include "log.h"
+#include "plugin_enum.h"
+#include "snort.h"
+
+typedef struct _ExecData
+{
+	char* program;
+	int ratelimit;
+	time_t lastcall;
+	int lastcallcount;
+	char* outputfile;
+} ExecData;
+
+
+void ExecInit(char *, OptTreeNode *, int ); 
+void ParseExec(ExecData *, char *);
+int DoExec(Packet *, RspFpList *);
+
+/**************************************************************************
+ *
+ * Function: SetupExec();
+ *
+ * Purpose: Initialize exec plugin
+ *
+ * Arguments: None.
+ *
+ * Returns: void
+ **************************************************************************/
+
+void SetupExec()
+{
+    RegisterPlugin("exec", ExecInit);
+    DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: Exec Setup\n"););
+}
+
+void ExecInit(char *data, OptTreeNode *otn, int protocol) 
+{
+    ExecData *ed;
+
+    if(( ed = (ExecData *)calloc(sizeof(ExecData), sizeof(char))) == NULL)
+        FatalError("sp_exec ExecInit() calloc failed!\n");
+		ParseExec(ed,data);
+    AddRspFuncToList(DoExec, otn, (void *)ed );
+
+    return;
+}
+
+/****************************************************************************
+ *
+ * Function: ParseExec(char *)
+ *
+ * Purpose: Parse parameters given to plugin
+ *   The parameters are a comma-separated list, having the format option=value
+ *   Valid options:
+ *     program   Program, including parameters, to execute
+ *     ratelimit Maximal number of calls per second (or 0 for unlimited, default)
+ *     output    Output file for stdout and stderr outputs of the program
+ *
+ * Arguments: ed => ExecData struct, type => string
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void ParseExec(ExecData *ed, char *type)
+{
+	static char* PROGRAM="program=";
+	static char* RATELIMIT="ratelimit=";
+	static char* OUTPUT="output=";
+	char* opt;
+
+	ed->program=NULL;
+	ed->ratelimit=0;
+	ed->lastcall=time(NULL);
+	ed->lastcallcount=0;
+	ed->outputfile=NULL;
+
+	opt=strtok(type,",");
+	while (opt) {
+		if (strncmp(opt,PROGRAM,strlen(PROGRAM))==0) {
+			ed->program=strdup(&opt[strlen(PROGRAM)]);
+		} else
+		if (strncmp(opt,RATELIMIT,strlen(RATELIMIT))==0) {
+			ed->ratelimit=atoi(&opt[strlen(RATELIMIT)]);
+		} else 
+		if (strncmp(opt,OUTPUT,strlen(OUTPUT))==0) {
+			ed->outputfile=strdup(&opt[strlen(OUTPUT)]);
+		} else DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"sp_exec: Unknown option %s\n",opt););
+		opt=strtok(NULL,",");
+	}
+}
+
+
+/****************************************************************************
+ *
+ * Function: DoExec(Packet *p, RspFpList)
+ *
+ * Purpose: Upon rule match, execute given program. Forks and does not wait
+ *   for the child process to terminate
+ *
+ * Arguments:
+ *
+ * Returns: int, 0 for failure, 1 for success.
+ *
+ ***************************************************************************/
+
+int DoExec(Packet *p, RspFpList *fp_list)
+{
+  ExecData *rd = (ExecData *)fp_list->params;
+	int pid;
+
+  if(!p->iph) return 0;
+	if (!rd->program) return 0;
+
+	/* Rate limit */
+	if (rd->ratelimit>0) {
+		time_t currenttime=time(NULL);
+		if (rd->lastcall==currenttime) {
+			rd->lastcallcount++;
+			if (rd->lastcallcount>rd->ratelimit) return 1;
+		} else {
+			rd->lastcall=currenttime;
+			rd->lastcallcount=1;
+		}
+	}
+  
+  DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"sp_exec DoExec: Running '%s'\n",program););
+	signal(SIGCHLD,SIG_IGN);
+	pid=fork();
+	if (pid<0) return 0;
+	if (pid==0) {
+		char* program=strdup(rd->program);
+		char** params;
+		char *ptr;
+		int paramcnt,maxparam;
+		int i;
+
+		paramcnt=0;
+		maxparam=10;
+		params=(char**)calloc(maxparam,sizeof(char*));
+		ptr=program;
+		while (*ptr!=0) {
+			// Skip spaces
+			while (*ptr!=0 && *ptr==' ') ptr++;
+			if (*ptr==0) break;
+			// New parameter
+			paramcnt++;
+			if (paramcnt==maxparam) {
+				char** newparams;
+				maxparam+=10;
+				newparams=(char**)calloc(maxparam,sizeof(char*));
+				memcpy(newparams,params,sizeof(char*)*paramcnt);
+				free(params);
+				params=newparams;
+			}
+			params[paramcnt-1]=ptr;
+			// Skip non-spaces
+			while (*ptr!=0 && *ptr!=' ') ptr++;
+			if (*ptr==0) break;
+			*ptr=0;
+			ptr++;
+		}
+		// Trailing NULL in array
+		paramcnt++;
+		if (paramcnt==maxparam) {
+			char** newparams;
+			maxparam+=10;
+			newparams=(char**)calloc(maxparam,sizeof(char*));
+			memcpy(newparams,params,sizeof(char*)*paramcnt);
+			free(params);
+			params=newparams;
+		}
+		params[paramcnt-1]=NULL;
+		// Check parameters for placeholders
+		for (i=1; i<paramcnt-1; i++) {
+			if (strcmp("#s",params[i])==0) {
+				params[i]=strdup(inet_ntoa(p->iph->ip_src));
+			} else
+			if (strcmp("#d",params[i])==0) {
+				params[i]=strdup(inet_ntoa(p->iph->ip_dst));
+			}
+		}
+		// Redirect stdout and stderr
+		if (rd->outputfile!=NULL) {
+			int fd = open(rd->outputfile,O_WRONLY|O_CREAT|O_APPEND);
+			dup2(fd,1);
+			dup2(fd,2);
+		}
+		execv(params[0],params);
+		exit(0);
+	}
+
+  return 1;
+}
+
diff -Nur snort-orig/src/detection-plugins/sp_exec.h snort-new/src/detection-plugins/sp_exec.h
--- snort-orig/src/detection-plugins/sp_exec.h	1970-01-01 01:00:00.000000000 +0100
+++ snort-new/src/detection-plugins/sp_exec.h	2003-06-26 11:19:09.000000000 +0200
@@ -0,0 +1,31 @@
+/* $Id: sp_exec.c,v 1.0 2003/06/24 21:59:34 sts Exp $ */
+/*
+** Copyright (C) 1998-2002 Martin Roesch <roesch at ...402...>
+** Copyright (C) 2003 Stefan Schlott <stefan at ...2056...>
+**
+** 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; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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.
+*/
+
+/*  I N C L U D E S
+**********************************************************/
+
+/*  D E F I N E S
+************************************************************/
+#ifndef __EXEC_H__
+#define __EXEC_H__
+
+void SetupExec(void);
+
+#endif /* __RESPOND_H__ */
diff -Nur snort-orig/src/plugbase.c snort-new/src/plugbase.c
--- snort-orig/src/plugbase.c	2003-05-20 08:15:13.000000000 +0200
+++ snort-new/src/plugbase.c	2003-06-26 11:19:09.000000000 +0200
@@ -86,6 +86,7 @@
 #include "detection-plugins/sp_byte_check.h"
 #include "detection-plugins/sp_byte_jump.h"
 #ifdef ENABLE_RESPONSE
+#include "detection-plugins/sp_exec.h"
 #include "detection-plugins/sp_react.h"
 #include "detection-plugins/sp_respond.h"
 #endif
@@ -146,6 +147,7 @@
     SetupByteTest();
     SetupByteJump();
 #ifdef ENABLE_RESPONSE
+		SetupExec();
     SetupReact();
     SetupRespond();
 #endif


More information about the Snort-devel mailing list