summaryrefslogtreecommitdiffstats
path: root/peekaboo/ruleset/rules.py
diff options
context:
space:
mode:
Diffstat (limited to 'peekaboo/ruleset/rules.py')
-rw-r--r--peekaboo/ruleset/rules.py104
1 files changed, 86 insertions, 18 deletions
diff --git a/peekaboo/ruleset/rules.py b/peekaboo/ruleset/rules.py
index 6635c0c..36daa1c 100644
--- a/peekaboo/ruleset/rules.py
+++ b/peekaboo/ruleset/rules.py
@@ -29,6 +29,8 @@
import re
import logging
from peekaboo.ruleset import Result, RuleResult
+from peekaboo.ruleset.expressions import ExpressionParser, \
+ IdentifierMissingException
from peekaboo.exceptions import PeekabooAnalysisDeferred, \
CuckooSubmitFailedException, PeekabooRulesetConfigError
from peekaboo.toolbox.ole import Oletools, OletoolsReport, \
@@ -104,6 +106,33 @@ class Rule(object):
return self.config.get_by_type(
self.rule_name, option, fallback=default, option_type=option_type)
+ def get_cuckoo_report(self, sample):
+ """ Get the samples cuckoo_report or submit the sample for analysis by
+ Cuckoo.
+
+ @returns: CuckooReport
+ """
+ report = sample.cuckoo_report
+ if report is not None:
+ return report
+
+ try:
+ job_id = sample.submit_to_cuckoo()
+ except CuckooSubmitFailedException as failed:
+ logger.error("Submit to Cuckoo failed: %s", failed)
+ # exception message intentionally not present in message
+ # delivered back to client as to not disclose internal
+ # information, should request user to contact admin instead
+ return self.result(
+ Result.failed,
+ _("Behavioral analysis by Cuckoo has produced an error "
+ "and did not finish successfully"),
+ False)
+
+ logger.info('Sample submitted to Cuckoo. Job ID: %s. '
+ 'Sample: %s', job_id, sample)
+ raise PeekabooAnalysisDeferred()
+
class KnownRule(Rule):
""" A rule determining if a sample is known by looking at the database for
@@ -293,24 +322,7 @@ class CuckooRule(Rule):
@raises PeekabooAnalysisDeferred: if the sample was submitted to Cuckoo
@returns: RuleResult containing verdict.
"""
- report = sample.cuckoo_report
- if report is None:
- try:
- job_id = sample.submit_to_cuckoo()
- except CuckooSubmitFailedException as failed:
- logger.error("Submit to Cuckoo failed: %s", failed)
- # exception message intentionally not present in message
- # delivered back to client as to not disclose internal
- # information, should request user to contact admin instead
- return self.result(
- Result.failed,
- _("Behavioral analysis by Cuckoo has produced an error "
- "and did not finish successfully"),
- False)
-
- logger.info('Sample submitted to Cuckoo. Job ID: %s. '
- 'Sample: %s', job_id, sample)
- raise PeekabooAnalysisDeferred()
+ report = self.get_cuckoo_report(sample)
# call report evaluation function if we get here
return self.evaluate_report(report)
@@ -467,6 +479,62 @@ class CuckooAnalysisFailedRule(CuckooRule):
return self.result(Result.failed, failure_reason, False)
+class ExpressionRule(Rule):
+ """ A rule checking the sample and cuckoo report against an almost
+ arbitrary logical expression. """
+ rule_name = 'expressions'
+
+ def get_config(self):
+ expressions = self.get_config_value('expression', [])
+ if not expressions:
+ raise PeekabooRulesetConfigError(
+ "List of expressions empty, check %s rule config."
+ % self.rule_name)
+
+ self.rules = []
+ parser = ExpressionParser()
+ for expr in expressions:
+ try:
+ rule = parser.parse(expr)
+ logger.debug("EXPR: %s", expr)
+ logger.debug("RULE: %s", rule)
+ self.rules.append(rule)
+ except SyntaxError as error:
+ raise PeekabooRulesetConfigError(error)
+
+ def evaluate(self, sample):
+ """ Match what rules report against our known result status names. """
+ for rule in self.rules:
+ result = None
+ context = {'variables': {'sample': sample}}
+
+ while result is None:
+ try:
+ result = rule.eval(context = context)
+ # otherwise this is an endless loop
+ if result is None:
+ break
+ except IdentifierMissingException as error:
+ if error.message == "cuckooreport":
+ context['variables']['cuckooreport'] = self.get_cuckoo_report(sample)
+ # here elif for other reports
+ else:
+ return self.result(
+ Result.failed,
+ _("Evaluation of expression uses undefined identifier."),
+ False)
+
+ if result:
+ return self.result(result,
+ _("A rule classified the sample as %s")
+ % result,
+ False)
+
+ return self.result(Result.unknown,
+ _("No rule classified the sample in any way."),
+ True)
+
+
class FinalRule(Rule):
""" A catch-all rule. """
rule_name = 'final_rule'