render: implement default renderer

This commit is contained in:
William Ballenthin
2020-06-27 09:05:43 -06:00
parent 135329ed1d
commit 1ea9b6e1e8
3 changed files with 73 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
import json
import capa.engine
import capa.render.default
def convert_statement_to_result_document(statement):
@@ -247,7 +248,7 @@ def render_verbose(rules, capabilities):
def render_default(rules, capabilities):
doc = convert_capabilities_to_result_document(rules, capabilities)
return ''
return capa.render.default.render_default(doc)
class CapaJsonObjectEncoder(json.JSONEncoder):

69
capa/render/default.py Normal file
View File

@@ -0,0 +1,69 @@
import collections
import six
import tabulate
import termcolor
def bold(s):
"""draw attention to the given string"""
return termcolor.colored(s, 'blue')
def render_capabilities(doc, ostream):
rows = []
for (namespace, name, rule) in sorted(map(lambda rule: (rule['meta']['namespace'], rule['meta']['name'], rule), doc.values())):
if rule['meta'].get('lib'):
continue
if rule['meta'].get('capa/subscope'):
continue
rows.append((bold(name), namespace))
ostream.write(tabulate.tabulate(rows, headers=['CAPABILITY', 'NAMESPACE'], tablefmt="psql"))
ostream.write("\n")
def render_attack(doc, ostream):
tactics = collections.defaultdict(set)
for rule in doc.values():
if rule['meta'].get('lib'):
continue
if rule['meta'].get('capa/subscope'):
continue
if not rule['meta'].get('att&ck'):
continue
for attack in rule['meta']['att&ck']:
tactic, _, rest = attack.partition('::')
if '::' in rest:
technique, _, rest = rest.partition('::')
subtechnique, _, id = rest.rpartition(' ')
tactics[tactic].add((technique, subtechnique, id))
else:
technique, _, id = rest.rpartition(' ')
tactics[tactic].add((technique, id))
for tactic, techniques in sorted(tactics.items()):
rows = []
for spec in sorted(techniques):
if len(spec) == 2:
technique, id = spec
rows.append(("%s %s" % (bold(technique), id), ))
elif len(spec) == 3:
technique, subtechnique, id = spec
rows.append(("%s::%s %s" % (bold(technique), subtechnique, id), ))
else:
raise RuntimeError("unexpected ATT&CK spec format")
ostream.write(tabulate.tabulate(rows, headers=['ATT&CK tactic: ' + bold(tactic.upper())], tablefmt="psql"))
ostream.write("\n")
def render_default(doc):
ostream = six.StringIO()
render_attack(doc, ostream)
ostream.write("\n")
render_capabilities(doc, ostream)
return ostream.getvalue()

View File

@@ -9,6 +9,8 @@ requirements = [
"tqdm",
"pyyaml",
"tabulate",
"colorama",
"termcolor",
"ruamel.yaml"
]