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-pdfs
|
||||
description: 'Analyzes malicious PDF documents: parsing the object structure for JavaScript,
|
||||
OpenAction/launch triggers, embedded files, and URIs, then extracting and decoding suspicious
|
||||
streams without opening the document in a reader. Activates for requests to analyze a malicious
|
||||
PDF, inspect PDF JavaScript, or extract embedded payloads from a PDF.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware-analysis
|
||||
- pdf
|
||||
- document-malware
|
||||
- javascript
|
||||
- static-analysis
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1204.002
|
||||
- T1059.007
|
||||
- T1027
|
||||
d3fend:
|
||||
- D3-FCR
|
||||
- D3-DA
|
||||
references:
|
||||
- 'PDF 32000-1:2008 (ISO PDF specification) — https://www.pdfa.org/resource/iso-32000-pdf/'
|
||||
- 'Didier Stevens PDF tools (pdfid, pdf-parser) — https://blog.didierstevens.com/programs/pdf-tools/'
|
||||
---
|
||||
|
||||
# Analyzing Malicious PDFs
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a suspicious PDF (often from phishing) and must determine if it is weaponized.
|
||||
- You need to find auto-executing actions, embedded JavaScript, launch actions, or embedded files.
|
||||
- You want to extract and decode suspicious streams safely.
|
||||
|
||||
**Do not use** a PDF reader to "just look" — opening in a viewer can trigger the very actions you
|
||||
are investigating. Parse the structure statically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A PDF object parser (Python, or pdfid/pdf-parser/peepdf); the sample handled inertly.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Never open the PDF in a graphical reader; parse the raw object structure only.
|
||||
- Defang any extracted URLs and store embedded payloads password-protected.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Triage the object inventory
|
||||
|
||||
Count high-risk keywords: `/JavaScript`, `/JS`, `/OpenAction`, `/AA`, `/Launch`, `/EmbeddedFile`,
|
||||
`/URI`, `/RichMedia`. Their presence (especially auto-actions) flags weaponization.
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py triage sample.pdf
|
||||
```
|
||||
|
||||
### Step 2: Locate auto-execution triggers
|
||||
|
||||
Resolve `/OpenAction` and `/AA` (additional actions) to see what runs on open, and any `/Launch`
|
||||
actions that spawn external programs.
|
||||
|
||||
### Step 3: Extract and decode streams
|
||||
|
||||
Pull JavaScript and suspicious streams, applying filters (`/FlateDecode`, `/ASCIIHexDecode`) to
|
||||
get the cleartext; deobfuscate layered JS as needed.
|
||||
|
||||
### Step 4: Recover payloads and IOCs
|
||||
|
||||
Extract embedded files and URIs; hash payloads, defang URLs, and route extracted executables to
|
||||
PE analysis.
|
||||
|
||||
## Validation
|
||||
|
||||
- Auto-execution triggers (`/OpenAction`, `/AA`, `/Launch`) are resolved to concrete actions.
|
||||
- JavaScript/streams are decoded through their filters, not left encoded.
|
||||
- Embedded payloads and URIs are extracted, hashed, and defanged.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Opening the PDF in a reader and triggering the payload.
|
||||
- Missing object-stream (`/ObjStm`) compressed objects that hide the malicious content.
|
||||
- Stopping at the first JS layer when it is multiply obfuscated.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the PDF triage parser.
|
||||
- ISO 32000 and Didier Stevens' PDF tools (linked in frontmatter).
|
||||
@@ -0,0 +1,39 @@
|
||||
# API Reference: Analyzing Malicious PDFs
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` scans raw PDF bytes for weaponization keywords (/JavaScript, /OpenAction,
|
||||
/Launch, /EmbeddedFile, /URI, /ObjStm, etc.), counts objects/streams, extracts and defangs URIs,
|
||||
and flags likely weaponization. It parses statically and never opens the document.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | regex, JSON, file IO |
|
||||
|
||||
## External tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| pdfid / pdf-parser (Didier Stevens) | Object inventory and stream extraction with filters |
|
||||
| peepdf | Interactive PDF analysis and JS extraction |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `triage(path)`
|
||||
Returns object/stream counts, risk-keyword counts, auto-action list, defanged URIs, and a
|
||||
weaponization flag.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py triage sample.pdf
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- PDF 32000-1:2008 (ISO PDF specification) — https://www.pdfa.org/resource/iso-32000-pdf/
|
||||
- Didier Stevens PDF tools (pdfid, pdf-parser) —
|
||||
https://blog.didierstevens.com/programs/pdf-tools/
|
||||
- /OpenAction, /AA, /Launch auto-execution and /ObjStm hiding, established PDF-analysis practice
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Triage a PDF's object structure for weaponization indicators.
|
||||
|
||||
Scans the raw PDF bytes for high-risk keywords (/JavaScript, /OpenAction, /Launch, /EmbeddedFile,
|
||||
/URI, etc.), counts indirect objects and streams, and extracts URIs. It parses bytes statically
|
||||
and never opens the document in a reader, so auto-actions cannot fire.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
KEYWORDS = ["/JavaScript", "/JS", "/OpenAction", "/AA", "/Launch", "/EmbeddedFile",
|
||||
"/URI", "/RichMedia", "/SubmitForm", "/GoToR", "/ObjStm", "/AcroForm",
|
||||
"/XFA", "/JBIG2Decode"]
|
||||
|
||||
AUTO_ACTION = {"/OpenAction", "/AA", "/Launch"}
|
||||
|
||||
RE_URI = re.compile(rb"/URI\s*\(([^)]*)\)")
|
||||
RE_OBJ = re.compile(rb"\d+\s+\d+\s+obj")
|
||||
RE_STREAM = re.compile(rb"\bstream\b")
|
||||
|
||||
|
||||
def _defang(url: str) -> str:
|
||||
return url.replace("http", "hxxp").replace(".", "[.]")
|
||||
|
||||
|
||||
def triage(path: str) -> dict:
|
||||
data = Path(path).read_bytes()
|
||||
if not data.lstrip().startswith(b"%PDF"):
|
||||
return {"error": "not a PDF (no %PDF header)"}
|
||||
counts = {kw: len(re.findall(re.escape(kw.encode()), data)) for kw in KEYWORDS}
|
||||
counts = {k: v for k, v in counts.items() if v}
|
||||
uris = sorted({m.decode("latin-1", "replace") for m in RE_URI.findall(data)})
|
||||
auto = [kw for kw in AUTO_ACTION if counts.get(kw)]
|
||||
has_js = bool(counts.get("/JavaScript") or counts.get("/JS"))
|
||||
return {
|
||||
"objects": len(RE_OBJ.findall(data)),
|
||||
"streams": len(RE_STREAM.findall(data)),
|
||||
"risk_keywords": counts,
|
||||
"auto_actions": auto,
|
||||
"has_javascript": has_js,
|
||||
"uris": [_defang(u) for u in uris],
|
||||
"weaponized_likely": bool(auto and has_js) or bool(counts.get("/Launch")),
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Triage a malicious PDF")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("triage")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
print(json.dumps(triage(args.file), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user