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,88 @@
|
||||
---
|
||||
name: analyzing-cryptominer-malware
|
||||
description: 'Analyzes cryptojacking/coinminer malware by extracting mining pool endpoints
|
||||
(stratum), wallet addresses, algorithm and miner identifiers (XMRig and forks), and persistence
|
||||
or resource-control settings from static strings and config. Activates for requests to analyze a
|
||||
cryptominer, extract mining pool and wallet IOCs, or identify coinminer configuration.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware-analysis
|
||||
- cryptominer
|
||||
- cryptojacking
|
||||
- xmrig
|
||||
- resource-hijacking
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1496
|
||||
- T1543
|
||||
- T1027
|
||||
d3fend:
|
||||
- D3-PSA
|
||||
- D3-DA
|
||||
references:
|
||||
- 'MITRE ATT&CK T1496 Resource Hijacking — https://attack.mitre.org/techniques/T1496/'
|
||||
- 'XMRig configuration documentation — https://xmrig.com/docs/miner/config'
|
||||
---
|
||||
|
||||
# Analyzing Cryptominer Malware
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a suspected coinminer (often an XMRig fork) and need to extract its pool, wallet,
|
||||
algorithm, and resource-control configuration for IOCs and attribution.
|
||||
- You are confirming a host's high CPU/GPU usage is malicious mining.
|
||||
|
||||
**Do not use** this to run the miner — extract its configuration statically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The miner sample or its extracted config/strings, read inertly.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Read bytes statically; defang pool endpoints; never start the miner.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Extract mining configuration
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py profile sample.bin
|
||||
```
|
||||
|
||||
Extracts `stratum+tcp://`/`stratum+ssl://` pool URLs, wallet addresses (Monero and common
|
||||
formats), algorithm names (`rx/0`, `cn/r`, etc.), and the XMRig/miner identifier strings.
|
||||
|
||||
### Step 2: Identify resource and stealth controls
|
||||
|
||||
Surface `max-cpu-usage`, `--background`, idle-detection, and `donate-level` settings, plus
|
||||
watchdog/persistence indicators.
|
||||
|
||||
### Step 3: Build IOCs
|
||||
|
||||
Record defanged pool endpoints, wallet addresses, and the miner family for detection and takedown
|
||||
referral.
|
||||
|
||||
### Step 4: Document
|
||||
|
||||
Summarize the campaign's pool/wallet and the resource-control posture.
|
||||
|
||||
## Validation
|
||||
|
||||
- Pool URLs use a recognized `stratum` scheme and resolve to plausible hosts.
|
||||
- Wallet addresses match a known coin's format/length.
|
||||
- The miner family is identified from its config keys/strings.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Legitimate mining software shares the same config keys — context (deployment, stealth) matters.
|
||||
- Encrypted/packed config requiring decryption first.
|
||||
- Proxy pools masking the true upstream pool.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the profiler.
|
||||
- ATT&CK T1496 and the XMRig config reference (linked in frontmatter).
|
||||
@@ -0,0 +1,39 @@
|
||||
# API Reference: Analyzing Cryptominer Malware
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` extracts a coinminer's configuration from static strings: stratum pool
|
||||
endpoints, wallet addresses (Monero/Bitcoin/Ethereum formats), algorithm identifiers, miner
|
||||
family strings, and resource-control/stealth keys. It reads bytes statically, defangs pool
|
||||
endpoints, and executes nothing.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | regex, JSON, file IO |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `profile(path)`
|
||||
Returns pool endpoints, wallet addresses (by coin), algorithms, miner family, resource controls,
|
||||
and a cryptominer likelihood flag.
|
||||
|
||||
## Extracted indicators
|
||||
|
||||
- **Pools**: `stratum+tcp://` / `stratum+ssl://`.
|
||||
- **Wallets**: Monero (`4…`, 95 chars), Bitcoin (legacy + bech32), Ethereum (`0x…40 hex`).
|
||||
- **Algorithms**: `rx/0`, `cn/r`, `randomx`, `kawpow`, `ethash`, etc.
|
||||
- **Resource controls**: `max-cpu-usage`, `donate-level`, `background`, `idle`.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py profile sample.bin
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- MITRE ATT&CK T1496 Resource Hijacking — https://attack.mitre.org/techniques/T1496/
|
||||
- XMRig configuration keys — https://xmrig.com/docs/miner/config
|
||||
- Coin address formats from each coin's public address specification
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Profile a cryptominer's configuration from static strings.
|
||||
|
||||
Extracts stratum pool endpoints, wallet addresses, algorithm identifiers, miner family strings,
|
||||
and resource-control/stealth settings. Reads bytes statically, defangs pool endpoints, and
|
||||
executes nothing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ASCII_RE = re.compile(rb"[\x20-\x7e]{4,}")
|
||||
RE_STRATUM = re.compile(r"stratum\+(?:tcp|ssl)://[^\s\"'<>]+", re.I)
|
||||
RE_MONERO = re.compile(r"\b4[0-9AB][0-9A-Za-z]{93}\b")
|
||||
RE_BTC = re.compile(r"\b(?:bc1[0-9a-z]{20,60}|[13][a-km-zA-HJ-NP-Z1-9]{25,34})\b")
|
||||
RE_ETH = re.compile(r"\b0x[a-fA-F0-9]{40}\b")
|
||||
ALGOS = ["rx/0", "rx/wow", "cn/r", "cn/2", "cn-heavy", "argon2", "kawpow", "ethash", "randomx",
|
||||
"cryptonight"]
|
||||
MINER_IDS = ["xmrig", "xmr-stak", "minerd", "cpuminer", "nbminer", "phoenixminer", "t-rex",
|
||||
"lolminer", "nanominer"]
|
||||
RESOURCE_KEYS = ["max-cpu-usage", "cpu-priority", "donate-level", "background", "max-threads-hint",
|
||||
"huge-pages", "idle", "watchdog"]
|
||||
|
||||
|
||||
def _strings(data: bytes) -> str:
|
||||
return "\n".join(m.decode("latin-1", "ignore") for m in ASCII_RE.findall(data))
|
||||
|
||||
|
||||
def _defang(s: str) -> str:
|
||||
return s.replace("stratum", "stratum-x").replace("://", "[://]").replace(".", "[.]")
|
||||
|
||||
|
||||
def profile(path: str) -> dict:
|
||||
blob = _strings(Path(path).read_bytes())
|
||||
low = blob.lower()
|
||||
pools = sorted({_defang(p) for p in RE_STRATUM.findall(blob)})
|
||||
wallets = {
|
||||
"monero": sorted(set(RE_MONERO.findall(blob)))[:10],
|
||||
"bitcoin": sorted(set(RE_BTC.findall(blob)))[:10],
|
||||
"ethereum": sorted(set(RE_ETH.findall(blob)))[:10],
|
||||
}
|
||||
wallets = {k: v for k, v in wallets.items() if v}
|
||||
algos = sorted({a for a in ALGOS if a in low})
|
||||
miners = sorted({m for m in MINER_IDS if m in low})
|
||||
resource = sorted({r for r in RESOURCE_KEYS if r in low})
|
||||
return {
|
||||
"pool_endpoints": pools,
|
||||
"wallet_addresses": wallets,
|
||||
"algorithms": algos,
|
||||
"miner_family": miners,
|
||||
"resource_controls": resource,
|
||||
"is_likely_cryptominer": bool(pools or (miners and algos)),
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Profile a cryptominer")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("profile")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
print(json.dumps(profile(args.file), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user