mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-05 23:38:57 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
174 lines
5.5 KiB
Python
174 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for extracting configuration from Agent Tesla RAT samples (malware analysis)."""
|
|
|
|
import argparse
|
|
import base64
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import re
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
AGENT_TESLA_INDICATORS = {
|
|
"strings": [
|
|
"smtp.gmail.com", "smtp.yandex.com", "SmtpPort",
|
|
"KeyboardHook", "ClipboardLogger", "ScreenCapture",
|
|
"GetClipboardData", "GetForegroundWindow",
|
|
"Mozilla/5.0", "passwords.txt",
|
|
],
|
|
"namespaces": [
|
|
"AgentTesla", "WebMonitor", "HPDefender",
|
|
"GodMode", "AKStealer", "Origin Logger",
|
|
],
|
|
}
|
|
|
|
|
|
def compute_file_hashes(file_path):
|
|
"""Compute MD5, SHA1, SHA256 of a file."""
|
|
md5 = hashlib.md5()
|
|
sha1 = hashlib.sha1()
|
|
sha256 = hashlib.sha256()
|
|
with open(file_path, "rb") as f:
|
|
for chunk in iter(lambda: f.read(65536), b""):
|
|
md5.update(chunk)
|
|
sha1.update(chunk)
|
|
sha256.update(chunk)
|
|
return {
|
|
"md5": md5.hexdigest(),
|
|
"sha1": sha1.hexdigest(),
|
|
"sha256": sha256.hexdigest(),
|
|
}
|
|
|
|
|
|
def extract_strings(file_path, min_len=6):
|
|
"""Extract ASCII and wide strings from binary."""
|
|
strings = []
|
|
with open(file_path, "rb") as f:
|
|
data = f.read()
|
|
# ASCII strings
|
|
for match in re.finditer(rb'[\x20-\x7e]{%d,}' % min_len, data):
|
|
strings.append(match.group().decode("ascii", errors="replace"))
|
|
# Wide strings (UTF-16LE)
|
|
for match in re.finditer(rb'(?:[\x20-\x7e]\x00){%d,}' % min_len, data):
|
|
try:
|
|
strings.append(match.group().decode("utf-16-le", errors="replace"))
|
|
except UnicodeDecodeError:
|
|
pass
|
|
return strings
|
|
|
|
|
|
def find_smtp_config(strings_list):
|
|
"""Extract SMTP configuration from string artifacts."""
|
|
config = {"smtp_server": None, "smtp_port": None, "email": None, "password": None}
|
|
for s in strings_list:
|
|
if re.match(r'smtp\.\w+\.\w+', s, re.I):
|
|
config["smtp_server"] = s
|
|
if re.match(r'^\d{2,5}$', s) and int(s) in (25, 465, 587, 2525):
|
|
config["smtp_port"] = int(s)
|
|
if re.match(r'[\w.+-]+@[\w-]+\.[\w.]+', s):
|
|
config["email"] = s
|
|
return config
|
|
|
|
|
|
def find_ftp_config(strings_list):
|
|
"""Extract FTP exfiltration configuration."""
|
|
config = {"ftp_server": None, "ftp_user": None, "ftp_password": None}
|
|
for s in strings_list:
|
|
if re.match(r'ftp\.\w+\.\w+', s, re.I):
|
|
config["ftp_server"] = s
|
|
if "ftp://" in s.lower():
|
|
config["ftp_url"] = s
|
|
return config
|
|
|
|
|
|
def find_telegram_config(strings_list):
|
|
"""Extract Telegram bot exfiltration config."""
|
|
config = {"bot_token": None, "chat_id": None}
|
|
for s in strings_list:
|
|
if re.match(r'\d{8,12}:[A-Za-z0-9_-]{35}', s):
|
|
config["bot_token"] = s
|
|
if re.match(r'^-?\d{9,13}$', s):
|
|
config["chat_id"] = s
|
|
return config
|
|
|
|
|
|
def decode_base64_strings(strings_list):
|
|
"""Try to decode base64-encoded configuration strings."""
|
|
decoded = []
|
|
for s in strings_list:
|
|
if len(s) > 20 and re.match(r'^[A-Za-z0-9+/=]+$', s):
|
|
try:
|
|
d = base64.b64decode(s).decode("utf-8", errors="replace")
|
|
if any(c.isprintable() for c in d) and len(d) > 4:
|
|
decoded.append({"encoded": s[:40], "decoded": d[:100]})
|
|
except Exception:
|
|
pass
|
|
return decoded
|
|
|
|
|
|
def analyze_sample(file_path):
|
|
"""Full analysis of suspected Agent Tesla sample."""
|
|
hashes = compute_file_hashes(file_path)
|
|
strings = extract_strings(file_path)
|
|
|
|
indicators_found = []
|
|
for indicator in AGENT_TESLA_INDICATORS["strings"]:
|
|
if any(indicator.lower() in s.lower() for s in strings):
|
|
indicators_found.append(indicator)
|
|
|
|
smtp = find_smtp_config(strings)
|
|
ftp = find_ftp_config(strings)
|
|
telegram = find_telegram_config(strings)
|
|
b64_decoded = decode_base64_strings(strings)
|
|
|
|
return {
|
|
"file": file_path,
|
|
"file_size": os.path.getsize(file_path),
|
|
"hashes": hashes,
|
|
"agent_tesla_indicators": indicators_found,
|
|
"is_agent_tesla": len(indicators_found) >= 3,
|
|
"config": {
|
|
"smtp": smtp,
|
|
"ftp": ftp,
|
|
"telegram": telegram,
|
|
},
|
|
"base64_decoded": b64_decoded[:10],
|
|
"total_strings": len(strings),
|
|
}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Extract configuration from Agent Tesla RAT samples"
|
|
)
|
|
parser.add_argument("sample", help="Path to suspected Agent Tesla sample")
|
|
parser.add_argument("--output", "-o", help="Output JSON report")
|
|
parser.add_argument("--verbose", "-v", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
print("[*] Agent Tesla Configuration Extraction Agent")
|
|
result = analyze_sample(args.sample)
|
|
|
|
print(f"[*] SHA256: {result['hashes']['sha256']}")
|
|
print(f"[*] Agent Tesla indicators: {len(result['agent_tesla_indicators'])}")
|
|
print(f"[*] Likely Agent Tesla: {result['is_agent_tesla']}")
|
|
|
|
if result["config"]["smtp"]["smtp_server"]:
|
|
print(f"[*] SMTP C2: {result['config']['smtp']['smtp_server']}")
|
|
if result["config"]["telegram"]["bot_token"]:
|
|
print(f"[*] Telegram bot found")
|
|
|
|
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "analysis": result}
|
|
|
|
if args.output:
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
print(f"[*] Report saved to {args.output}")
|
|
else:
|
|
print(json.dumps(report, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|