prelude-correlator/master: Use setuptools for distribution and plugins.

[email protected] Wed, 17 Jun 2009 15:46:58 +0200 (CEST)
Newsgroups gmane.comp.security.ids.prelude.cvs
Message-ID <[email protected]>
commit 04df89e00cf7ab7d30ab76e32b0017b8839b3205
Author: Yoann Vandoorselaere <[email protected]>
Date:   Mon Jun 15 13:27:32 2009 +0200

    Use setuptools for distribution and plugins.


========================================

 PreludeCorrelator/main.py                        |  163 +++++++++++++
 PreludeCorrelator/pluginmanager.py               |   66 +++++
 PreludeCorrelator/plugins.py                     |   74 ------
 PreludeCorrelator/plugins/bruteforce.py          |   74 ++++++
 PreludeCorrelator/plugins/businesshour.py        |   44 ++++
 PreludeCorrelator/plugins/dshield.py             |   89 +++++++
 PreludeCorrelator/plugins/firewall.py            |   52 ++++
 PreludeCorrelator/plugins/opensshauth.py         |   56 +++++
 PreludeCorrelator/plugins/scan.py                |  110 +++++++++
 PreludeCorrelator/plugins/worm.py                |   58 +++++
 ez_setup.py                                      |  276 ++++++++++++++++++++++
 prelude_correlator.egg-info/PKG-INFO             |   34 +++
 prelude_correlator.egg-info/SOURCES.txt          |   23 ++
 prelude_correlator.egg-info/dependency_links.txt |    1 +
 prelude_correlator.egg-info/entry_points.txt     |   14 +
 prelude_correlator.egg-info/top_level.txt        |    1 +
 ruleset/brute-force.py                           |   74 ------
 ruleset/business-hour.py                         |   44 ----
 ruleset/dshield.py                               |   89 -------
 ruleset/firewall.py                              |   52 ----
 ruleset/openssh-multiple-authtypes.py            |   56 -----
 ruleset/scan.py                                  |  110 ---------
 ruleset/worm.py                                  |   58 -----
 scripts/prelude-correlator                       |  153 ------------
 setup.py                                         |   77 +++++-
 25 files changed, 1124 insertions(+), 724 deletions(-)

========================================

