reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
145
vendor-new/malware-analysis-claude-skills/tests/run.sh
Normal file
145
vendor-new/malware-analysis-claude-skills/tests/run.sh
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env bash
|
||||
# End-to-end test harness for the malware-analysis skills package.
|
||||
#
|
||||
# Proves the host-side tooling works on realistic fixtures: the Python
|
||||
# scripts every skill depends on, plus the detection rules the skills
|
||||
# ship as examples. No malware is involved — fixtures are synthetic
|
||||
# (tests/make_pe.py builds a benign PE that only calls ExitProcess).
|
||||
#
|
||||
# Usage: bash tests/run.sh
|
||||
# Exit 0 = all required checks pass. Optional tool checks (pefile, yara,
|
||||
# sigma, olevba) are skipped with a note when the tool is absent, so the
|
||||
# harness runs on a bare box and does more when deps are installed.
|
||||
|
||||
set -u
|
||||
cd "$(dirname "$0")/.."
|
||||
ROOT=$(pwd)
|
||||
PY=python3
|
||||
[ -x .venv/bin/python ] && PY=.venv/bin/python
|
||||
mkdir -p tests/out
|
||||
|
||||
pass=0; fail=0; skip=0
|
||||
ok() { echo " ok $1"; pass=$((pass+1)); }
|
||||
bad() { echo " FAIL $1"; fail=$((fail+1)); }
|
||||
skipm(){ echo " skip $1"; skip=$((skip+1)); }
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
pyhas(){ $PY -c "import $1" >/dev/null 2>&1; }
|
||||
# assert: <label> <needle> <<< "$output"
|
||||
assert(){ if grep -qF -- "$2" <<<"$3"; then ok "$1"; else bad "$1 (missing: $2)"; fi; }
|
||||
refute(){ if grep -qF -- "$2" <<<"$3"; then bad "$1 (unexpected: $2)"; else ok "$1"; fi; }
|
||||
|
||||
echo "== 1. script self-tests"
|
||||
for s in scripts/ioc_extract.py malware-dynamic-analysis/scripts/procmon_summary.py malware-dynamic-analysis/scripts/sysmon_summary.py; do
|
||||
if $PY "$s" --self-test >/dev/null 2>&1; then ok "$s"; else bad "$s"; fi
|
||||
done
|
||||
|
||||
echo "== 2. PE triage (pe_info.py on synthetic PE)"
|
||||
$PY tests/make_pe.py tests/out/invoice_2024.exe >/dev/null
|
||||
[ -f tests/out/invoice_2024.exe ] && ok "PE fixture built" || bad "PE fixture build"
|
||||
if pyhas pefile; then
|
||||
o=$($PY malware-triage/scripts/pe_info.py tests/out/invoice_2024.exe)
|
||||
assert "detects .NET=no" ".NET: no" "$o"
|
||||
assert "categorizes injection" "injection: CreateRemoteThread" "$o"
|
||||
assert "categorizes network" "network: InternetOpenA" "$o"
|
||||
assert "categorizes persistence" "persistence: RegCreateKeyExA" "$o"
|
||||
assert "stable imphash" "dfcaebd44ff7676285215e9d856415f3" "$o"
|
||||
assert "finds overlay" "Overlay size: 530 bytes" "$o"
|
||||
# deterministic hash
|
||||
h=$($PY malware-triage/scripts/hash_calculator.py tests/out/invoice_2024.exe | grep -i sha256)
|
||||
assert "hash_calculator SHA256" "af747150f9afc0937a6b62755f9bd84cfb88726370f6007ac03f8f7504d38c4d" "$h"
|
||||
else
|
||||
skipm "pe_info.py (pip install pefile)"
|
||||
fi
|
||||
|
||||
echo "== 3. Procmon evidence parsing"
|
||||
o=$($PY malware-dynamic-analysis/scripts/procmon_summary.py tests/fixtures/evidence/procmon.csv --process invoice_2024.exe)
|
||||
assert "process tree nests cmd" " cmd.exe (PID 5102)" "$o"
|
||||
assert "grandchild named" "PING.EXE (PID 5140)" "$o"
|
||||
assert "dropped file" "svc.exe" "$o"
|
||||
assert "persistence flagged" "PERSISTENCE" "$o"
|
||||
assert "self-deletion" "Files deleted (1)" "$o"
|
||||
refute "no unrelated process" "chrome.exe:2100" "$o"
|
||||
|
||||
echo "== 4. Sysmon evidence parsing"
|
||||
o=$($PY malware-dynamic-analysis/scripts/sysmon_summary.py tests/fixtures/evidence/sysmon.json --process invoice_2024.exe,svc.exe)
|
||||
assert "injection remote thread" "-> C:\\Windows\\explorer.exe" "$o"
|
||||
assert "high-rights access" "0x1F0FFF" "$o"
|
||||
assert "run key persistence" "PERSISTENCE" "$o"
|
||||
assert "beacon detected" "BEACON-LIKE" "$o"
|
||||
assert "named pipe IOC" "\\testfixture" "$o"
|
||||
assert "unsigned dll load" "hlp.dll signed=false" "$o"
|
||||
|
||||
echo "== 5. IOC extraction + defang"
|
||||
o=$(cat tests/fixtures/evidence/*.txt tests/fixtures/evidence/procmon.csv | $PY scripts/ioc_extract.py)
|
||||
assert "C2 IP defanged" "203[.]0[.]113[.]5" "$o"
|
||||
assert "C2 domain defanged" "update-cdn[.]example[.]test" "$o"
|
||||
refute "no live C2 dot" "203.0.113.5" "$o"
|
||||
o2=$(echo "hxxps://update-cdn[.]example[.]test/gate[.]php" | $PY scripts/ioc_extract.py --refang)
|
||||
assert "refang restores URL" "update-cdn.example.test" "$o2"
|
||||
|
||||
echo "== 6. Script deobfuscation (host-side decoders from the skill)"
|
||||
o=$($PY - tests/fixtures/scripts/malicious.ps1 <<'EOF'
|
||||
import base64, re, sys
|
||||
src = open(sys.argv[1], encoding="utf-8", errors="replace").read()
|
||||
for m in re.finditer(r"[A-Za-z0-9+/]{40,}={0,2}", src):
|
||||
raw = base64.b64decode(m.group(0) + "=" * (-len(m.group(0)) % 4))
|
||||
for enc in ("utf-16le", "utf-8"):
|
||||
try:
|
||||
print(raw.decode(enc)); break
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
EOF
|
||||
)
|
||||
assert "PowerShell base64 decoded" "DownloadString" "$o"
|
||||
o=$($PY - tests/fixtures/scripts/malicious.vbs <<'EOF'
|
||||
import re, sys
|
||||
c = open(sys.argv[1], encoding="utf-8", errors="replace").read()
|
||||
c = re.sub(r"Chr[Ww]?\((\d+)\)", lambda m: '"' + chr(int(m.group(1))) + '"', c)
|
||||
c = re.sub(r'"\s*&\s*"', "", c)
|
||||
c = re.sub(r'StrReverse\("([^"]*)"\)', lambda m: '"' + m.group(1)[::-1] + '"', c)
|
||||
for m in re.finditer(r'Replace\("([^"]*)",\s*"([^"]*)",\s*"([^"]*)"\)', c):
|
||||
c = c.replace(m.group(0), '"' + m.group(1).replace(m.group(2), m.group(3)) + '"')
|
||||
print(c)
|
||||
EOF
|
||||
)
|
||||
assert "VBS Chr() resolved" '"cmd"' "$o"
|
||||
assert "VBS StrReverse resolved" "calc.exe" "$o"
|
||||
|
||||
echo "== 7. Detection rules validate (optional)"
|
||||
if have sigma || [ -x .venv/bin/sigma ]; then
|
||||
SIGMA=sigma; [ -x .venv/bin/sigma ] && SIGMA=.venv/bin/sigma
|
||||
n=0
|
||||
rm -f tests/out/sigma_*.yml
|
||||
$PY tests/extract_rules.py detection-engineer/SKILL.md tests/out/sigma_
|
||||
for f in tests/out/sigma_*.yml; do
|
||||
[ -f "$f" ] || continue
|
||||
if $SIGMA check "$f" >/dev/null 2>&1; then ok "sigma check $(basename "$f")"; else bad "sigma check $(basename "$f")"; fi
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" -gt 0 ] || skipm "no sigma rules extracted"
|
||||
else
|
||||
skipm "sigma check (pip install sigma-cli)"
|
||||
fi
|
||||
|
||||
echo "== 8. YARA rule tests against PE fixture (optional)"
|
||||
if { have yara || pyhas yara; } && [ -f tests/fixtures/yara/fixture.yar ]; then
|
||||
if pyhas yara; then
|
||||
o=$($PY - tests/fixtures/yara/fixture.yar tests/out/invoice_2024.exe tests/extract_rules.py <<'EOF'
|
||||
import yara, sys
|
||||
r = yara.compile(sys.argv[1])
|
||||
print("MATCH" if r.match(sys.argv[2]) else "NOMATCH", "sample")
|
||||
print("MATCH" if r.match(sys.argv[3]) else "NOMATCH", "clean")
|
||||
EOF
|
||||
)
|
||||
assert "YARA matches sample" "MATCH sample" "$o"
|
||||
assert "YARA clean no-match" "NOMATCH clean" "$o"
|
||||
elif have yara; then
|
||||
yara -w tests/fixtures/yara/fixture.yar tests/out/invoice_2024.exe | grep -q fixture && ok "yara matches sample" || bad "yara sample"
|
||||
fi
|
||||
else
|
||||
skipm "yara (pip install yara-python)"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== summary: $pass passed, $fail failed, $skip skipped"
|
||||
[ "$fail" -eq 0 ]
|
||||
Reference in New Issue
Block a user