reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
Apache License 2.0 — see the repository root LICENSE file for the full text.
|
||||
|
||||
Copyright the AnalystAIPack contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: analyzing-excel-4-macro-malware
|
||||
description: 'Analyzes legacy Excel 4.0 (XLM) macro malware by parsing extracted macro-sheet
|
||||
formulas for auto-executing names, obfuscation (FORMULA.FILL, CHAR concatenation), and download
|
||||
or execution primitives (EXEC, CALL, REGISTER). Activates for requests to analyze XLM macros,
|
||||
examine Excel 4.0 macro sheets, or deobfuscate legacy spreadsheet macros.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware-analysis
|
||||
- xlm
|
||||
- excel4
|
||||
- macros
|
||||
- document-malware
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1059.005
|
||||
- T1204.002
|
||||
- T1027
|
||||
d3fend:
|
||||
- D3-FCR
|
||||
- D3-DA
|
||||
references:
|
||||
- 'MITRE ATT&CK T1059.005 Visual Basic / macros — https://attack.mitre.org/techniques/T1059/005/'
|
||||
- 'Microsoft Excel 4.0 macro functions reference — https://learn.microsoft.com/office/'
|
||||
---
|
||||
|
||||
# Analyzing Excel 4.0 Macro Malware
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have an extracted Excel 4.0 (XLM) macro sheet (e.g., from a `.xls`/`.xlsm` dumped with
|
||||
oletools/XLMMacroDeobfuscator) and need to find auto-run cells and execution primitives.
|
||||
- You are triaging maldocs that hide logic in legacy macro sheets rather than VBA.
|
||||
|
||||
**Do not use** Excel to open the document to "see" the macro — opening triggers the auto-run
|
||||
cells. Work from the extracted formula text statically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The extracted XLM formula text (cell address → formula). Optional: `oletools` to extract it.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Never open the workbook in Excel; analyze the extracted formulas inertly. Defang URLs.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Find auto-executing entry points
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py analyze macros.txt
|
||||
```
|
||||
|
||||
Flags defined-name triggers (`Auto_Open`, `Auto_Close`) and the cells they point to, plus
|
||||
`=HALT()`/`=RETURN()` flow markers.
|
||||
|
||||
### Step 2: Identify execution and download primitives
|
||||
|
||||
Detects `EXEC(`, `CALL(`, `REGISTER(` (Win32 imports), and URLDownload-style `CALL` patterns that
|
||||
fetch and run a payload.
|
||||
|
||||
### Step 3: Unwind obfuscation
|
||||
|
||||
Surfaces `CHAR()`/`&` string-building, `FORMULA.FILL`/`FORMULA` self-writing, and base/`MID`
|
||||
slicing used to hide strings; reconstructs concatenated literals where possible.
|
||||
|
||||
### Step 4: Extract IOCs
|
||||
|
||||
Pull URLs/paths and defang them; record the execution method (regsvr32, rundll32, mshta).
|
||||
|
||||
## Validation
|
||||
|
||||
- Auto-run entry cells are identified, not just the presence of macros.
|
||||
- Execution primitives (EXEC/CALL/REGISTER) are reported with their arguments.
|
||||
- Reconstructed strings and URLs are defanged.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Heavily obfuscated sheets that self-write cells at runtime — static reconstruction is partial.
|
||||
- Macro sheets hidden as `Very Hidden` that simple viewers miss.
|
||||
- Confusing benign legacy spreadsheets that legitimately use XLM.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the analyzer.
|
||||
- ATT&CK T1059.005 and the Excel 4.0 macro reference (linked in frontmatter).
|
||||
@@ -0,0 +1,41 @@
|
||||
# API Reference: Analyzing Excel 4.0 Macro Malware
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` parses an extracted XLM macro-sheet formula dump and flags auto-run triggers,
|
||||
execution/download primitives, executors, and obfuscation, reconstructing `CHAR()` string chains
|
||||
and defanging URLs. It parses text only, never opens the workbook, and executes nothing.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | regex, JSON, file IO |
|
||||
| oletools | optional | extract the formulas upstream (not required by this script) |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `analyze(path)`
|
||||
Returns auto-run triggers, execution primitives, download indicators, executors, obfuscation
|
||||
techniques, defanged URLs, reconstructed `CHAR()` strings, and a maliciousness flag.
|
||||
|
||||
### `_reconstruct_char(line)`
|
||||
Rebuilds a string from a `CHAR(n)&CHAR(n)…` concatenation chain.
|
||||
|
||||
## Indicators
|
||||
|
||||
- Auto-run: `Auto_Open`, `Auto_Close`, `Auto_Activate`.
|
||||
- Execution: `EXEC(`, `CALL(`, `REGISTER(` (Win32 import declaration).
|
||||
- Download: `URLDownloadToFile`, `MSXML2`, `WinHTTP`.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py analyze macros.txt
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- MITRE ATT&CK T1059.005 — https://attack.mitre.org/techniques/T1059/005/
|
||||
- Excel 4.0 macro function semantics (EXEC/CALL/REGISTER/FORMULA.FILL) from Microsoft Office docs
|
||||
- XLM obfuscation patterns from public maldoc analysis (XLMMacroDeobfuscator methodology)
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Analyze extracted Excel 4.0 (XLM) macro formulas for malicious behavior.
|
||||
|
||||
Reads a text dump of macro-sheet formulas and flags auto-run entry points, execution/download
|
||||
primitives (EXEC/CALL/REGISTER), and obfuscation (CHAR concatenation, FORMULA.FILL self-writing).
|
||||
Parses text only; executes nothing and never opens the workbook. Defangs recovered URLs.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
AUTO_NAMES = ["auto_open", "auto_close", "auto_activate", "auto_deactivate"]
|
||||
EXEC_PRIMS = ["exec(", "call(", "register(", "fopen(", "fwrite("]
|
||||
DOWNLOAD_HINTS = ["urlmon", "urldownloadtofile", "http", "msxml2", "winhttp", "shellexecute"]
|
||||
EXECUTORS = ["regsvr32", "rundll32", "mshta", "powershell", "cmd.exe", "wscript", "cscript"]
|
||||
OBFUSCATION = ["char(", "formula.fill", "formula(", "mid(", "&", "concatenate("]
|
||||
RE_URL = re.compile(r"https?://[^\s\"'<>)]+", re.I)
|
||||
RE_CHAR = re.compile(r"CHAR\((\d{1,3})\)", re.I)
|
||||
|
||||
|
||||
def _defang(s: str) -> str:
|
||||
return s.replace("http", "hxxp").replace(".", "[.]")
|
||||
|
||||
|
||||
def _reconstruct_char(line: str) -> str:
|
||||
chars = RE_CHAR.findall(line)
|
||||
if len(chars) < 3:
|
||||
return ""
|
||||
try:
|
||||
return "".join(chr(int(c)) for c in chars if 0 <= int(c) < 256)
|
||||
except ValueError:
|
||||
return ""
|
||||
|
||||
|
||||
def analyze(path: str) -> dict:
|
||||
text = Path(path).read_text(encoding="utf-8-sig", errors="replace")
|
||||
low = text.lower()
|
||||
auto = sorted({n for n in AUTO_NAMES if n in low})
|
||||
exec_prims = sorted({p.rstrip("(") for p in EXEC_PRIMS if p in low})
|
||||
downloads = sorted({d for d in DOWNLOAD_HINTS if d in low})
|
||||
executors = sorted({e for e in EXECUTORS if e in low})
|
||||
obf = sorted({o.rstrip("(") for o in OBFUSCATION if o in low})
|
||||
urls = sorted({_defang(u) for u in RE_URL.findall(text)})
|
||||
reconstructed = sorted({r for line in text.splitlines()
|
||||
if (r := _reconstruct_char(line))})[:25]
|
||||
return {
|
||||
"auto_run_triggers": auto,
|
||||
"execution_primitives": exec_prims,
|
||||
"download_indicators": downloads,
|
||||
"executors": executors,
|
||||
"obfuscation_techniques": obf,
|
||||
"urls": urls[:50],
|
||||
"reconstructed_char_strings": reconstructed,
|
||||
"is_likely_malicious_xlm": bool(auto and (exec_prims or downloads)),
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Analyze Excel 4.0 (XLM) macros")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("analyze")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
print(json.dumps(analyze(args.file), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user