diff --git a/PreludeCorrelator/main.py b/PreludeCorrelator/main.py
new file mode 100644
index 0000000..08e7b5a
--- /dev/null
+++ b/PreludeCorrelator/main.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+# Author: Yoann Vandoorselaere <[email protected]>
+#
+# This file is part of the Prewikka program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import pkg_resources
+import sys, os, time, signal
+from PreludeCorrelator import idmef, pluginmanager, context, siteconfig
+from optparse import OptionParser
+from PreludeEasy import ClientEasy, CheckVersion
+
+
+prelude_client = None
+VERSION = pkg_resources.get_distribution('prelude-correlator').version
+
+
+if not CheckVersion(siteconfig.libprelude_required_version):
+        raise Exception, ("Libprelude version '%s' is required" % siteconfig.libprelude_required_version)
+
+class PreludeClient:
+        def __init__(self, print_input=None, print_output=None, dry_run=False):
+                self._message_processed = 0
+                self._alert_generated = 0
+                self._print_input = print_input
+                self._print_output = print_output
+                self._continue = True
+                self._dry_run = dry_run
+
+                self._pm = pluginmanager.PluginManager()
+                print ("%d plugin have been loaded." % (self._pm.getPluginCount()))
+
+                self._client = ClientEasy("prelude-correlator", ClientEasy.PERMISSION_IDMEF_READ|ClientEasy.PERMISSION_IDMEF_WRITE,
+                                          "Prelude-Correlator", "Correlator", "PreludeIDS Technologies", VERSION)
+                self._client.Start()
+
+
+        def _handle_event(self, idmef):
+                if self._print_input:
+                        self._print_input.write(str(idmef))
+
+                self._pm.run(idmef)
+                self._message_processed += 1
+
+        def stats(self):
+                print("%d message received, %d correlationAlert generated." % (self._message_processed, self._alert_generated))
+
+        def correlationAlert(self, idmef):
+                self._alert_generated = self._alert_generated + 1
+
+                if not self._dry_run:
+                        self._client.SendIDMEF(idmef)
+
+                if self._print_output:
+                        self._print_output.write(str(idmef))
+
+        def recvEvent(self):
+                msg = idmef.IDMEF()
+
+                last = time.time()
+                while self._continue:
+                        try:
+                            r = self._client.RecvIDMEF(msg, 1000)
+                        except:
+                                r = 0
+
+                        if r:
+                                if msg.Get("alert.create_time"):
+                                        self._handle_event(msg)
+                                msg.reset()
+
+                        now = time.time()
+                        if now - last >= 1:
+                                context.wakeup(now)
+                                last = now
+
+        def stop(self):
+                self._continue = False
+
+
+def handle_signal(signum, frame):
+        print 'Signal handler called with signal', signum
+        if signum == signal.SIGQUIT:
+                prelude_client.stats()
+                context.stats()
+        else:
+                prelude_client.stop()
+
+def main():
+        global prelude_client
+
+        parser = OptionParser(usage="%prog", version="%prog " + VERSION)
+        parser.add_option("-c", "--config", action="store", dest="config", type="string", help="Configuration file to use", metavar="FILE")
+        parser.add_option("", "--dry-run", action="store_true", dest="dry_run", help="No report to the specified Manager will occur", default=False)
+        parser.add_option("-d", "--daemon", action="store_true", dest="daemon", help="Run in daemon mode")
+        parser.add_option("-P", "--pidfile", action="store", dest="pidfile", type="string", help="Write Prelude Correlator PID to specified file", metavar="FILE")
+        parser.add_option("", "--print-input", action="store", dest="print_input", type="string", help="Dump alert input from manager to the specified file", metavar="FILE")
+        parser.add_option("", "--print-output", action="store", dest="print_output", type="string", help="Dump alert output to the specified file", metavar="FILE")
+        parser.add_option("--debug", action="store", dest="debug", type="int", help="Enable debug ouptut (optional debug level argument)", metavar="LEVEL")
+        (options, args) = parser.parse_args()
+
+        ifd = None
+        if options.print_input:
+                if options.print_input == "-":
+                        ifd = sys.stdout
+                else:
+                        ifd = open(options.print_input, "w")
+
+        ofd = None
+        if options.print_output:
+                if options.print_output == "-":
+                        ofd = sys.stdout
+                else:
+                        ofd = open(options.print_output, "w")
+
+        if options.daemon:
+            if os.fork():
+                os._exit(0)
+
+            os.setsid()
+            if os.fork():
+                os._exit(0)
+
+            os.umask(077)
+
+            fd = os.open('/dev/null', os.O_RDWR)
+            for i in xrange(3):
+                os.dup2(fd, i)
+
+            os.close(fd)
+            if options.pidfile:
+                open(pidfile, "w").write(str(os.getpid()))
+
+        prelude_client = PreludeClient(print_input=ifd, print_output=ofd, dry_run=options.dry_run)
+        idmef.set_prelude_client(prelude_client)
+
+        signal.signal(signal.SIGTERM, handle_signal)
+        signal.signal(signal.SIGINT, handle_signal)
+        signal.signal(signal.SIGQUIT, handle_signal)
+
+        # restore previous context.
+        context.load()
+
+        prelude_client.recvEvent()
+
+        # save existing context
+        context.save()
+
diff --git a/PreludeCorrelator/pluginmanager.py b/PreludeCorrelator/pluginmanager.py
new file mode 100644
index 0000000..a24e7b4
--- /dev/null
+++ b/PreludeCorrelator/pluginmanager.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+# Author: Yoann Vandoorselaere <[email protected]>
+#
+# This file is part of the Prewikka program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import pkg_resources
+import ConfigParser, sys, os, traceback
+from PreludeCorrelator import siteconfig
+
+
+config = ConfigParser.ConfigParser()
+config.read(siteconfig.conf_dir + '/plugins.conf')
+
+ENTRYPOINT = 'PreludeCorrelator.plugins'
+
+class Plugin(object):
+    enable = True
+
+    def getConfigValue(self, key, replacement=None):
+        if not config.has_section(self.__class__.__name__):
+            return replacement
+
+        try:
+            return config.get(self.__class__.__name__, key)
+        except ConfigParser.NoOptionError:
+            return replacement
+
+    def run(self, idmef):
+        pass
+
+
+class PluginManager:
+    def __init__(self):
+        self._count = 0
+        self._instance = []
+
+        for entrypoint in pkg_resources.iter_entry_points(ENTRYPOINT):
+            plugin_class = entrypoint.load()
+
+            self._instance.append(plugin_class())
+            self._count += 1
+
+    def getPluginCount(self):
+        return self._count
+
+    def run(self, idmef):
+        for plugin in self.__instances:
+            try:
+                plugin.run(idmef)
+            except Exception, e:
+                traceback.print_exc()
+
diff --git a/PreludeCorrelator/plugins.py b/PreludeCorrelator/plugins.py
deleted file mode 100644
index 486eb38..0000000
--- a/PreludeCorrelator/plugins.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
-# Author: Yoann Vandoorselaere <[email protected]>
-#
-# This file is part of the Prewikka program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-from PreludeCorrelator import siteconfig
-import ConfigParser, sys, os, traceback
-
-
-config = ConfigParser.ConfigParser()
-config.read(siteconfig.conf_dir + '/plugins.conf')
-
-
-class Plugin(object):
-    enable = True
-
-    def getConfigValue(self, key, replacement=None):
-        if not config.has_section(self.__module__):
-            return replacement
-
-        try:
-            return config.get(self.__module__, key)
-        except ConfigParser.NoOptionError:
-            return replacement
-
-    def run(self, idmef):
-        pass
-
-
-class PluginManager:
-    __instances = []
-
-    def __initPlugin(self, plugin):
-        p = plugin()
-        if p.enable:
-            self.__instances.append(p)
-
-        self._count = self._count + 1
-
-    def __init__(self):
-        self._count = 0
-
-        sys.path.insert(0, siteconfig.ruleset_dir)
-
-        for file in os.listdir(siteconfig.ruleset_dir):
-            pl = __import__(os.path.splitext(file)[0], None, None, [''])
-
-        for plugin in Plugin.__subclasses__():
-            self.__initPlugin(plugin)
-
-    def getPluginCount(self):
-        return self._count
-
-    def run(self, idmef):
-        for plugin in self.__instances:
-            try:
-                plugin.run(idmef)
-            except Exception, e:
-                traceback.print_exc()
-
diff --git a/PreludeCorrelator/plugins/__init__.py b/PreludeCorrelator/plugins/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/PreludeCorrelator/plugins/bruteforce.py b/PreludeCorrelator/plugins/bruteforce.py
new file mode 100644
index 0000000..72c6af9
--- /dev/null
+++ b/PreludeCorrelator/plugins/bruteforce.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2006 G Ramon Gomez <gene at gomezbrothers dot com>
+# Copyright (C) 2009 PreludeIDS Technologies <[email protected]>
+#
+# This file is part of the Prelude-Correlator program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import re
+from PreludeCorrelator.pluginmanager import Plugin
+from PreludeCorrelator.context import Context
+
+class BruteForcePlugin(Plugin):
+    def _BruteForce(self, idmef):
+        sadd = idmef.Get("alert.source(*).node.address(*).address")
+        tadd = idmef.Get("alert.target(*).node.address(*).address")
+        if not sadd or not tadd:
+            return
+
+        for source in sadd:
+            for target in tadd:
+                ctx = Context("BRUTE_ST_" + source + target, { "expire": 2, "threshold": 5 }, update = True)
+                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+
+                if ctx.CheckAndDecThreshold():
+                    ctx.Set("alert.classification.text", "Brute force attack")
+                    ctx.Set("alert.correlation_alert.name", "Multiple failed login")
+                    ctx.Set("alert.assessment.impact.severity", "high")
+                    ctx.Set("alert.assessment.impact.description", "Multiple failed attempts have been made to login to a user account")
+                    ctx.alert()
+                    ctx.destroy()
+
+    def _BruteUserForce(self, idmef):
+        userid = idmef.Get("alert.target(*).user.user_id(*).name");
+        if not userid:
+            return
+
+        for user in userid:
+            ctx = Context("BRUTE_U_" + user, { "expire": 120, "threshold": 2 }, update = True)
+            ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+            ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+            ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+            ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+
+            if ctx.CheckAndDecThreshold():
+                ctx.Set("alert.classification.text", "Brute force attack")
+                ctx.Set("alert.correlation_alert.name", "Multiple failed login")
+                ctx.Set("alert.assessment.impact.severity", "high")
+                ctx.Set("alert.assessment.impact.description", "Multiple failed attempts have been made to login to a user account")
+                ctx.alert()
+                ctx.destroy()
+
+
+    def run(self, idmef):
+        if not idmef.match("alert.classification.text", re.compile("[Ll]ogin|[Aa]uthentication"),
+                           "alert.assessment.impact.completion", "failed"):
+            return
+
+        self._BruteForce()
+        self._BruteUserForce()
diff --git a/PreludeCorrelator/plugins/businesshour.py b/PreludeCorrelator/plugins/businesshour.py
new file mode 100644
index 0000000..d450737
--- /dev/null
+++ b/PreludeCorrelator/plugins/businesshour.py
@@ -0,0 +1,44 @@
+# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+# Author: Yoann Vandoorselaere <[email protected]>
+#
+# This file is part of the Prelude-Correlator program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import time
+from PreludeCorrelator.idmef import IDMEF
+from PreludeCorrelator.pluginmanager import Plugin
+
+# Alert only on saturday and sunday, and everyday from 6:00pm to 9:00am.
+
+class BusinessHourPlugin(Plugin):
+    def run(self, idmef):
+
+        t = time.localtime(int(idmef.Get("alert.create_time")))
+
+        if not (t.tm_wday == 5 or t.tm_wday == 6 or t.tm_hour < 9 or t.tm_hour > 17):
+                return
+
+        if idmef.Get("alert.assessment.impact.completion") != "succeeded":
+                return
+
+        ca = IDMEF()
+        ca.Set("alert.source", idmef.Get("alert.source"))
+        ca.Set("alert.target", idmef.Get("alert.target"))
+        ca.Set("alert.classification", idmef.Get("alert.classification"))
+        ca.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+        ca.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+        ca.Set("alert.correlation_alert.name", "Critical system activity on day off")
+        ca.alert()
diff --git a/PreludeCorrelator/plugins/dshield.py b/PreludeCorrelator/plugins/dshield.py
new file mode 100644
index 0000000..7c0dbf6
--- /dev/null
+++ b/PreludeCorrelator/plugins/dshield.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+# Author: Yoann Vandoorselaere <[email protected]>
+# Author: Sebastien Tricaud <[email protected]>
+#
+# This file is part of the Prelude-Correlator program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import os, httplib, time
+from PreludeCorrelator import siteconfig
+from PreludeCorrelator.idmef import IDMEF
+from PreludeCorrelator.pluginmanager import Plugin
+from PreludeCorrelator.context import Context, Timer
+
+
+class DshieldPlugin(Plugin):
+    DSHIELD_RELOAD = 7 * 24 * 60 * 60
+    DSHIELD_SERVER = "www.dshield.org"
+    DSHIELD_URI = "www.dshield.org/ipsascii.html?limit=10000"
+
+    def __loadData(self, fname, age=0):
+        cnt = 0
+        self.__iphash.clear()
+
+        for line in open(fname, "r"):
+            if line[0] != '#':
+                self.__iphash[line.split('\t')[0]] = True
+                cnt = cnt + 1
+
+        Timer(self.__reload - age, self.__retrieveData)
+
+    def __retrieveData(self, timer=None):
+        fname = siteconfig.lib_dir + "/dshield.dat"
+
+        try:
+            st = os.stat(fname)
+            if time.time() - st.st_mtime < self.__reload:
+                return self.__loadData(fname, time.time() - st.st_mtime)
+        except:
+            pass
+
+        print("Downloading host list from dshield, this might take some time...")
+        con = httplib.HTTPConnection(self.__server)
+        con.request("GET", self.__uri)
+        r = con.getresponse()
+        if r.status != 200:
+            return
+
+        fd = open(fname, "w")
+        fd.write(r.read())
+        fd.close()
+
+        print("Downloading done, processing data.")
+        self.__loadData(fname)
+
+
+    def __init__(self):
+        self.__iphash = { }
+        self.__reload = self.getConfigValue("reload", self.DSHIELD_RELOAD)
+        self.__server = self.getConfigValue("server", self.DSHIELD_SERVER)
+        self.__uri = self.getConfigValue("uri", self.DSHIELD_URI)
+
+        self.__retrieveData()
+
+    def run(self, idmef):
+        for source in idmef.Get("alert.source(*).node.address(*).address"):
+            if self.__iphash.has_key(source):
+                ca = IDMEF()
+                ca.Set("alert.source(>>)", idmef.Get("alert.source"))
+                ca.Set("alert.target(>>)", idmef.Get("alert.target"))
+                ca.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+                ca.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+                ca.Set("alert.classification.text", "IP source matching Dshield database")
+                ca.Set("alert.correlation_alert.name", "IP source matching Dshield database")
+                ca.Set("alert.assessment.impact.description", "Dshield gather IP addresses tagged from firewall logs drops")
+                ca.Set("alert.assessment.impact.severity", "high")
+                ca.alert()
diff --git a/PreludeCorrelator/plugins/firewall.py b/PreludeCorrelator/plugins/firewall.py
new file mode 100644
index 0000000..fd05eac
--- /dev/null
+++ b/PreludeCorrelator/plugins/firewall.py
@@ -0,0 +1,52 @@
+# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+# Author: Yoann Vandoorselaere <[email protected]>
+#
+# This file is part of the Prewikka program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import re
+from PreludeCorrelator import context
+from PreludeCorrelator.pluginmanager import Plugin
+
+class FirewallPlugin(Plugin):
+    def run(self, idmef):
+        source = idmef.Get("alert.source(0).node.address(0).address")
+        sport = idmef.Get("alert.source(0).service.port", 0)
+        target = idmef.Get("alert.target(0).node.address(0).address")
+        dport = idmef.Get("alert.target(0).service.port", 0)
+
+        if not source or not target:
+                return
+
+        ctxname = "FIREWALL_" + source + str(sport) + target + str(dport)
+
+        if idmef.match("alert.classification.text", re.compile("[Pp]acket [Dd]ropped|[Dd]enied")):
+                # Update context if any, removing the alert_on_expire attribute.
+                ctx = context.Context(ctxname, { "expire": 10 }, update = True)
+        else:
+                # Begins a timer for every event that contains a source and a target
+                # address which has not been matched by an observed packet denial.  If a packet
+                # denial is not observed in the next 10 seconds, an event alert is generated.
+
+                if not context.search(ctxname):
+                        ctx = context.Context(ctxname, { "expire": 10, "alert_on_expire": True })
+                        ctx.Set("alert.source", idmef.Get("alert.source"))
+                        ctx.Set("alert.target", idmef.Get("alert.target"))
+                        ctx.Set("alert.assessment", idmef.Get("alert.assessment"))
+                        ctx.Set("alert.classification", idmef.Get("alert.classification"))
+                        ctx.Set("alert.correlation_alert.name", "Events to firewall correlation")
+                        ctx.Set("alert.correlation_alert.alertident(0).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+                        ctx.Set("alert.correlation_alert.alertident(0).alertident", idmef.Get("alert.messageid"))
diff --git a/PreludeCorrelator/plugins/opensshauth.py b/PreludeCorrelator/plugins/opensshauth.py
new file mode 100644
index 0000000..1872bc9
--- /dev/null
+++ b/PreludeCorrelator/plugins/opensshauth.py
@@ -0,0 +1,56 @@
+# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
+# Author: Sebastien Tricaud <[email protected]>
+# Author: Yoann Vandoorselaere <[email protected]>
+#
+# This file is part of the Prelude-Correlator program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+from PreludeCorrelator.pluginmanager import Plugin
+from PreludeCorrelator.context import Context
+
+
+class OpenSSHAuthPlugin(Plugin):
+    def run(self, idmef):
+        if idmef.Get("alert.analyzer(-1).manufacturer") != "OpenSSH":
+                return
+
+        if idmef.Get("alert.assessment.impact.completion") != "succeeded":
+                return
+
+        try:
+                idx = idmef.Get("alert.additional_data(*).meaning").index("Authentication method")
+        except:
+                return
+
+        data = idmef.Get("alert.additional_data(%d).data" % idx)
+
+        for username in idmef.Get("alert.target(*).user.user_id(*).name"):
+            for target in idmef.Get("alert.target(*).node.address(*).address"):
+                ctx = Context("SSH_MAT_" + target + username, {"threshold": 1}, update = True)
+                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+
+                if not hasattr(ctx, "authtype"):
+                    ctx.authtype = data
+                elif ctx.authtype != data:
+                    ctx.Set("alert.classification.text", "Multiple authentication methods")
+                    ctx.Set("alert.correlation_alert.name", "Multiple authentication methods")
+                    ctx.Set("alert.assessment.impact.severity", "medium")
+                    ctx.Set("alert.assessment.impact.description", "Multiple ways of authenticating a single user have been found over SSH. If passphrase is the only allowed method, make sure you disable passwords.")
+                    ctx.alert()
+                    ctx.destroy()
diff --git a/PreludeCorrelator/plugins/scan.py b/PreludeCorrelator/plugins/scan.py
new file mode 100644
index 0000000..309ce7a
--- /dev/null
+++ b/PreludeCorrelator/plugins/scan.py
@@ -0,0 +1,110 @@
+# Copyright (C) 2006 G Ramon Gomez <gene at gomezbrothers dot com>
+# Copyright (C) 2009 PreludeIDS Technologies <[email protected]>
+#
+# This file is part of the Prelude-Correlator program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Detect Eventscan:
+# Playing multiple events from a single host against another single host
+
+from PreludeCorrelator.context import Context
+from PreludeCorrelator.pluginmanager import Plugin
+
+class EventScanPlugin(Plugin):
+    def run(self, idmef):
+        source = idmef.Get("alert.source(*).node.address(*).address")
+        target = idmef.Get("alert.target(*).node.address(*).address")
+
+        if not source or not target:
+            return
+
+        for saddr in source:
+            for daddr in target:
+                ctx = Context("SCAN_EVENTSCAN_" + saddr + daddr, { "expire": 60, "threshold": 30 }, update = True)
+                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+
+                if ctx.CheckAndDecThreshold():
+                    ctx.Set("alert.correlation_alert.name", "A single host has played many events against a single target. This may be a vulnerability scan")
+                    ctx.Set("alert.classification.text", "Eventscan")
+                    ctx.Set("alert.assessment.impact.severity", "high")
+                    ctx.alert()
+                    ctx.destroy()
+
+
+# Detect Eventsweep:
+# Playing the same event from a single host against multiple hosts
+class EventSweepPlugin(Plugin):
+    def run(self, idmef):
+        classification = idmef.Get("alert.classification.text")
+        source = idmef.Get("alert.source(*).node.address(*).address")
+        target = idmef.Get("alert.target(*).node.address(*).address")
+
+        if not source or not target or not classification:
+            return
+
+        for saddr in source:
+            ctx = Context("SCAN_EVENTSWEEP_" + classification + saddr, { "expire": 60, "threshold": 30 }, update = True)
+            insert = True
+
+            cur = ctx.Get("alert.target(*).node.address(*).address")
+            if cur:
+                for address in target:
+                    if address in cur:
+                        insert = False
+                        break
+
+            if insert:
+                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+
+                if ctx.CheckAndDecThreshold():
+                    ctx.Set("alert.correlation_alert.name", "A single host has played the same event against multiple targets. This may be a network scan for a specific vulnerability")
+                    ctx.Set("alert.classification.text", "Eventsweep")
+                    ctx.Set("alert.assessment.impact.severity", "high")
+                    ctx.alert()
+                    ctx.destroy()
+
+
+
+
+# Detect Eventstorm:
+# Playing excessive events by a single host
+class EventStormPlugin(Plugin):
+    def run(self, idmef):
+        source = idmef.Get("alert.source(*).node.address(*).address")
+        if not source:
+            return
+
+        for saddr in source:
+            ctx = Context("SCAN_EVENTSTORM_" + saddr, { "expire": 120, "threshold": 150 }, update = True)
+
+            ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+            ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+            ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+            ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+
+            if ctx.CheckAndDecThreshold():
+                ctx.Set("alert.correlation_alert.name", "A single host is producing an unusual amount of events")
+                ctx.Set("alert.classification.text", "Eventstorm")
+                ctx.Set("alert.assessment.impact.severity", "high")
+                ctx.alert()
+                ctx.destroy()
+
diff --git a/PreludeCorrelator/plugins/worm.py b/PreludeCorrelator/plugins/worm.py
new file mode 100644
index 0000000..6b90760
--- /dev/null
+++ b/PreludeCorrelator/plugins/worm.py
@@ -0,0 +1,58 @@
+# Copyright (C) 2006 G Ramon Gomez <gene at gomezbrothers dot com>
+# Copyright (C) 2009 PreludeIDS Technologies <[email protected]>
+# All Rights Reserved.
+#
+# This file is part of the Prelude-Correlator program.
+#
+# 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, 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# This rule looks for events against a host, records the messageid, then sets
+# a timer of 600 seconds.   If the host then replays the event against
+# other hosts multiple times, an event is generated.
+
+from PreludeCorrelator import context
+from PreludeCorrelator.pluginmanager import Plugin
+
+class WormPlugin(Plugin):
+    def run(self, idmef):
+        ctxt = idmef.Get("alert.classification.text")
+        if not ctxt:
+            return
+
+        # Create context for classification combined with all the target.
+        for target in idmef.Get("alert.target(*).node.address(*).address"):
+            ctx = context.Context("WORM_HOST_" + ctxt + target, { "expire": 300, "threshold": 5 }, update = True)
+
+        for source in idmef.Get("alert.source(*).node.address(*).address"):
+            # We are trying to see whether a previous target is now attacking other hosts
+            # thus, we check whether a context exist with this classification combined to
+            # this source.
+            ctx = context.search("WORM_HOST_" + ctxt + source)
+            if not ctx:
+                continue
+
+            ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
+            ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
+            ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
+            ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
+
+            # Increase and check the context threshold.
+            if ctx.CheckAndDecThreshold():
+                ctx.Set("alert.classification.text", "Possible Worm Activity")
+                ctx.Set("alert.correlation_alert.name", "Source host repeating actions taken against it recently")
+                ctx.Set("alert.assessment.impact.severity", "high")
+                ctx.Set("alert.assessment.impact.description", source + " has repeated actions taken against it recently at least 5 times. It may have been infected with a worm.")
+                ctx.alert()
+                ctx.destroy()
diff --git a/ez_setup.py b/ez_setup.py
new file mode 100644
index 0000000..d24e845
--- /dev/null
+++ b/ez_setup.py
@@ -0,0 +1,276 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from ez_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c9"
+DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
+    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
+    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
+    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
+}
+
+import sys, os
+try: from hashlib import md5
+except ImportError: from md5 import md5
+
+def _validate_md5(egg_name, data):
+    if egg_name in md5_data:
+        digest = md5(data).hexdigest()
+        if digest != md5_data[egg_name]:
+            print >>sys.stderr, (
+                "md5 validation of %s failed!  (Possible download problem?)"
+                % egg_name
+            )
+            sys.exit(2)
+    return data
+
+def use_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    download_delay=15
+):
+    """Automatically find/download setuptools and make it available on sys.path
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end with
+    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
+    it is not already available.  If `download_delay` is specified, it should
+    be the number of seconds that will be paused before initiating a download,
+    should one be required.  If an older version of setuptools is installed,
+    this routine will print a message to ``sys.stderr`` and raise SystemExit in
+    an attempt to abort the calling script.
+    """
+    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+    def do_download():
+        egg = download_setuptools(version, download_base, to_dir, download_delay)
+        sys.path.insert(0, egg)
+        import setuptools; setuptools.bootstrap_install_from = egg
+    try:
+        import pkg_resources
+    except ImportError:
+        return do_download()       
+    try:
+        pkg_resources.require("setuptools>="+version); return
+    except pkg_resources.VersionConflict, e:
+        if was_imported:
+            print >>sys.stderr, (
+            "The required version of setuptools (>=%s) is not available, and\n"
+            "can't be installed while this script is running. Please install\n"
+            " a more recent version first, using 'easy_install -U setuptools'."
+            "\n\n(Currently using %r)"
+            ) % (version, e.args[0])
+            sys.exit(2)
+        else:
+            del pkg_resources, sys.modules['pkg_resources']    # reload ok
+            return do_download()
+    except pkg_resources.DistributionNotFound:
+        return do_download()
+
+def download_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    delay = 15
+):
+    """Download setuptools from a specified location and return its filename
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download attempt.
+    """
+    import urllib2, shutil
+    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+    url = download_base + egg_name
+    saveto = os.path.join(to_dir, egg_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            from distutils import log
+            if delay:
+                log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help).  I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+   %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+                    version, download_base, delay, url
+                ); from time import sleep; sleep(delay)
+            log.warn("Downloading %s", url)
+            src = urllib2.urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = _validate_md5(egg_name, src.read())
+            dst = open(saveto,"wb"); dst.write(data)
+        finally:
+            if src: src.close()
+            if dst: dst.close()
+    return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+    try:
+        import setuptools
+    except ImportError:
+        egg = None
+        try:
+            egg = download_setuptools(version, delay=0)
+            sys.path.insert(0,egg)
+            from setuptools.command.easy_install import main
+            return main(list(argv)+[egg])   # we're done here
+        finally:
+            if egg and os.path.exists(egg):
+                os.unlink(egg)
+    else:
+        if setuptools.__version__ == '0.0.1':
+            print >>sys.stderr, (
+            "You have an obsolete version of setuptools installed.  Please\n"
+            "remove it from your system entirely before rerunning this script."
+            )
+            sys.exit(2)
+
+    req = "setuptools>="+version
+    import pkg_resources
+    try:
+        pkg_resources.require(req)
+    except pkg_resources.VersionConflict:
+        try:
+            from setuptools.command.easy_install import main
+        except ImportError:
+            from easy_install import main
+        main(list(argv)+[download_setuptools(delay=0)])
+        sys.exit(0) # try to force an exit
+    else:
+        if argv:
+            from setuptools.command.easy_install import main
+            main(argv)
+        else:
+            print "Setuptools version",version,"or greater has been installed."
+            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+    """Update our built-in md5 registry"""
+
+    import re
+
+    for name in filenames:
+        base = os.path.basename(name)
+        f = open(name,'rb')
+        md5_data[base] = md5(f.read()).hexdigest()
+        f.close()
+
+    data = ["    %r: %r,\n" % it for it in md5_data.items()]
+    data.sort()
+    repl = "".join(data)
+
+    import inspect
+    srcfile = inspect.getsourcefile(sys.modules[__name__])
+    f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+    match = re.search("\nmd5_data = {\n([^}]+)}", src)
+    if not match:
+        print >>sys.stderr, "Internal error!"
+        sys.exit(2)
+
+    src = src[:match.start(1)] + repl + src[match.end(1):]
+    f = open(srcfile,'w')
+    f.write(src)
+    f.close()
+
+
+if __name__=='__main__':
+    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+        update_md5(sys.argv[2:])
+    else:
+        main(sys.argv[1:])
+
+
+
+
+
+
diff --git a/prelude_correlator.egg-info/PKG-INFO b/prelude_correlator.egg-info/PKG-INFO
new file mode 100644
index 0000000..cac97ff
--- /dev/null
+++ b/prelude_correlator.egg-info/PKG-INFO
@@ -0,0 +1,34 @@
+Metadata-Version: 1.0
+Name: prelude-correlator
+Version: 0.1
+Summary: Prelude-Correlator perform real time correlation of events received by Prelude
+Home-page: http://www.prelude-ids.com
+Author: Yoann Vandoorselaere
+Author-email: [email protected]
+License: UNKNOWN
+Download-URL: http://www.prelude-ids.com/development/download/
+Description: 
+        Prelude-Correlator perform real time correlation of events received by Prelude.
+        
+        Several isolated alerts, generated from different sensors, can thus
+        trigger a single CorrelationAlert should the events be related. This
+        CorrelationAlert then appears within the Prewikka interface and
+        indicates the potential target information via the set of correlation
+        rules.
+        
+        Signature creation with Prelude-Correlator is based on the Python
+        programming language. Prelude's integrated correlation engine is
+        distributed with a default set of correlation rules, yet you still
+        have the opportunity to modify and create any correlation rule that
+        suits your needs.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: GNU General Public License (GPL)
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Security
+Classifier: Topic :: System :: Monitoring
diff --git a/prelude_correlator.egg-info/SOURCES.txt b/prelude_correlator.egg-info/SOURCES.txt
new file mode 100644
index 0000000..f2c3567
--- /dev/null
+++ b/prelude_correlator.egg-info/SOURCES.txt
@@ -0,0 +1,23 @@
+README
+ez_setup.py
+setup.py
+PreludeCorrelator/__init__.py
+PreludeCorrelator/context.py
+PreludeCorrelator/idmef.py
+PreludeCorrelator/main.py
+PreludeCorrelator/pluginmanager.py
+PreludeCorrelator/siteconfig.py
+PreludeCorrelator/utils.py
+PreludeCorrelator/plugins/__init__.py
+PreludeCorrelator/plugins/bruteforce.py
+PreludeCorrelator/plugins/businesshour.py
+PreludeCorrelator/plugins/dshield.py
+PreludeCorrelator/plugins/firewall.py
+PreludeCorrelator/plugins/opensshauth.py
+PreludeCorrelator/plugins/scan.py
+PreludeCorrelator/plugins/worm.py
+prelude_correlator.egg-info/PKG-INFO
+prelude_correlator.egg-info/SOURCES.txt
+prelude_correlator.egg-info/dependency_links.txt
+prelude_correlator.egg-info/entry_points.txt
+prelude_correlator.egg-info/top_level.txt
\ No newline at end of file
diff --git a/prelude_correlator.egg-info/dependency_links.txt b/prelude_correlator.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/prelude_correlator.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/prelude_correlator.egg-info/entry_points.txt b/prelude_correlator.egg-info/entry_points.txt
new file mode 100644
index 0000000..c1f83c7
--- /dev/null
+++ b/prelude_correlator.egg-info/entry_points.txt
@@ -0,0 +1,14 @@
+[PreludeCorrelator.plugins]
+OpenSSHAuthPlugin = PreludeCorrelator.plugins.opensshauth:OpenSSHAuthPlugin
+EventSweepPlugin = PreludeCorrelator.plugins.scan:EventSweepPlugin
+BusinessHourPlugin = PreludeCorrelator.plugins.businesshour:BusinessHourPlugin
+WormPlugin = PreludeCorrelator.plugins.worm:WormPlugin
+FirewallPlugin = PreludeCorrelator.plugins.firewall:FirewallPlugin
+BruteForcePlugin = PreludeCorrelator.plugins.bruteforce:BruteForcePlugin
+EventStormPlugin = PreludeCorrelator.plugins.scan:EventStormPlugin
+DshieldPlugin = PreludeCorrelator.plugins.dshield:DshieldPlugin
+EventScanPlugin = PreludeCorrelator.plugins.scan:EventScanPlugin
+
+[console_scripts]
+prelude-correlator = PreludeCorrelator.main:main
+
diff --git a/prelude_correlator.egg-info/top_level.txt b/prelude_correlator.egg-info/top_level.txt
new file mode 100644
index 0000000..b386f92
--- /dev/null
+++ b/prelude_correlator.egg-info/top_level.txt
@@ -0,0 +1 @@
+PreludeCorrelator
diff --git a/ruleset/brute-force.py b/ruleset/brute-force.py
deleted file mode 100644
index dfa4e69..0000000
--- a/ruleset/brute-force.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (C) 2006 G Ramon Gomez <gene at gomezbrothers dot com>
-# Copyright (C) 2009 PreludeIDS Technologies <[email protected]>
-#
-# This file is part of the Prelude-Correlator program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import re
-from PreludeCorrelator.plugins import Plugin
-from PreludeCorrelator.context import Context
-
-class BrutePlugin(Plugin):
-    def _BruteForce(self, idmef):
-        sadd = idmef.Get("alert.source(*).node.address(*).address")
-        tadd = idmef.Get("alert.target(*).node.address(*).address")
-        if not sadd or not tadd:
-            return
-
-        for source in sadd:
-            for target in tadd:
-                ctx = Context("BRUTE_ST_" + source + target, { "expire": 2, "threshold": 5 }, update = True)
-                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-
-                if ctx.CheckAndDecThreshold():
-                    ctx.Set("alert.classification.text", "Brute force attack")
-                    ctx.Set("alert.correlation_alert.name", "Multiple failed login")
-                    ctx.Set("alert.assessment.impact.severity", "high")
-                    ctx.Set("alert.assessment.impact.description", "Multiple failed attempts have been made to login to a user account")
-                    ctx.alert()
-                    ctx.destroy()
-
-    def _BruteUserForce(self, idmef):
-        userid = idmef.Get("alert.target(*).user.user_id(*).name");
-        if not userid:
-            return
-
-        for user in userid:
-            ctx = Context("BRUTE_U_" + user, { "expire": 120, "threshold": 2 }, update = True)
-            ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-            ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-            ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-            ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-
-            if ctx.CheckAndDecThreshold():
-                ctx.Set("alert.classification.text", "Brute force attack")
-                ctx.Set("alert.correlation_alert.name", "Multiple failed login")
-                ctx.Set("alert.assessment.impact.severity", "high")
-                ctx.Set("alert.assessment.impact.description", "Multiple failed attempts have been made to login to a user account")
-                ctx.alert()
-                ctx.destroy()
-
-
-    def run(self, idmef):
-        if not idmef.match("alert.classification.text", re.compile("[Ll]ogin|[Aa]uthentication"),
-                           "alert.assessment.impact.completion", "failed"):
-            return
-
-        self._BruteForce()
-        self._BruteUserForce()
diff --git a/ruleset/business-hour.py b/ruleset/business-hour.py
deleted file mode 100644
index db4f6cb..0000000
--- a/ruleset/business-hour.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
-# Author: Yoann Vandoorselaere <[email protected]>
-#
-# This file is part of the Prelude-Correlator program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import time
-from PreludeCorrelator.idmef import IDMEF
-from PreludeCorrelator.plugins import Plugin
-
-# Alert only on saturday and sunday, and everyday from 6:00pm to 9:00am.
-
-class BusinessHourPlugin(Plugin):
-    def run(self, idmef):
-
-        t = time.localtime(int(idmef.Get("alert.create_time")))
-
-        if not (t.tm_wday == 5 or t.tm_wday == 6 or t.tm_hour < 9 or t.tm_hour > 17):
-                return
-
-        if idmef.Get("alert.assessment.impact.completion") != "succeeded":
-                return
-
-        ca = IDMEF()
-        ca.Set("alert.source", idmef.Get("alert.source"))
-        ca.Set("alert.target", idmef.Get("alert.target"))
-        ca.Set("alert.classification", idmef.Get("alert.classification"))
-        ca.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-        ca.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-        ca.Set("alert.correlation_alert.name", "Critical system activity on day off")
-        ca.alert()
diff --git a/ruleset/dshield.py b/ruleset/dshield.py
deleted file mode 100644
index 24d0780..0000000
--- a/ruleset/dshield.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
-# Author: Yoann Vandoorselaere <[email protected]>
-# Author: Sebastien Tricaud <[email protected]>
-#
-# This file is part of the Prelude-Correlator program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import os, httplib, time
-from PreludeCorrelator import siteconfig
-from PreludeCorrelator.idmef import IDMEF
-from PreludeCorrelator.plugins import Plugin
-from PreludeCorrelator.context import Context, Timer
-
-
-class DshieldPlugin(Plugin):
-    DSHIELD_RELOAD = 7 * 24 * 60 * 60
-    DSHIELD_SERVER = "www.dshield.org"
-    DSHIELD_URI = "www.dshield.org/ipsascii.html?limit=10000"
-
-    def __loadData(self, fname, age=0):
-        cnt = 0
-        self.__iphash.clear()
-
-        for line in open(fname, "r"):
-            if line[0] != '#':
-                self.__iphash[line.split('\t')[0]] = True
-                cnt = cnt + 1
-
-        Timer(self.__reload - age, self.__retrieveData)
-
-    def __retrieveData(self, timer=None):
-        fname = siteconfig.lib_dir + "/dshield.dat"
-
-        try:
-            st = os.stat(fname)
-            if time.time() - st.st_mtime < self.__reload:
-                return self.__loadData(fname, time.time() - st.st_mtime)
-        except:
-            pass
-
-        print("Downloading host list from dshield, this might take some time...")
-        con = httplib.HTTPConnection(self.__server)
-        con.request("GET", self.__uri)
-        r = con.getresponse()
-        if r.status != 200:
-            return
-
-        fd = open(fname, "w")
-        fd.write(r.read())
-        fd.close()
-
-        print("Downloading done, processing data.")
-        self.__loadData(fname)
-
-
-    def __init__(self):
-        self.__iphash = { }
-        self.__reload = self.getConfigValue("reload", self.DSHIELD_RELOAD)
-        self.__server = self.getConfigValue("server", self.DSHIELD_SERVER)
-        self.__uri = self.getConfigValue("uri", self.DSHIELD_URI)
-
-        self.__retrieveData()
-
-    def run(self, idmef):
-        for source in idmef.Get("alert.source(*).node.address(*).address"):
-            if self.__iphash.has_key(source):
-                ca = IDMEF()
-                ca.Set("alert.source(>>)", idmef.Get("alert.source"))
-                ca.Set("alert.target(>>)", idmef.Get("alert.target"))
-                ca.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-                ca.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-                ca.Set("alert.classification.text", "IP source matching Dshield database")
-                ca.Set("alert.correlation_alert.name", "IP source matching Dshield database")
-                ca.Set("alert.assessment.impact.description", "Dshield gather IP addresses tagged from firewall logs drops")
-                ca.Set("alert.assessment.impact.severity", "high")
-                ca.alert()
diff --git a/ruleset/firewall.py b/ruleset/firewall.py
deleted file mode 100644
index 9d9bc43..0000000
--- a/ruleset/firewall.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
-# Author: Yoann Vandoorselaere <[email protected]>
-#
-# This file is part of the Prewikka program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import re
-from PreludeCorrelator import context
-from PreludeCorrelator.plugins import Plugin
-
-class FirewallPlugin(Plugin):
-    def run(self, idmef):
-        source = idmef.Get("alert.source(0).node.address(0).address")
-        sport = idmef.Get("alert.source(0).service.port", 0)
-        target = idmef.Get("alert.target(0).node.address(0).address")
-        dport = idmef.Get("alert.target(0).service.port", 0)
-
-        if not source or not target:
-                return
-
-        ctxname = "FIREWALL_" + source + str(sport) + target + str(dport)
-
-        if idmef.match("alert.classification.text", re.compile("[Pp]acket [Dd]ropped|[Dd]enied")):
-                # Update context if any, removing the alert_on_expire attribute.
-                ctx = context.Context(ctxname, { "expire": 10 }, update = True)
-        else:
-                # Begins a timer for every event that contains a source and a target
-                # address which has not been matched by an observed packet denial.  If a packet
-                # denial is not observed in the next 10 seconds, an event alert is generated.
-
-                if not context.search(ctxname):
-                        ctx = context.Context(ctxname, { "expire": 10, "alert_on_expire": True })
-                        ctx.Set("alert.source", idmef.Get("alert.source"))
-                        ctx.Set("alert.target", idmef.Get("alert.target"))
-                        ctx.Set("alert.assessment", idmef.Get("alert.assessment"))
-                        ctx.Set("alert.classification", idmef.Get("alert.classification"))
-                        ctx.Set("alert.correlation_alert.name", "Events to firewall correlation")
-                        ctx.Set("alert.correlation_alert.alertident(0).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-                        ctx.Set("alert.correlation_alert.alertident(0).alertident", idmef.Get("alert.messageid"))
diff --git a/ruleset/openssh-multiple-authtypes.py b/ruleset/openssh-multiple-authtypes.py
deleted file mode 100644
index 1b98a29..0000000
--- a/ruleset/openssh-multiple-authtypes.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
-# Author: Sebastien Tricaud <[email protected]>
-# Author: Yoann Vandoorselaere <[email protected]>
-#
-# This file is part of the Prelude-Correlator program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-from PreludeCorrelator.plugins import Plugin
-from PreludeCorrelator.context import Context
-
-
-class OpenSSHMultipleAuthTypesPlugin(Plugin):
-    def run(self, idmef):
-        if idmef.Get("alert.analyzer(-1).manufacturer") != "OpenSSH":
-                return
-
-        if idmef.Get("alert.assessment.impact.completion") != "succeeded":
-                return
-
-        try:
-                idx = idmef.Get("alert.additional_data(*).meaning").index("Authentication method")
-        except:
-                return
-
-        data = idmef.Get("alert.additional_data(%d).data" % idx)
-
-        for username in idmef.Get("alert.target(*).user.user_id(*).name"):
-            for target in idmef.Get("alert.target(*).node.address(*).address"):
-                ctx = Context("SSH_MAT_" + target + username, {"threshold": 1}, update = True)
-                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-
-                if not hasattr(ctx, "authtype"):
-                    ctx.authtype = data
-                elif ctx.authtype != data:
-                    ctx.Set("alert.classification.text", "Multiple authentication methods")
-                    ctx.Set("alert.correlation_alert.name", "Multiple authentication methods")
-                    ctx.Set("alert.assessment.impact.severity", "medium")
-                    ctx.Set("alert.assessment.impact.description", "Multiple ways of authenticating a single user have been found over SSH. If passphrase is the only allowed method, make sure you disable passwords.")
-                    ctx.alert()
-                    ctx.destroy()
diff --git a/ruleset/scan.py b/ruleset/scan.py
deleted file mode 100644
index cf8bc10..0000000
--- a/ruleset/scan.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (C) 2006 G Ramon Gomez <gene at gomezbrothers dot com>
-# Copyright (C) 2009 PreludeIDS Technologies <[email protected]>
-#
-# This file is part of the Prelude-Correlator program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# Detect Eventscan:
-# Playing multiple events from a single host against another single host
-
-from PreludeCorrelator.context import Context
-from PreludeCorrelator.plugins import Plugin
-
-class EventScanPlugin(Plugin):
-    def run(self, idmef):
-        source = idmef.Get("alert.source(*).node.address(*).address")
-        target = idmef.Get("alert.target(*).node.address(*).address")
-
-        if not source or not target:
-            return
-
-        for saddr in source:
-            for daddr in target:
-                ctx = Context("SCAN_EVENTSCAN_" + saddr + daddr, { "expire": 60, "threshold": 30 }, update = True)
-                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-
-                if ctx.CheckAndDecThreshold():
-                    ctx.Set("alert.correlation_alert.name", "A single host has played many events against a single target. This may be a vulnerability scan")
-                    ctx.Set("alert.classification.text", "Eventscan")
-                    ctx.Set("alert.assessment.impact.severity", "high")
-                    ctx.alert()
-                    ctx.destroy()
-
-
-# Detect Eventsweep:
-# Playing the same event from a single host against multiple hosts
-class EventSweepPlugin(Plugin):
-    def run(self, idmef):
-        classification = idmef.Get("alert.classification.text")
-        source = idmef.Get("alert.source(*).node.address(*).address")
-        target = idmef.Get("alert.target(*).node.address(*).address")
-
-        if not source or not target or not classification:
-            return
-
-        for saddr in source:
-            ctx = Context("SCAN_EVENTSWEEP_" + classification + saddr, { "expire": 60, "threshold": 30 }, update = True)
-            insert = True
-
-            cur = ctx.Get("alert.target(*).node.address(*).address")
-            if cur:
-                for address in target:
-                    if address in cur:
-                        insert = False
-                        break
-
-            if insert:
-                ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-                ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-                ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-                ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-
-                if ctx.CheckAndDecThreshold():
-                    ctx.Set("alert.correlation_alert.name", "A single host has played the same event against multiple targets. This may be a network scan for a specific vulnerability")
-                    ctx.Set("alert.classification.text", "Eventsweep")
-                    ctx.Set("alert.assessment.impact.severity", "high")
-                    ctx.alert()
-                    ctx.destroy()
-
-
-
-
-# Detect Eventstorm:
-# Playing excessive events by a single host
-class EventStormPlugin(Plugin):
-    def run(self, idmef):
-        source = idmef.Get("alert.source(*).node.address(*).address")
-        if not source:
-            return
-
-        for saddr in source:
-            ctx = Context("SCAN_EVENTSTORM_" + saddr, { "expire": 120, "threshold": 150 }, update = True)
-
-            ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-            ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-            ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-            ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-
-            if ctx.CheckAndDecThreshold():
-                ctx.Set("alert.correlation_alert.name", "A single host is producing an unusual amount of events")
-                ctx.Set("alert.classification.text", "Eventstorm")
-                ctx.Set("alert.assessment.impact.severity", "high")
-                ctx.alert()
-                ctx.destroy()
-
diff --git a/ruleset/worm.py b/ruleset/worm.py
deleted file mode 100644
index 15fcd64..0000000
--- a/ruleset/worm.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) 2006 G Ramon Gomez <gene at gomezbrothers dot com>
-# Copyright (C) 2009 PreludeIDS Technologies <[email protected]>
-# All Rights Reserved.
-#
-# This file is part of the Prelude-Correlator program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# This rule looks for events against a host, records the messageid, then sets
-# a timer of 600 seconds.   If the host then replays the event against
-# other hosts multiple times, an event is generated.
-
-from PreludeCorrelator import context
-from PreludeCorrelator.plugins import Plugin
-
-class WormPlugin(Plugin):
-    def run(self, idmef):
-        ctxt = idmef.Get("alert.classification.text")
-        if not ctxt:
-            return
-
-        # Create context for classification combined with all the target.
-        for target in idmef.Get("alert.target(*).node.address(*).address"):
-            ctx = context.Context("WORM_HOST_" + ctxt + target, { "expire": 300, "threshold": 5 }, update = True)
-
-        for source in idmef.Get("alert.source(*).node.address(*).address"):
-            # We are trying to see whether a previous target is now attacking other hosts
-            # thus, we check whether a context exist with this classification combined to
-            # this source.
-            ctx = context.search("WORM_HOST_" + ctxt + source)
-            if not ctx:
-                continue
-
-            ctx.Set("alert.source(>>)", idmef.Get("alert.source"))
-            ctx.Set("alert.target(>>)", idmef.Get("alert.target"))
-            ctx.Set("alert.correlation_alert.alertident(>>).alertident", idmef.Get("alert.messageid"))
-            ctx.Set("alert.correlation_alert.alertident(-1).analyzerid", idmef.Get("alert.analyzer(*).analyzerid")[-1])
-
-            # Increase and check the context threshold.
-            if ctx.CheckAndDecThreshold():
-                ctx.Set("alert.classification.text", "Possible Worm Activity")
-                ctx.Set("alert.correlation_alert.name", "Source host repeating actions taken against it recently")
-                ctx.Set("alert.assessment.impact.severity", "high")
-                ctx.Set("alert.assessment.impact.description", source + " has repeated actions taken against it recently at least 5 times. It may have been infected with a worm.")
-                ctx.alert()
-                ctx.destroy()
diff --git a/scripts/prelude-correlator b/scripts/prelude-correlator
deleted file mode 100755
index 94b1c98..0000000
--- a/scripts/prelude-correlator
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2009 PreludeIDS Technologies. All Rights Reserved.
-# Author: Yoann Vandoorselaere <[email protected]>
-#
-# This file is part of the Prewikka program.
-#
-# 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, 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; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import sys, os, time, signal
-from PreludeCorrelator import idmef, plugins, context, siteconfig
-from optparse import OptionParser
-from PreludeEasy import ClientEasy, CheckVersion
-
-if not CheckVersion(siteconfig.libprelude_required_version):
-        raise Exception, ("Libprelude version '%s' is required" % siteconfig.libprelude_required_version)
-
-class PreludeClient:
-        def __init__(self, print_input=None, print_output=None, dry_run=False):
-                self._message_processed = 0
-                self._alert_generated = 0
-                self._print_input = print_input
-                self._print_output = print_output
-                self._continue = True
-                self._dry_run = dry_run
-
-                self._pm = plugins.PluginManager()
-                print ("%d plugin have been loaded." % (self._pm.getPluginCount()))
-
-                self._client = ClientEasy("prelude-correlator", ClientEasy.PERMISSION_IDMEF_READ|ClientEasy.PERMISSION_IDMEF_WRITE,
-                                          "Prelude-Correlator", "Correlator", "PreludeIDS Technologies", siteconfig.version)
-                self._client.Start()
-
-
-        def _handle_event(self, idmef):
-                if self._print_input:
-                        self._print_input.write(str(idmef))
-
-                self._pm.run(idmef)
-                self._message_processed += 1
-
-        def stats(self):
-                print("%d message received, %d correlationAlert generated." % (self._message_processed, self._alert_generated))
-
-        def correlationAlert(self, idmef):
-                self._alert_generated = self._alert_generated + 1
-
-                if not self._dry_run:
-                        self._client.SendIDMEF(idmef)
-
-                if self._print_output:
-                        self._print_output.write(str(idmef))
-
-        def recvEvent(self):
-                msg = idmef.IDMEF()
-
-                last = time.time()
-                while self._continue:
-                        try:
-                            r = self._client.RecvIDMEF(msg, 1000)
-                        except:
-                                r = 0
-
-                        if r:
-                                if msg.Get("alert.create_time"):
-                                        self._handle_event(msg)
-                                msg.reset()
-
-                        now = time.time()
-                        if now - last >= 1:
-                                context.wakeup(now)
-                                last = now
-
-        def stop(self):
-                self._continue = False
-
-parser = OptionParser(usage="%prog", version="%%prog %s" % siteconfig.version)
-parser.add_option("-c", "--config", action="store", dest="config", type="string", help="Configuration file to use", metavar="FILE")
-parser.add_option("", "--dry-run", action="store_true", dest="dry_run", help="No report to the specified Manager will occur", default=False)
-parser.add_option("-d", "--daemon", action="store_true", dest="daemon", help="Run in daemon mode")
-parser.add_option("-P", "--pidfile", action="store", dest="pidfile", type="string", help="Write Prelude Correlator PID to specified file", metavar="FILE")
-parser.add_option("", "--print-input", action="store", dest="print_input", type="string", help="Dump alert input from manager to the specified file", metavar="FILE")
-parser.add_option("", "--print-output", action="store", dest="print_output", type="string", help="Dump alert output to the specified file", metavar="FILE")
-parser.add_option("--debug", action="store", dest="debug", type="int", help="Enable debug ouptut (optional debug level argument)", metavar="LEVEL")
-(options, args) = parser.parse_args()
-
-ifd = None
-if options.print_input:
-        if options.print_input == "-":
-                ifd = sys.stdout
-        else:
-                ifd = open(options.print_input, "w")
-
-ofd = None
-if options.print_output:
-        if options.print_output == "-":
-                ofd = sys.stdout
-        else:
-                ofd = open(options.print_output, "w")
-
-if options.daemon:
-    if os.fork():
-        os._exit(0)
-
-    os.setsid()
-    if os.fork():
-        os._exit(0)
-
-    os.umask(077)
-
-    fd = os.open('/dev/null', os.O_RDWR)
-    for i in xrange(3):
-        os.dup2(fd, i)
-
-    os.close(fd)
-    if options.pidfile:
-        open(pidfile, "w").write(str(os.getpid()))
-
-
-def handle_signal(signum, frame):
-        print 'Signal handler called with signal', signum
-        if signum == signal.SIGQUIT:
-                prelude_client.stats()
-                context.stats()
-        else:
-                prelude_client.stop()
-
-signal.signal(signal.SIGTERM, handle_signal)
-signal.signal(signal.SIGINT, handle_signal)
-signal.signal(signal.SIGQUIT, handle_signal)
-
-# restore previous context.
-context.load()
-
-prelude_client = PreludeClient(print_input=ifd, print_output=ofd, dry_run=options.dry_run)
-idmef.set_prelude_client(prelude_client)
-prelude_client.recvEvent()
-
-# save existing context
-context.save()
-
diff --git a/setup.py b/setup.py
index a231436..8f2bad1 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,11 @@
 #!/usr/bin/env python
 
