From ed12c4758ba0840e86a93beae2024a5ae088bc99 Mon Sep 17 00:00:00 2001 From: William Ballenthin Date: Sun, 28 Jun 2020 12:23:07 -0600 Subject: [PATCH] render: group ATT&CK tags in a single table --- capa/render/default.py | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/capa/render/default.py b/capa/render/default.py index 0eb5e0a7..978eb1cc 100644 --- a/capa/render/default.py +++ b/capa/render/default.py @@ -21,7 +21,7 @@ def render_capabilities(doc, ostream): +-------------------------------------------------------+-------------------------------------------------+ | CAPABILITY | NAMESPACE | |-------------------------------------------------------+-------------------------------------------------| - | check for OutputDebugString error | anti-analysis/anti-debugging/debugger-detection | + | check for OutputDebugString error (2 matches) | anti-analysis/anti-debugging/debugger-detection | | read and send data from client to server | c2/file-transfer | | ... | ... | +-------------------------------------------------------+-------------------------------------------------+ @@ -35,21 +35,25 @@ def render_capabilities(doc, ostream): capability = '%s (%d matches)' % (rutils.bold(rule['meta']['name']), count) rows.append((capability, rule['meta']['namespace'])) - ostream.write(tabulate.tabulate(rows, headers=[width('CAPABILITY', 40), width('NAMESPACE', 40)], tablefmt="psql")) - ostream.write("\n") + ostream.write(tabulate.tabulate(rows, headers=[width('CAPABILITY', 40), width('NAMESPACE', 40)], tablefmt='psql')) + ostream.write('\n') def render_attack(doc, ostream): """ example:: - +----------------------------------------------------------------------+ - | ATT&CK tactic: EXECUTION | - |----------------------------------------------------------------------| - | Command and Scripting Interpreter::Windows Command Shell [T1059.003] | - | Shared Modules [T1129] | - | ... | - +----------------------------------------------------------------------+ + +------------------------+----------------------------------------------------------------------+ + | ATT&CK Tactic | ATT&CK Technique | + |------------------------+----------------------------------------------------------------------| + | DEFENSE EVASION | Obfuscated Files or Information [T1027] | + | DISCOVERY | Query Registry [T1012] | + | | System Information Discovery [T1082] | + | EXECUTION | Command and Scripting Interpreter::Windows Command Shell [T1059.003] | + | | Shared Modules [T1129] | + | EXFILTRATION | Exfiltration Over C2 Channel [T1041] | + | PERSISTENCE | Create or Modify System Process::Windows Service [T1543.003] | + +------------------------+----------------------------------------------------------------------+ """ tactics = collections.defaultdict(set) for rule in rutils.capability_rules(doc): @@ -66,19 +70,21 @@ def render_attack(doc, ostream): technique, _, id = rest.rpartition(' ') tactics[tactic].add((technique, id)) + rows = [] for tactic, techniques in sorted(tactics.items()): - rows = [] + inner_rows = [] for spec in sorted(techniques): if len(spec) == 2: technique, id = spec - rows.append(("%s %s" % (rutils.bold(technique), id), )) + inner_rows.append('%s %s' % (rutils.bold(technique), id)) elif len(spec) == 3: technique, subtechnique, id = spec - rows.append(("%s::%s %s" % (rutils.bold(technique), subtechnique, id), )) + inner_rows.append('%s::%s %s' % (rutils.bold(technique), subtechnique, id)) else: - raise RuntimeError("unexpected ATT&CK spec format") - ostream.write(tabulate.tabulate(rows, headers=[width('ATT&CK tactic: ' + rutils.bold(tactic.upper()), 80)], tablefmt="psql")) - ostream.write("\n") + raise RuntimeError('unexpected ATT&CK spec format') + rows.append((rutils.bold(tactic.upper()), '\n'.join(inner_rows), )) + ostream.write(tabulate.tabulate(rows, headers=[width('ATT&CK Tactic', 20), width('ATT&CK Technique', 60)], tablefmt='psql')) + ostream.write('\n') def render_default(doc):