121 lines
3.2 KiB
Python
121 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Malware-report helpers: generate a structured skeleton and check a draft for completeness.
|
|
|
|
Text-only tooling. ``scaffold`` prints a Markdown report template; ``check`` verifies a draft
|
|
contains the required sections and at least one ATT&CK technique reference.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import datetime as _dt
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REQUIRED_SECTIONS = [
|
|
"Executive Summary",
|
|
"Sample Identity",
|
|
"Capabilities",
|
|
"Indicators of Compromise",
|
|
"ATT&CK Mapping",
|
|
"Detection and Response",
|
|
]
|
|
|
|
_ATTACK_RE = re.compile(r"\bT\d{4}(\.\d{3})?\b")
|
|
|
|
|
|
def scaffold(sha256: str, name: str) -> str:
|
|
today = _dt.date.today().isoformat()
|
|
return f"""# Malware Analysis Report: {name}
|
|
|
|
_Date: {today} · Analyst: <you> · Confidence: <low/medium/high>_
|
|
|
|
## Executive Summary
|
|
|
|
<3-5 sentences: what it is, what it does, risk, recommended action.>
|
|
|
|
## Sample Identity
|
|
|
|
| Field | Value |
|
|
|---|---|
|
|
| Filename (as received) | <name> |
|
|
| SHA-256 | {sha256} |
|
|
| SHA-1 / MD5 | <...> |
|
|
| File type / size | <...> |
|
|
| First seen / source | {today} / <source> |
|
|
| Signing | <unsigned/invalid/valid> |
|
|
|
|
## Capabilities
|
|
|
|
| Capability | Evidence | ATT&CK |
|
|
|---|---|---|
|
|
| Persistence | <evidence> | T1547.001 |
|
|
| Command and Control | <evidence> | T1071.001 |
|
|
| Defense Evasion | <evidence> | T1027 |
|
|
|
|
## Indicators of Compromise
|
|
|
|
**Host**
|
|
- <path / registry key / mutex>
|
|
|
|
**Network (defanged)**
|
|
- hxxps://evil[.]com/api
|
|
|
|
```csv
|
|
type,value,context
|
|
domain,evil.com,c2
|
|
sha256,{sha256},sample
|
|
```
|
|
|
|
## ATT&CK Mapping
|
|
|
|
- T1547.001 — Registry Run Keys
|
|
- T1071.001 — Web Protocols
|
|
|
|
## Detection and Response
|
|
|
|
- Detection: <YARA/Sigma summary>
|
|
- Hunt: <what to search for>
|
|
- Containment / remediation: <steps>
|
|
"""
|
|
|
|
|
|
def check(text: str) -> list[str]:
|
|
problems = []
|
|
for section in REQUIRED_SECTIONS:
|
|
if section.lower() not in text.lower():
|
|
problems.append(f"missing section: {section}")
|
|
if not _ATTACK_RE.search(text):
|
|
problems.append("no ATT&CK technique IDs found")
|
|
if "http://" in text or "https://" in text:
|
|
problems.append("clickable URL present; defang before sharing")
|
|
return problems
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description="Malware report helpers")
|
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
|
|
p_s = sub.add_parser("scaffold", help="print a report skeleton")
|
|
p_s.add_argument("--sha256", required=True)
|
|
p_s.add_argument("--name", required=True)
|
|
|
|
p_c = sub.add_parser("check", help="check a draft for completeness")
|
|
p_c.add_argument("file")
|
|
|
|
args = parser.parse_args(argv)
|
|
if args.cmd == "scaffold":
|
|
print(scaffold(args.sha256, args.name))
|
|
return 0
|
|
problems = check(Path(args.file).read_text(encoding="utf-8", errors="replace"))
|
|
if problems:
|
|
for p in problems:
|
|
print(f"- {p}")
|
|
return 1
|
|
print("OK: report contains all required sections and ATT&CK references.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|