-import os, glob
-from distutils.command.install import install
-from distutils.core import setup
+from ez_setup import use_setuptools
+use_setuptools()
+
+import os
+from setuptools import setup, find_packages
+from setuptools.command.install import install
 
 PRELUDE_CORRELATOR_VERSION = "0.1"
 LIBPRELUDE_REQUIRED_VERSION = "0.9.23"
@@ -23,18 +26,64 @@ class my_install(install):
         def init_siteconfig(self):
                 config = open("PreludeCorrelator/siteconfig.py", "w")
                 print >> config, "conf_dir = '%s'" % os.path.abspath(self.conf_prefix)
-                print >> config, "ruleset_dir = '%s'" % os.path.abspath(self.conf_prefix + "/ruleset")
                 print >> config, "lib_dir = '%s'" % os.path.abspath(self.prefix + "/var/lib/prelude-correlator")
-                print >> config, "version = '%s'" % PRELUDE_CORRELATOR_VERSION
                 print >> config, "libprelude_required_version = '%s'" % LIBPRELUDE_REQUIRED_VERSION
                 config.close()
 
-setup(name="prelude-corelator",
-      version=PRELUDE_CORRELATOR_VERSION,
-      maintainer = "Yoann Vandoorselaere",
-      maintainer_email = "[email protected]",
-      url = "http://www.prelude-ids.com",
-      packages=[ 'PreludeCorrelator'],
-      data_files=[('etc/prelude-correlator/ruleset', glob.glob("ruleset/*.py"))],
-      scripts=[ "scripts/prelude-correlator" ],
-      cmdclass={ 'install': my_install })
+
+setup(
+        name="prelude-correlator",
+        version=PRELUDE_CORRELATOR_VERSION,
+        maintainer = "Yoann Vandoorselaere",
+        maintainer_email = "[email protected]",
+        author = "Yoann Vandoorselaere",
+        author_email = "[email protected]",
+        url = "http://www.prelude-ids.com",
+        download_url = "http://www.prelude-ids.com/development/download/",
+        description = "Prelude-Correlator perform real time correlation of events received by Prelude",
+        long_description = """
+Prelude-Correlator perform real time correlation of events received by Prelude.
+
+Several isolated alerts, generated from different sensors, can thus
+trigger a single CorrelationAlert should the events be related. This
+CorrelationAlert then appears within the Prewikka interface and
+indicates the potential target information via the set of correlation
+rules.
+
+Signature creation with Prelude-Correlator is based on the Python
+programming language. Prelude's integrated correlation engine is
+distributed with a default set of correlation rules, yet you still
+have the opportunity to modify and create any correlation rule that
+suits your needs.
+""",
+        classifiers = [ "Development Status :: 4 - Beta",
+                        "Environment :: Console",
+                        "Intended Audience :: System Administrators",
+                        "License :: OSI Approved :: GNU General Public License (GPL)",
+                        "Natural Language :: English",
+                        "Operating System :: OS Independent",
+                        "Programming Language :: Python",
+                        "Topic :: Security",
+                        "Topic :: System :: Monitoring" ],
+
+        packages = find_packages(),
+        entry_points = {
+                'console_scripts': [
+                        'prelude-correlator = PreludeCorrelator.main:main',
+                ],
+
+                'PreludeCorrelator.plugins': [
+                        'BruteForcePlugin = PreludeCorrelator.plugins.bruteforce:BruteForcePlugin',
+                        'BusinessHourPlugin = PreludeCorrelator.plugins.businesshour:BusinessHourPlugin',
+                        'DshieldPlugin = PreludeCorrelator.plugins.dshield:DshieldPlugin',
+                        'FirewallPlugin = PreludeCorrelator.plugins.firewall:FirewallPlugin',
+                        'OpenSSHAuthPlugin = PreludeCorrelator.plugins.opensshauth:OpenSSHAuthPlugin',
+                        'EventScanPlugin = PreludeCorrelator.plugins.scan:EventScanPlugin',
+                        'EventStormPlugin = PreludeCorrelator.plugins.scan:EventStormPlugin',
+                        'EventSweepPlugin = PreludeCorrelator.plugins.scan:EventSweepPlugin',
+                        'WormPlugin = PreludeCorrelator.plugins.worm:WormPlugin'
+                ]
+        },
+
+        cmdclass = { 'install': my_install }
+)
_______________________________________________
Prelude-cvslog site list
[email protected]
http://lists.prelude-ids.org/mailman/listinfo/prelude-cvslog