prelude-correlator/master: Context class improvement: overwrite, and new update method
[email protected] Sat, 16 Jan 2010 17:24:06 +0100 (CET)
| Newsgroups | gmane.comp.security.ids.prelude.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit 09ba679044b70608144e24b01dae982011469682 Author: Yoann Vandoorselaere <[email protected]> Date: Sat Jan 16 16:51:41 2010 +0100 Context class improvement: overwrite, and new update method Context initialization now take an optional 'overwrite' argument. This argument, if set to False, mean that the Context() will be returned un-modified if it already exist. If it doesn't, it will be created. There is now a new update() method, which provide exactly the same functionality as calling Context() with the 'update=True' argument. This is useful since some plugin might want to defer an update to another place in the code. Remove CheckAndDecThreshold() method. This function can be replaced by using Context.update() along with the Context.getUpdateCount() method. [Scan]: Update to the new Context API (removal of CheckAndDecThreshold). Improve the plugin so that it report CorrelationAlert after the timer expire, not after the threshold is reached. ======================================== PreludeCorrelator/context.py | 79 +++++++++++++++++++++--------------- PreludeCorrelator/plugins/scan.py | 33 +++++---------- 2 files changed, 57 insertions(+), 55 deletions(-) ======================================== diff --git a/PreludeCorrelator/context.py b/PreludeCorrelator/context.py index 82978bf..f2d8853 100644 --- a/PreludeCorrelator/context.py +++ b/PreludeCorrelator/context.py @@ -79,65 +79,78 @@ class Context(IDMEF, Timer): Timer.__setstate__(self, dict) IDMEF.__setstate__(self, dict) - def __init__(self, name, options={}, update=False, idmef=None): - is_update = update and hasattr(self, "_name") - if is_update is False: - self._options = { "threshold": -1, "expire": 0, "alert_on_expire": False } - IDMEF.__init__(self) - Timer.__init__(self, 0) - - self._options.update(options) - self.setOptions(self._options) - - if is_update is True: + def __init__(self, name, options={}, overwrite=True, update=False, idmef=None): + already_initialized = (update or (overwrite is False)) and hasattr(self, "_name") + if already_initialized is True: return + self._options = { "threshold": -1, "expire": 0, "alert_on_expire": False } + IDMEF.__init__(self) + Timer.__init__(self, 0) + self._name = name self._update_count = 0 - self._threshold_count = 0 + + if _CONTEXT_TABLE.has_key(name): # Make sure any timer is deleted on overwrite + _CONTEXT_TABLE[name].destroy() + _CONTEXT_TABLE[name] = self + self._options.update(options) + self.setOptions(self._options) + if idmef: self.addAlertReference(idmef) - def __new__(cls, name, options={}, update=False, idmef=None): - if update: + def __new__(cls, name, options={}, overwrite=True, update=False, idmef=None): + if update or (overwrite is False): ctx = search(name) if ctx: - ctx._update_count += 1 - if idmef: - ctx.addAlertReference(idmef) - - if ctx.running(): - ctx.reset() + if update: + ctx.update(options, idmef) + return ctx - return ctx + if overwrite is False: + return ctx return super(Context, cls).__new__(cls) - def CheckAndDecThreshold(self): - self._threshold_count += 1 - if self._threshold_count == self._options["threshold"]: - return True - else: - return False - def _timerExpireCallback(self): + threshold = self._options["threshold"] alert_on_expire = self._options["alert_on_expire"] + if alert_on_expire: + if threshold == -1 or (self._update_count + 1) >= threshold: if callable(alert_on_expire): alert_on_expire(self) + return else: self.alert() self.destroy() + def update(self, options={}, idmef=None): + self._update_count += 1 + + if idmef: + self.addAlertReference(idmef) + + if self.running(): + self.reset() + + self._options.update(options) + self.setOptions(self._options) + def stats(self, log_func, now=time.time()): - if not self._timer_start: - log_func("[%s]: threshold=%d/%d update=%d" % (self._name, self._threshold_count, self._options["threshold"], self._update_count)) - else: - log_func("[%s]: threshold=%d/%d update=%d expire=%d/%d" % (self._name, self._threshold_count, self._options["threshold"], - self._update_count, self.elapsed(now), self._options["expire"])) + str = "" + + if self._options["threshold"] != -1: + str += " threshold=%d/%d" % (self._update_count + 1, self._options["threshold"]) + + if self._timer_start: + str += " expire=%d/%d" % (self.elapsed(now), self._options["expire"]) + + log_func("[%s]: update=%d%s" % (self._name, self._update_count, str)) def getOptions(self): return self._options diff --git a/PreludeCorrelator/plugins/scan.py b/PreludeCorrelator/plugins/scan.py index 8f24600..9246689 100644 --- a/PreludeCorrelator/plugins/scan.py +++ b/PreludeCorrelator/plugins/scan.py @@ -33,13 +33,11 @@ class EventScanPlugin(Plugin): for saddr in source: for daddr in target: - ctx = Context("SCAN_EVENTSCAN_" + saddr + daddr, { "expire": 60, "threshold": 30 }, update = True, idmef=idmef) - if ctx.CheckAndDecThreshold(): + ctx = Context("SCAN_EVENTSCAN_" + saddr + daddr, { "expire": 60, "threshold": 30, "alert_on_expire": True }, update = True, idmef=idmef) + if ctx.getUpdateCount() == 0: 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: @@ -54,27 +52,20 @@ class EventSweepPlugin(Plugin): return for saddr in source: - ctx = Context("SCAN_EVENTSWEEP_" + classification + saddr, { "expire": 60, "threshold": 30 }, update = True) - insert = True + ctx = Context("SCAN_EVENTSWEEP_" + classification + saddr, { "expire": 60, "threshold": 30, "alert_on_expire": True }, overwrite = False) + if ctx.getUpdateCount() == 0: + 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") cur = ctx.Get("alert.target(*).node.address(*).address") if cur: for address in target: if address in cur: insert = False - break - - if insert: - ctx.addAlertReference(idmef) - - 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() - + return + ctx.update(idmef=idmef) # Detect Eventstorm: @@ -86,11 +77,9 @@ class EventStormPlugin(Plugin): return for saddr in source: - ctx = Context("SCAN_EVENTSTORM_" + saddr, { "expire": 120, "threshold": 150 }, update = True, idmef = idmef) - if ctx.CheckAndDecThreshold(): + ctx = Context("SCAN_EVENTSTORM_" + saddr, { "expire": 120, "threshold": 150, "alert_on_expire": True }, update = True, idmef = idmef) + if ctx.getUpdateCount() == 0: 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() _______________________________________________ Prelude-cvslog site list [email protected] http://lists.prelude-ids.org/mailman/listinfo/prelude-cvslog