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,90 @@
|
||||
---
|
||||
name: decrypting-embedded-configuration
|
||||
description: 'Decrypts statically embedded malware configuration blobs by trying common schemes
|
||||
(single-byte and multi-byte XOR, RC4, base64 layers) and scoring decoded output for config-like
|
||||
content. Activates for requests to decrypt an embedded config, recover hardcoded settings from a
|
||||
blob, or brute-force a configuration encryption scheme.'
|
||||
domain: cybersecurity
|
||||
subdomain: reverse-engineering
|
||||
tags:
|
||||
- reverse-engineering
|
||||
- config-extraction
|
||||
- decryption
|
||||
- xor
|
||||
- rc4
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1140
|
||||
- T1027
|
||||
- T1071
|
||||
d3fend:
|
||||
- D3-SDA
|
||||
- D3-DA
|
||||
references:
|
||||
- 'MITRE ATT&CK T1140 Deobfuscate/Decode Files or Information — https://attack.mitre.org/techniques/T1140/'
|
||||
- 'RC4 algorithm (RFC-equivalent public description) — https://en.wikipedia.org/wiki/RC4'
|
||||
---
|
||||
|
||||
# Decrypting Embedded Configuration
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have an extracted config blob (from a resource, `.data` section, or overlay) that is XOR/RC4/
|
||||
base64-obfuscated and want to recover plaintext settings.
|
||||
- You need a quick brute-force over common schemes before writing a family-specific decryptor.
|
||||
|
||||
**Do not use** this on a live-decrypted-in-memory config — for that use the memory config skill.
|
||||
This works statically on the extracted blob and executes nothing.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The extracted ciphertext blob and (optionally) a candidate key.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Treat decoded endpoints as live C2; defang before sharing.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Try single-byte XOR
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py xor blob.bin
|
||||
```
|
||||
|
||||
Brute-forces all 256 single-byte keys and scores each output for printable ratio and config tokens
|
||||
(`http`, `.php`, IP patterns, `id=`).
|
||||
|
||||
### Step 2: Try RC4 / multi-byte XOR with a key
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py rc4 blob.bin --key mysecret
|
||||
python scripts/analyst.py xorkey blob.bin --key 0x11,0x22,0x33
|
||||
```
|
||||
|
||||
### Step 3: Peel base64 / repeat
|
||||
|
||||
If output is base64, decode and re-run the scheme search on the result.
|
||||
|
||||
### Step 4: Extract and defang
|
||||
|
||||
Pull URLs/IPs/keys from the best-scoring plaintext and defang.
|
||||
|
||||
## Validation
|
||||
|
||||
- The chosen scheme yields a high printable ratio and real config tokens.
|
||||
- Recovered endpoints parse as valid hosts/URLs.
|
||||
- Output is defanged before sharing.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Single-byte XOR coincidentally producing some ASCII — require config tokens, not just printables.
|
||||
- RC4 key drop-bytes variants (RC4-drop) needed by some families.
|
||||
- Nested layers (base64 over XOR over RC4) requiring multiple passes.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the decryptor.
|
||||
- ATT&CK T1140 and the RC4 description (linked in frontmatter).
|
||||
@@ -0,0 +1,42 @@
|
||||
# API Reference: Decrypting Embedded Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` brute-forces single-byte XOR, applies repeating-key XOR or RC4 with a supplied
|
||||
key, and scores each candidate plaintext by printable ratio and config tokens, defanging recovered
|
||||
endpoints. It reads the ciphertext blob statically and executes nothing.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | regex, JSON, file IO |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `xor_brute(data)`
|
||||
Tries all 256 single-byte keys; returns the top-scoring candidates with endpoints and a preview.
|
||||
|
||||
### `rc4(data, key)`
|
||||
Standard RC4 keystream decryption.
|
||||
|
||||
### `xor_key(data, key)`
|
||||
Repeating multi-byte XOR with a supplied key list.
|
||||
|
||||
## Scoring
|
||||
|
||||
Printable ratio (0–100) + 10 per config token + 5 per IP match. Higher = more config-like.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py xor blob.bin
|
||||
python scripts/analyst.py rc4 blob.bin --key mysecret
|
||||
python scripts/analyst.py xorkey blob.bin --key 0x11,0x22,0x33
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- MITRE ATT&CK T1140 Deobfuscate/Decode Information — https://attack.mitre.org/techniques/T1140/
|
||||
- RC4 keystream algorithm (public description) — https://en.wikipedia.org/wiki/RC4
|
||||
- XOR/base64/RC4 config patterns from public malware config-extractor write-ups
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Brute-force common embedded-config encryption schemes and score config-like output.
|
||||
|
||||
Supports single-byte XOR brute force, multi-byte repeating-key XOR, and RC4. Scores each candidate
|
||||
plaintext by printable ratio and presence of config tokens, and defangs recovered endpoints. Reads
|
||||
the ciphertext blob statically; executes nothing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
CONFIG_TOKENS = [b"http", b".php", b"id=", b"botnet", b"campaign", b".onion", b"User-Agent",
|
||||
b"POST", b"Mozilla"]
|
||||
RE_IP = re.compile(rb"\b(?:\d{1,3}\.){3}\d{1,3}\b")
|
||||
RE_URL = re.compile(rb"https?://[\x21-\x7e]{4,}")
|
||||
|
||||
|
||||
def _score(data: bytes) -> int:
|
||||
printable = sum(1 for b in data if 0x20 <= b <= 0x7e or b in (9, 10, 13))
|
||||
ratio = printable / max(len(data), 1)
|
||||
score = int(ratio * 100)
|
||||
score += 10 * sum(1 for t in CONFIG_TOKENS if t in data)
|
||||
score += 5 * len(RE_IP.findall(data))
|
||||
return score
|
||||
|
||||
|
||||
def _defang(s: str) -> str:
|
||||
return s.replace("http", "hxxp").replace(".", "[.]")
|
||||
|
||||
|
||||
def _endpoints(data: bytes) -> list[str]:
|
||||
out = {_defang(m.decode("ascii", "ignore")) for m in RE_URL.findall(data)}
|
||||
out |= {_defang(m.decode("ascii", "ignore")) for m in RE_IP.findall(data)}
|
||||
return sorted(out)
|
||||
|
||||
|
||||
def rc4(data: bytes, key: bytes) -> bytes:
|
||||
s = list(range(256))
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + s[i] + key[i % len(key)]) & 0xFF
|
||||
s[i], s[j] = s[j], s[i]
|
||||
out = bytearray()
|
||||
i = j = 0
|
||||
for b in data:
|
||||
i = (i + 1) & 0xFF
|
||||
j = (j + s[i]) & 0xFF
|
||||
s[i], s[j] = s[j], s[i]
|
||||
out.append(b ^ s[(s[i] + s[j]) & 0xFF])
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def xor_brute(data: bytes) -> dict:
|
||||
best = []
|
||||
for key in range(256):
|
||||
dec = bytes(b ^ key for b in data)
|
||||
best.append((_score(dec), key, dec))
|
||||
best.sort(reverse=True, key=lambda t: t[0])
|
||||
top = best[:3]
|
||||
return {"candidates": [
|
||||
{"key": hex(k), "score": s, "endpoints": _endpoints(d),
|
||||
"preview": d[:80].decode("ascii", "replace")} for s, k, d in top]}
|
||||
|
||||
|
||||
def xor_key(data: bytes, key: bytes) -> dict:
|
||||
dec = bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
|
||||
return {"score": _score(dec), "endpoints": _endpoints(dec),
|
||||
"preview": dec[:120].decode("ascii", "replace")}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Decrypt embedded config blobs")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
px = sub.add_parser("xor")
|
||||
px.add_argument("file")
|
||||
pr = sub.add_parser("rc4")
|
||||
pr.add_argument("file")
|
||||
pr.add_argument("--key", required=True)
|
||||
pk = sub.add_parser("xorkey")
|
||||
pk.add_argument("file")
|
||||
pk.add_argument("--key", required=True, help="comma list e.g. 0x11,0x22")
|
||||
args = parser.parse_args(argv)
|
||||
data = Path(args.file).read_bytes()
|
||||
if args.cmd == "xor":
|
||||
print(json.dumps(xor_brute(data), indent=2))
|
||||
elif args.cmd == "rc4":
|
||||
dec = rc4(data, args.key.encode())
|
||||
print(json.dumps({"score": _score(dec), "endpoints": _endpoints(dec),
|
||||
"preview": dec[:120].decode("ascii", "replace")}, indent=2))
|
||||
else:
|
||||
key = bytes(int(x, 0) for x in args.key.split(","))
|
||||
print(json.dumps(xor_key(data, key), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user