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,91 @@
|
||||
---
|
||||
name: analyzing-malicious-vbscript-and-wsf
|
||||
description: 'Analyzes malicious VBScript, WSF, and HTA scripts: parsing WSF/HTA containers,
|
||||
decoding VBScript.Encode (#@~^) and string obfuscation, and identifying WScript.Shell/ActiveX
|
||||
abuse to recover dropper behavior. Activates for requests to analyze VBScript, decode a WSF/HTA,
|
||||
or investigate a Windows Script Host dropper.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware-analysis
|
||||
- vbscript
|
||||
- wsf
|
||||
- hta
|
||||
- document-malware
|
||||
- deobfuscation
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1059.005
|
||||
- T1059.003
|
||||
- T1027
|
||||
d3fend:
|
||||
- D3-FCR
|
||||
- D3-DA
|
||||
references:
|
||||
- 'Microsoft Windows Script Host documentation — https://learn.microsoft.com/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/'
|
||||
- 'VBScript.Encode / Script Encoder format analysis — https://gist.github.com/bcse/1834878'
|
||||
---
|
||||
|
||||
# Analyzing Malicious VBScript and WSF
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a `.vbs`, `.wsf`, or `.hta` delivered via phishing and need its real behavior.
|
||||
- You must decode `VBScript.Encode`-obfuscated script (the `#@~^` marker) or string obfuscation.
|
||||
- You are identifying WScript.Shell/ActiveX-based dropper actions and IOCs.
|
||||
|
||||
**Do not use** `wscript`/`cscript`/`mshta` to run the script for analysis — that executes the
|
||||
dropper. Decode and read it statically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A static decoder (Python) or a script sandbox; the sample handled inertly in the lab.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Never run the script with Windows Script Host (`wscript`/`cscript`/`mshta`).
|
||||
- Defang recovered URLs; store dropped payloads password-protected.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Parse the container
|
||||
|
||||
For WSF, parse the XML `<job>`/`<script>` elements (a WSF can bundle multiple languages). For HTA,
|
||||
separate the HTML wrapper from the `<script>` body.
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py analyze sample.wsf
|
||||
```
|
||||
|
||||
### Step 2: Decode VBScript.Encode
|
||||
|
||||
If you see the `#@~^` header, decode the Microsoft Script Encoder stream back to source.
|
||||
|
||||
### Step 3: Unroll string obfuscation
|
||||
|
||||
Resolve `Chr()`/`Asc()` builds, string concatenation, and `Replace()`-based deobfuscators to
|
||||
reveal commands and URLs.
|
||||
|
||||
### Step 4: Identify dropper actions and IOCs
|
||||
|
||||
Find `CreateObject("WScript.Shell")`, `Run`/`Exec`, ADODB/MSXML download patterns, and PowerShell
|
||||
hand-offs; recover URLs/paths, defang, and route payloads onward.
|
||||
|
||||
## Validation
|
||||
|
||||
- WSF/HTA containers are decomposed into their script bodies (all jobs/languages).
|
||||
- `VBScript.Encode` streams are decoded to readable source.
|
||||
- Dropper actions and IOCs are recovered without executing the script.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Executing with `wscript`/`mshta` to "see" behavior, infecting the host.
|
||||
- Missing one `<script>` block in a multi-job WSF.
|
||||
- Overlooking the `#@~^` encoded section and analyzing only the cleartext stub.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the WSF/VBScript decoder.
|
||||
- Windows Script Host docs and the Script Encoder format (linked in frontmatter).
|
||||
@@ -0,0 +1,37 @@
|
||||
# API Reference: Analyzing Malicious VBScript and WSF
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` extracts `<script>` bodies from WSF/HTA containers, detects and isolates
|
||||
Microsoft Script Encoder (`#@~^`) blocks, and flags suspicious WScript/ActiveX dropper APIs. It
|
||||
parses text only and never invokes Windows Script Host. Full Script Encoder decoding is delegated
|
||||
to a dedicated decoder; the script isolates encoded blocks and confirms their presence.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | regex, JSON, file IO |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `analyze(text)`
|
||||
Returns script-block counts, encoded-block presence, suspicious API hits, and defanged URLs.
|
||||
|
||||
### `_isolate_script_encoder(encoded)`
|
||||
Strips the `#@~^`/`^#~@` markers and framing to isolate the encoded body for follow-on decoding.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py analyze sample.wsf
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- Microsoft Windows Script Host documentation —
|
||||
https://learn.microsoft.com/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/
|
||||
- VBScript.Encode / Script Encoder format (`#@~^` marker) analysis —
|
||||
https://gist.github.com/bcse/1834878
|
||||
- WScript.Shell / ADODB.Stream / MSXML2.XMLHTTP dropper patterns, established script-analysis
|
||||
practice
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Analyze WSF/HTA/VBScript droppers statically.
|
||||
|
||||
Extracts ``<script>`` bodies from WSF/HTA XML/HTML containers, decodes Microsoft Script Encoder
|
||||
(``VBScript.Encode``, ``#@~^``) streams, and flags suspicious WScript/ActiveX dropper patterns.
|
||||
It parses text only and never invokes Windows Script Host.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
RE_SCRIPT = re.compile(r"<script\b[^>]*>(.*?)</script>", re.I | re.S)
|
||||
RE_ENCODED = re.compile(r"#@~\^.*?\^#~@", re.S)
|
||||
RE_URL = re.compile(r"https?://[^\s'\"<>)]+", re.I)
|
||||
|
||||
SUSPECT = ["wscript.shell", "createobject", ".run", ".exec", "powershell", "adodb.stream",
|
||||
"msxml2.xmlhttp", "winhttp", "shell.application", "regwrite"]
|
||||
|
||||
|
||||
def _isolate_script_encoder(encoded: str) -> str:
|
||||
"""Isolate the body of a #@~^...^#~@ Script Encoder block for follow-on decoding.
|
||||
|
||||
Full Script Encoder decoding relies on a published ~140-entry substitution table; this
|
||||
strips the wrapper markers and the 6-character length/checksum framing so the encoded body
|
||||
can be handed to a dedicated decoder. The goal here is detection and isolation, not a
|
||||
reimplementation of the entire table.
|
||||
"""
|
||||
m = re.match(r"#@~\^.{6}==(.*)\^#~@", encoded, re.S)
|
||||
return m.group(1) if m else encoded
|
||||
|
||||
|
||||
def analyze(text: str) -> dict:
|
||||
scripts = [s.strip() for s in RE_SCRIPT.findall(text)]
|
||||
if not scripts:
|
||||
scripts = [text] # bare .vbs
|
||||
encoded_blocks = RE_ENCODED.findall(text)
|
||||
isolated = [_isolate_script_encoder(b) for b in encoded_blocks]
|
||||
combined = "\n".join(scripts + isolated).lower()
|
||||
indicators = sorted({s for s in SUSPECT if s in combined})
|
||||
urls = sorted(set(RE_URL.findall(text)))
|
||||
return {
|
||||
"script_blocks": len(scripts),
|
||||
"script_encoder_blocks": len(encoded_blocks),
|
||||
"encoded_block_present": bool(encoded_blocks),
|
||||
"suspicious_apis": indicators,
|
||||
"urls": [u.replace("http", "hxxp").replace(".", "[.]") for u in urls],
|
||||
"note": "encoded blocks isolated; finish Script Encoder decode with a dedicated decoder",
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Analyze VBScript/WSF/HTA")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("analyze")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
text = Path(args.file).read_text(encoding="utf-8-sig", errors="replace")
|
||||
print(json.dumps(analyze(text), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user