summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Bauer <jack@ai4me.de>2019-10-01 17:33:39 +0200
committerGitHub <noreply@github.com>2019-10-01 17:33:39 +0200
commitbaab4937eff80e950db33a080790ad4b2a45b99d (patch)
treebb1c43e5c763e4829c7f200766357da0512a02c5
parent778ff1931b793292c8fcdcc921dda76d92626524 (diff)
Add olereport to expression context (#100)
olereport can now be used in expressions Before oletools was only a separate rule. Now has_office_macro and vba_code can be used in generic rule expressions.
-rw-r--r--docs/source/ruleset.rst11
-rw-r--r--peekaboo/locale/de/LC_MESSAGES/peekaboo.mobin4392 -> 4743 bytes
-rw-r--r--peekaboo/locale/de/LC_MESSAGES/peekaboo.po77
-rw-r--r--peekaboo/locale/peekaboo.pot73
-rw-r--r--peekaboo/ruleset/rules.py29
-rw-r--r--peekaboo/toolbox/ole.py19
-rw-r--r--ruleset.conf.sample2
-rwxr-xr-xtests/test.py59
8 files changed, 194 insertions, 76 deletions
diff --git a/docs/source/ruleset.rst b/docs/source/ruleset.rst
index 46d4bd9..bca63d8 100644
--- a/docs/source/ruleset.rst
+++ b/docs/source/ruleset.rst
@@ -60,6 +60,9 @@ Rules can then be constructed like:
'application/x-pkcs7-mime'
} -> ignore
expression.3 : /DDE/ in cuckooreport.signature_descriptions -> bad
+ expression.4 : /suspicious/ in olereport.vba_code -> bad
+ expression.5 : olereport.has_office_macros == True
+ and cuckooreport.score > 4 -> bad
Attributes of sample
--------------------
@@ -86,3 +89,11 @@ Attributes of cuckooreport
score
errors
cuckoo_server_messages
+
+Attributes of olereport
+-----------------------
+
+.. code-block:: shell
+
+ has_office_macro
+ vba_code
diff --git a/peekaboo/locale/de/LC_MESSAGES/peekaboo.mo b/peekaboo/locale/de/LC_MESSAGES/peekaboo.mo
index af5a962..c7ba71f 100644
--- a/peekaboo/locale/de/LC_MESSAGES/peekaboo.mo
+++ b/peekaboo/locale/de/LC_MESSAGES/peekaboo.mo
Binary files differ
diff --git a/peekaboo/locale/de/LC_MESSAGES/peekaboo.po b/peekaboo/locale/de/LC_MESSAGES/peekaboo.po
index 77ab127..f5022ba 100644
--- a/peekaboo/locale/de/LC_MESSAGES/peekaboo.po
+++ b/peekaboo/locale/de/LC_MESSAGES/peekaboo.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PeekabooAV 1.6.2\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2019-08-20 10:35+0200\n"
+"POT-Creation-Date: 2019-09-09 11:18+0200\n"
"PO-Revision-Date: 2019-02-14 22:02+0000\n"
"Last-Translator: Michael Weiser <michael.weiser@gmx.de>\n"
"Language: de\n"
@@ -36,7 +36,7 @@ msgstr "Die Datei \"%s\" wird als \"%s\" betrachtet"
msgid "File \"%s\": %s"
msgstr "Datei \"%s\": %s"
-#: peekaboo/sample.py:497
+#: peekaboo/sample.py:478
#, python-format
msgid "Sample %s successfully submitted to Cuckoo as job %d"
msgstr "Erfolgreich an Cuckoo gegeben %s als Job %d"
@@ -100,65 +100,73 @@ msgstr "Ja"
msgid "No"
msgstr "Nein"
-#: peekaboo/ruleset/engine.py:147
+#: peekaboo/ruleset/engine.py:148
msgid "Rule aborted with error"
msgstr "Regel mit Fehler abgebrochen"
-#: peekaboo/ruleset/rules.py:122
+#: peekaboo/ruleset/rules.py:128 peekaboo/ruleset/rules.py:470
+msgid ""
+"Behavioral analysis by Cuckoo has produced an error and did not finish "
+"successfully"
+msgstr ""
+"Die Verhaltensanalyse durch Cuckoo hat einen Fehler produziert und konnte"
+" nicht erfolgreich abgeschlossen werden"
+
+#: peekaboo/ruleset/rules.py:164
msgid "File is not yet known to the system"
msgstr "Datei ist dem System noch nicht bekannt"
-#: peekaboo/ruleset/rules.py:143
+#: peekaboo/ruleset/rules.py:185
#, python-format
msgid "Failure to determine sample file size: %s"
msgstr "Ermittlung der Dateigröße fehlgeschlagen: %s"
-#: peekaboo/ruleset/rules.py:148
+#: peekaboo/ruleset/rules.py:190
#, python-format
msgid "File has more than %d bytes"
msgstr "Datei hat mehr als %d bytes"
-#: peekaboo/ruleset/rules.py:154
+#: peekaboo/ruleset/rules.py:196
#, python-format
msgid "File is only %d bytes long"
msgstr "Die Datei ist nur %d bytes groß"
-#: peekaboo/ruleset/rules.py:176
+#: peekaboo/ruleset/rules.py:218
msgid "File type is on whitelist"
msgstr "Dateityp ist auf Whitelist"
-#: peekaboo/ruleset/rules.py:180
+#: peekaboo/ruleset/rules.py:222
msgid "File type is not on whitelist"
msgstr "Dateityp ist nicht auf Whitelist"
-#: peekaboo/ruleset/rules.py:202
+#: peekaboo/ruleset/rules.py:244
msgid "File type is on the list of types to analyze"
msgstr "Dateityp ist auf der Liste der zu analysiserenden Typen"
-#: peekaboo/ruleset/rules.py:207
+#: peekaboo/ruleset/rules.py:249
#, python-format
msgid "File type is not on the list of types to analyse (%s)"
msgstr "Dateityp ist nicht auf der Liste der zu analysierenden Typen (%s)"
-#: peekaboo/ruleset/rules.py:223
+#: peekaboo/ruleset/rules.py:265
msgid "File is not an office document"
msgstr "Die Datei ist kein Office Dokument"
-#: peekaboo/ruleset/rules.py:247
+#: peekaboo/ruleset/rules.py:289
msgid "The file contains an Office macro"
msgstr "Die Datei beinhaltet ein Office-Makro"
-#: peekaboo/ruleset/rules.py:251
+#: peekaboo/ruleset/rules.py:293
msgid "The file does not contain a recognizable Office macro"
msgstr "Die Datei beinhaltet kein erkennbares Office-Makro"
-#: peekaboo/ruleset/rules.py:272
+#: peekaboo/ruleset/rules.py:314
msgid "The file contains an Office macro which runs at document open"
msgstr ""
"Die Datei beinhaltet ein Office Makro welches beim Öffnen der Datei "
"ausgeführt wird"
-#: peekaboo/ruleset/rules.py:277
+#: peekaboo/ruleset/rules.py:319
msgid ""
"The file does not contain a recognizable Office macro that is run at "
"document open"
@@ -166,49 +174,54 @@ msgstr ""
"Die Datei beinhaltet kein erkennbares Office Makro welches beim Öffnen "
"ausgeführt wird"
-#: peekaboo/ruleset/rules.py:307 peekaboo/ruleset/rules.py:445
-msgid ""
-"Behavioral analysis by Cuckoo has produced an error and did not finish "
-"successfully"
-msgstr ""
-"Die Verhaltensanalyse durch Cuckoo hat einen Fehler produziert und konnte"
-" nicht erfolgreich abgeschlossen werden"
-
-#: peekaboo/ruleset/rules.py:365
+#: peekaboo/ruleset/rules.py:390
msgid "No signature suggesting malware detected"
msgstr "Keine Signatur erkannt die auf Schadcode hindeutet"
-#: peekaboo/ruleset/rules.py:370
+#: peekaboo/ruleset/rules.py:395
#, python-format
msgid "The following signatures have been recognized: %s"
msgstr "Folgende Signaturen wurden erkannt: %s"
-#: peekaboo/ruleset/rules.py:389
+#: peekaboo/ruleset/rules.py:414
#, python-format
msgid "Cuckoo score >= %s: %s"
msgstr ""
-#: peekaboo/ruleset/rules.py:394
+#: peekaboo/ruleset/rules.py:419
#, python-format
msgid "Cuckoo score < %s: %s"
msgstr ""
-#: peekaboo/ruleset/rules.py:418
+#: peekaboo/ruleset/rules.py:443
#, python-format
msgid "The file attempts to contact at least one domain on the blacklist (%s)"
msgstr ""
"Die Datei versucht mindestens eine Domain aus der Blacklist zu "
"kontaktieren (%s)"
-#: peekaboo/ruleset/rules.py:424
+#: peekaboo/ruleset/rules.py:449
msgid "File does not seem to attempt contact with domains on the blacklist"
msgstr "Datei scheint keine Domains aus der Blacklist kontaktieren zu wollen"
-#: peekaboo/ruleset/rules.py:461
+#: peekaboo/ruleset/rules.py:486
msgid "Behavioral analysis by Cuckoo completed successfully"
msgstr "Die Verhaltensanalyse durch Cuckoo wurde erfolgreich abgeschlossen"
-#: peekaboo/ruleset/rules.py:478
+#: peekaboo/ruleset/rules.py:539
+msgid "Evaluation of expression uses undefined identifier."
+msgstr "Auswertung des Ausdrucks nutzt nicht definierten Bezeichner."
+
+#: peekaboo/ruleset/rules.py:544
+#, python-format
+msgid "The rule (%s) classified the sample as %s"
+msgstr "Die Regel (%s) klassifizierte die Datei als %s"
+
+#: peekaboo/ruleset/rules.py:550
+msgid "No rule classified the sample in any way."
+msgstr "Keine Regel klassifizierte die Datei in irgendeiner Weise."
+
+#: peekaboo/ruleset/rules.py:562
msgid "File does not seem to exhibit recognizable malicious behaviour"
msgstr "Datei scheint keine erkennbaren Schadroutinen zu starten"
diff --git a/peekaboo/locale/peekaboo.pot b/peekaboo/locale/peekaboo.pot
index 085c447..e1b3f34 100644
--- a/peekaboo/locale/peekaboo.pot
+++ b/peekaboo/locale/peekaboo.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2019-08-20 10:35+0200\n"
+"POT-Creation-Date: 2019-09-09 11:18+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -36,7 +36,7 @@ msgstr ""
msgid "File \"%s\": %s"
msgstr ""
-#: peekaboo/sample.py:497
+#: peekaboo/sample.py:478
#, python-format
msgid "Sample %s successfully submitted to Cuckoo as job %d"
msgstr ""
@@ -99,107 +99,120 @@ msgstr ""
msgid "No"
msgstr ""
-#: peekaboo/ruleset/engine.py:147
+#: peekaboo/ruleset/engine.py:148
msgid "Rule aborted with error"
msgstr ""
-#: peekaboo/ruleset/rules.py:122
+#: peekaboo/ruleset/rules.py:128 peekaboo/ruleset/rules.py:470
+msgid ""
+"Behavioral analysis by Cuckoo has produced an error and did not finish "
+"successfully"
+msgstr ""
+
+#: peekaboo/ruleset/rules.py:164
msgid "File is not yet known to the system"
msgstr ""
-#: peekaboo/ruleset/rules.py:143
+#: peekaboo/ruleset/rules.py:185
#, python-format
msgid "Failure to determine sample file size: %s"
msgstr ""
-#: peekaboo/ruleset/rules.py:148
+#: peekaboo/ruleset/rules.py:190
#, python-format
msgid "File has more than %d bytes"
msgstr ""
-#: peekaboo/ruleset/rules.py:154
+#: peekaboo/ruleset/rules.py:196
#, python-format
msgid "File is only %d bytes long"
msgstr ""
-#: peekaboo/ruleset/rules.py:176
+#: peekaboo/ruleset/rules.py:218
msgid "File type is on whitelist"
msgstr ""
-#: peekaboo/ruleset/rules.py:180
+#: peekaboo/ruleset/rules.py:222
msgid "File type is not on whitelist"
msgstr ""
-#: peekaboo/ruleset/rules.py:202
+#: peekaboo/ruleset/rules.py:244
msgid "File type is on the list of types to analyze"
msgstr ""
-#: peekaboo/ruleset/rules.py:207
+#: peekaboo/ruleset/rules.py:249
#, python-format
msgid "File type is not on the list of types to analyse (%s)"
msgstr ""
-#: peekaboo/ruleset/rules.py:223
+#: peekaboo/ruleset/rules.py:265
msgid "File is not an office document"
msgstr ""
-#: peekaboo/ruleset/rules.py:247
+#: peekaboo/ruleset/rules.py:289
msgid "The file contains an Office macro"
msgstr ""
-#: peekaboo/ruleset/rules.py:251
+#: peekaboo/ruleset/rules.py:293
msgid "The file does not contain a recognizable Office macro"
msgstr ""
-#: peekaboo/ruleset/rules.py:272
+#: peekaboo/ruleset/rules.py:314
msgid "The file contains an Office macro which runs at document open"
msgstr ""
-#: peekaboo/ruleset/rules.py:277
+#: peekaboo/ruleset/rules.py:319
msgid ""
"The file does not contain a recognizable Office macro that is run at "
"document open"
msgstr ""
-#: peekaboo/ruleset/rules.py:307 peekaboo/ruleset/rules.py:445
-msgid ""
-"Behavioral analysis by Cuckoo has produced an error and did not finish "
-"successfully"
-msgstr ""
-
-#: peekaboo/ruleset/rules.py:365
+#: peekaboo/ruleset/rules.py:390
msgid "No signature suggesting malware detected"
msgstr ""
-#: peekaboo/ruleset/rules.py:370
+#: peekaboo/ruleset/rules.py:395
#, python-format
msgid "The following signatures have been recognized: %s"
msgstr ""
-#: peekaboo/ruleset/rules.py:389
+#: peekaboo/ruleset/rules.py:414
#, python-format
msgid "Cuckoo score >= %s: %s"
msgstr ""
-#: peekaboo/ruleset/rules.py:394
+#: peekaboo/ruleset/rules.py:419
#, python-format
msgid "Cuckoo score < %s: %s"
msgstr ""
-#: peekaboo/ruleset/rules.py:418
+#: peekaboo/ruleset/rules.py:443
#, python-format
msgid "The file attempts to contact at least one domain on the blacklist (%s)"
msgstr ""
-#: peekaboo/ruleset/rules.py:424
+#: peekaboo/ruleset/rules.py:449
msgid "File does not seem to attempt contact with domains on the blacklist"
msgstr ""
-#: peekaboo/ruleset/rules.py:461
+#: peekaboo/ruleset/rules.py:486
msgid "Behavioral analysis by Cuckoo completed successfully"
msgstr ""
-#: peekaboo/ruleset/rules.py:478
+#: peekaboo/ruleset/rules.py:539
+msgid "Evaluation of expression uses undefined identifier."
+msgstr ""
+
+#: peekaboo/ruleset/rules.py:544
+#, python-format
+msgid "The rule (%s) classified the sample as %s"
+msgstr ""
+
+#: peekaboo/ruleset/rules.py:550
+msgid "No rule classified the sample in any way."
+msgstr ""
+
+#: peekaboo/ruleset/rules.py:562
msgid "File does not seem to exhibit recognizable malicious behaviour"
msgstr ""
diff --git a/peekaboo/ruleset/rules.py b/peekaboo/ruleset/rules.py
index e5e789d..9bfae33 100644
--- a/peekaboo/ruleset/rules.py
+++ b/peekaboo/ruleset/rules.py
@@ -133,6 +133,19 @@ class Rule(object):
'Sample: %s', job_id, sample)
raise PeekabooAnalysisDeferred()
+ def get_oletools_report(self, sample):
+ """ Get the samples oletools_report or generate it.
+
+ @returns: OleReport
+ """
+ report = sample.oletools_report
+ if report is not None:
+ return report
+
+ oletool = Oletools()
+ report = OletoolsReport(oletool.get_report(sample))
+ return report
+
class KnownRule(Rule):
""" A rule determining if a sample is known by looking at the database for
@@ -271,7 +284,7 @@ class OfficeMacroRule(OleRule):
def evaluate_report(self, report):
""" Report the sample as bad if it contains a macro. """
- if report.has_office_macros():
+ if report.has_office_macros:
return self.result(Result.bad,
_("The file contains an Office macro"),
False)
@@ -485,15 +498,15 @@ class ExpressionRule(Rule):
rule_name = 'expressions'
def get_config(self):
- expressions = self.get_config_value('expression', [])
- if not expressions:
+ self.expressions = self.get_config_value('expression', [])
+ if not self.expressions:
raise PeekabooRulesetConfigError(
"List of expressions empty, check %s rule config."
% self.rule_name)
self.rules = []
parser = ExpressionParser()
- for expr in expressions:
+ for expr in self.expressions:
try:
rule = parser.parse(expr)
logger.debug("EXPR: %s", expr)
@@ -504,19 +517,21 @@ class ExpressionRule(Rule):
def evaluate(self, sample):
""" Match what rules report against our known result status names. """
- for rule in self.rules:
+ for i, rule in enumerate(self.rules):
result = None
context = {'variables': {'sample': sample}}
while result is None:
try:
- result = rule.eval(context = context)
+ result = rule.eval(context=context)
# otherwise this is an endless loop
if result is None:
break
except IdentifierMissingException as error:
- if "cuckooreport" == error.args[0]:
+ if error.args[0] == "cuckooreport":
context['variables']['cuckooreport'] = self.get_cuckoo_report(sample)
+ elif error.args[0] == "olereport":
+ context['variables']['olereport'] = self.get_oletools_report(sample)
# here elif for other reports
else:
return self.result(
diff --git a/peekaboo/toolbox/ole.py b/peekaboo/toolbox/ole.py
index e4a3ce0..b4d9eb6 100644
--- a/peekaboo/toolbox/ole.py
+++ b/peekaboo/toolbox/ole.py
@@ -77,7 +77,7 @@ class Oletools(object):
pass
except Exception as error:
logger.exception(error)
- sample.register_oletools_report(report)
+ sample.register_oletools_report(OletoolsReport(report))
return report
@@ -86,6 +86,10 @@ class OletoolsReport(object):
def __init__(self, report):
self.report = report
+ def __str__(self):
+ return "<OletoolsReport('%s'>" % self.report
+
+ @property
def has_office_macros(self):
"""
Detects macros in Microsoft Office documents.
@@ -93,12 +97,23 @@ class OletoolsReport(object):
@return: True if macros where found, otherwise False.
If VBA_Parser crashes it returns False too.
"""
-
+
try:
return self.report['has_macros']
except KeyError:
return False
+ @property
+ def vba_code(self):
+ """
+ Extracts vba code from Microsoft Office documents.
+ @return: vba code if found, otherwise empty string.
+ """
+ try:
+ return self.report['vba']
+ except KeyError:
+ return ""
+
def has_office_macros_with_suspicious_keyword(self, suspicious_keywords):
"""
Detects macros with supplied suspicious keywords in Microsoft Office documents.
diff --git a/ruleset.conf.sample b/ruleset.conf.sample
index 6b7c956..e0b2ef2 100644
--- a/ruleset.conf.sample
+++ b/ruleset.conf.sample
@@ -90,6 +90,8 @@ expression.3 : sample.meta_info_name_declared == 'signature.asc'
and sample.meta_info_type_declared in {
'application/pgp-signature'
} -> ignore
+expression.4 : olereport.has_office_macros == True
+ and cuckooreport.score > 4 -> bad
[cuckoo_evil_sig]
signature.1 : A potential heapspray has been detected. .*
diff --git a/tests/test.py b/tests/test.py
index bec3d97..6ab72b2 100755
--- a/tests/test.py
+++ b/tests/test.py
@@ -862,21 +862,21 @@ unknown : baz'''
def test_rule_ignore_mail_signatures(self):
""" Test rule to ignore cryptographic mail signatures. """
config = '''[expressions]
- expression.4 : sample.meta_info_name_declared == 'smime.p7s'
+ expression.1 : sample.meta_info_name_declared == 'smime.p7s'
and sample.meta_info_type_declared in {
'application/pkcs7-signature',
'application/x-pkcs7-signature',
'application/pkcs7-mime',
'application/x-pkcs7-mime'
} -> ignore
- expression.3 : sample.meta_info_name_declared == 'signature.asc'
+ expression.2 : sample.meta_info_name_declared == 'signature.asc'
and sample.meta_info_type_declared in {
'application/pgp-signature'
} -> ignore'''
- part = { "full_name": "p001",
- "name_declared": "smime.p7s",
- "type_declared": "application/pkcs7-signature"
+ part = {"full_name": "p001",
+ "name_declared": "smime.p7s",
+ "type_declared": "application/pkcs7-signature"
}
factory = SampleFactory(
@@ -928,6 +928,55 @@ unknown : baz'''
result = rule.evaluate(sample)
self.assertEqual(result.result, Result.bad)
+ def test_rule_expressions_cuckooreport_context(self):
+ """ Test generic rule cuckooreport context """
+ config = '''[expressions]
+ expression.3 : "EVIL" in cuckooreport.signature_descriptions
+ and cuckooreport.score > 4 -> bad
+ '''
+
+ factory = CreatingSampleFactory(
+ cuckoo=None, base_dir=None, job_hash_regex=None,
+ keep_mail_data=False, processing_info_dir=None)
+ tests_data_dir = os.path.dirname(os.path.abspath(__file__))+"/test-data"
+
+ report = {
+ "signatures": [
+ {"description": "EVIL"}
+ ],
+ "info": {"score": 4.2}
+ }
+ cuckooreport = CuckooReport(report)
+
+ sample = factory.make_sample(tests_data_dir+'/office/blank.doc')
+ sample.register_cuckoo_report(cuckooreport)
+ rule = ExpressionRule(CreatingConfigParser(config))
+ result = rule.evaluate(sample)
+ self.assertEqual(result.result, Result.bad)
+
+ def test_rule_expressions_olereport_context(self):
+ """ Test generic rule olereport context """
+ config = '''[expressions]
+ expression.3 : olereport.has_office_macros == True -> bad
+ '''
+
+ factory = CreatingSampleFactory(
+ cuckoo=None, base_dir=None, job_hash_regex=None,
+ keep_mail_data=False, processing_info_dir=None)
+ tests_data_dir = os.path.dirname(os.path.abspath(__file__))+"/test-data"
+
+ sample = factory.make_sample(tests_data_dir+'/office/suspiciousMacro.doc')
+ rule = ExpressionRule(CreatingConfigParser(config))
+ result = rule.evaluate(sample)
+ self.assertEqual(result.result, Result.bad)
+
+ config = '''[expressions]
+ expression.3 : /suspicious/ in olereport.vba_code -> bad
+ '''
+ rule = ExpressionRule(CreatingConfigParser(config))
+ result = rule.evaluate(sample)
+ self.assertEqual(result.result, Result.bad)
+
def test_config_file_type_on_whitelist(self):
""" Test whitelist rule configuration. """
config = '''[file_type_on_whitelist]