npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- A Linux server or container has been compromised and suspicious ELF binaries are found
- Analyzing Linux botnets (Mirai, Gafgyt, XorDDoS), cryptominers, or ransomware
- Investigating malware targeting cloud infrastructure, Docker containers, or Kubernetes pods
- Reverse engineering Linux rootkits and kernel modules
- Analyzing cross-platform malware compiled for Linux x86_64, ARM, or MIPS architectures
Do not use for Windows PE binary analysis; use PEStudio, Ghidra, or IDA for Windows malware.
Prerequisites
- Ghidra or IDA with Linux ELF support for disassembly and decompilation
- Linux analysis VM (Ubuntu 22.04 recommended) with development tools installed
- strace, ltrace, and GDB for dynamic analysis and debugging
- readelf, objdump, and nm from GNU binutils for static inspection
- Radare2 for quick binary triage and scripted analysis
- Docker for isolated container-based malware execution
Workflow
Step 1: Identify ELF Binary Properties
Examine the ELF header and basic properties:
# File type identification
file suspect_binary
# Detailed ELF header analysis
readelf -h suspect_binary
# Section headers
readelf -S suspect_binary
# Program headers (segments)
readelf -l suspect_binary
# Symbol table (if not stripped)
readelf -s suspect_binary
nm suspect_binary 2>/dev/null
# Dynamic linking information
readelf -d suspect_binary
ldd suspect_binary 2>/dev/null # Only on matching architecture!
# Compute hashes
md5sum suspect_binary
sha256sum suspect_binary
# Check for packing/UPX
upx -t suspect_binary# Python-based ELF analysis
from elftools.elf.elffile import ELFFile
import hashlib
with open("suspect_binary", "rb") as f:
data = f.read()
sha256 = hashlib.sha256(data).hexdigest()
with open("suspect_binary", "rb") as f:
elf = ELFFile(f)
print(f"SHA-256: {sha256}")
print(f"Class: {elf.elfclass}-bit")
print(f"Endian: {elf.little_endian and 'Little' or 'Big'}")
print(f"Machine: {elf.header.e_machine}")
print(f"Type: {elf.header.e_type}")
print(f"Entry Point: 0x{elf.header.e_entry:X}")
# Check if stripped
symtab = elf.get_section_by_name('.symtab')
print(f"Stripped: {'Yes' if symtab is None else 'No'}")
# Section entropy analysis
import math
from collections import Counter
for section in elf.iter_sections():
data = section.data()
if len(data) > 0:
entropy = -sum((c/len(data)) * math.log2(c/len(data))
for c in Counter(data).values() if c > 0)
if entropy > 7.0:
print(f" [!] High entropy section: {section.name} ({entropy:.2f})")Step 2: Extract Strings and Indicators
Search for embedded IOCs and functionality clues:
# ASCII strings
strings suspect_binary > strings_output.txt
# Search for network indicators
grep -iE "(http|https|ftp)://" strings_output.txt
grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_output.txt
grep -iE "[a-zA-Z0-9.-]+\.(com|net|org|io|ru|cn)" strings_output.txt
# Search for shell commands
grep -iE "(bash|sh|wget|curl|chmod|/tmp/|/dev/)" strings_output.txt
# Search for crypto mining indicators
grep -iE "(stratum|xmr|monero|pool\.|mining)" strings_output.txt
# Search for SSH/credential theft
grep -iE "(ssh|authorized_keys|id_rsa|shadow|passwd)" strings_output.txt
# Search for persistence mechanisms
grep -iE "(crontab|systemd|init\.d|rc\.local|ld\.so\.preload)" strings_output.txt
# FLOSS for obfuscated strings (if available)
floss suspect_binaryStep 3: Analyze System Calls and Library Usage
Identify what system calls and libraries the malware uses:
# List imported functions (dynamically linked)
readelf -r suspect_binary | grep -E "socket|connect|exec|fork|open|write|bind|listen"
# Trace system calls during execution (in isolated VM only)
strace -f -e trace=network,process,file -o strace_output.txt ./suspect_binary
# Trace library calls
ltrace -f -o ltrace_output.txt ./suspect_binary
# Key system calls to watch:
# Network: socket, connect, bind, listen, accept, sendto, recvfrom
# Process: fork, execve, clone, kill, ptrace
# File: open, read, write, unlink, rename, chmod
# Persistence: inotify_add_watch (file monitoring)Step 4: Dynamic Analysis with GDB
Debug the malware to observe runtime behavior:
# Start GDB with the binary
gdb ./suspect_binary
# Set breakpoints on key functions
(gdb) break main
(gdb) break socket
(gdb) break connect
(gdb) break execve
(gdb) break fork
# Run and analyze
(gdb) run
(gdb) info registers # View register state
(gdb) x/20s $rdi # Examine string argument
(gdb) bt # Backtrace
(gdb) continue
# For stripped binaries, break on entry point
(gdb) break *0x400580 # Entry point from readelf
(gdb) run
# Monitor network connections during execution
# In another terminal:
ss -tlnp # List listening sockets
ss -tnp # List established connectionsStep 5: Reverse Engineer with Ghidra
Perform deep code analysis on the ELF binary:
Ghidra Analysis for Linux ELF:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Import: File -> Import -> Select ELF binary
- Ghidra auto-detects ELF format and architecture
- Accept default analysis options
2. Key analysis targets:
- main() function (or entry point if stripped)
- Socket creation and connection functions
- Command dispatch logic (switch/case on received data)
- Encryption/encoding routines
- Persistence installation code
- Self-propagation/scanning functions
3. For Mirai-like botnets, look for:
- Credential list for brute-forcing (telnet/SSH)
- Attack module selection (UDP flood, SYN flood, ACK flood)
- Scanner module (port scanning for vulnerable devices)
- Killer module (killing competing botnets)
4. For cryptominers, look for:
- Mining pool connection (stratum protocol)
- Wallet address strings
- CPU/GPU utilization functions
- Process hiding techniquesStep 6: Analyze Linux-Specific Persistence
Check for persistence mechanisms:
# Check for LD_PRELOAD rootkit
strings suspect_binary | grep "ld.so.preload"
# Malware writing to /etc/ld.so.preload can hook all dynamic library calls
# Check for crontab persistence
strings suspect_binary | grep -i "cron"
# Check for systemd service creation
strings suspect_binary | grep -iE "systemd|\.service|systemctl"
# Check for init script creation
strings suspect_binary | grep -iE "init\.d|rc\.local|update-rc"
# Check for SSH key injection
strings suspect_binary | grep -i "authorized_keys"
# Check for kernel module (rootkit) loading
strings suspect_binary | grep -iE "insmod|modprobe|init_module"
# Check for process hiding
strings suspect_binary | grep -iE "proc|readdir|getdents"Key Concepts
| Term | Definition |
|---|---|
| ELF (Executable and Linkable Format) | Standard binary format for Linux executables, shared libraries, and core dumps containing headers, sections, and segments |
| Stripped Binary | ELF binary with debug symbols removed, making reverse engineering more difficult as function names are lost |
| LD_PRELOAD | Linux environment variable specifying shared libraries to load before all others; abused by rootkits to intercept system library calls |
| strace | Linux system call tracer that logs all system calls and signals made by a process, revealing file, network, and process operations |
| GOT/PLT | Global Offset Table and Procedure Linkage Table; ELF structures for dynamic linking that can be hijacked for function hooking |
| Statically Linked | Binary compiled with all library code included; common in IoT malware to run on systems without matching shared libraries |
| Mirai | Prolific Linux botnet targeting IoT devices via telnet brute-force; source code leaked, leading to many variants |
Tools & Systems
- Ghidra: NSA reverse engineering tool with full ELF support for x86, x86_64, ARM, MIPS, and other Linux architectures
- Radare2: Open-source reverse engineering framework with command-line interface for quick binary analysis and scripting
- strace: Linux system call tracing tool for observing binary behavior including file, network, and process operations
- GDB: GNU Debugger for setting breakpoints, examining memory, and stepping through Linux binary execution
- pyelftools: Python library for parsing ELF files programmatically for automated analysis pipelines
Common Scenarios
Scenario: Analyzing a Cryptominer Found on a Compromised Linux Server
Context: A cloud server shows 100% CPU usage. Investigation reveals an unknown binary running from /tmp with a suspicious name. The binary needs analysis to confirm it is a cryptominer and identify the attacker's wallet and pool.
Approach:
- Copy the binary to an analysis VM and compute SHA-256 hash
- Run
fileandreadelfto identify architecture and linking type - Extract strings and search for mining pool addresses (stratum+tcp://) and wallet addresses
- Run with strace in a sandbox to observe network connections (mining pool connection)
- Import into Ghidra to identify the mining algorithm and configuration extraction
- Check for persistence mechanisms (crontab, systemd service, SSH keys)
- Document all IOCs including pool address, wallet, C2 for updates, and persistence artifacts
Pitfalls:
- Running
lddon malware outside a sandbox (ldd can execute code in the binary) - Not checking for ARM/MIPS architecture before attempting x86_64 execution
- Missing companion scripts (.sh files) that may handle persistence and cleanup
- Ignoring the initial access vector (how the miner was deployed: SSH brute force, web exploit, container escape)
Output Format
LINUX ELF MALWARE ANALYSIS REPORT
====================================
File: /tmp/.X11-unix/.rsync
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
Type: ELF 64-bit LSB executable, x86-64
Linking: Statically linked (all libraries embedded)
Stripped: Yes
Size: 2,847,232 bytes
Packer: UPX 3.96 (unpacked for analysis)
CLASSIFICATION
Family: XMRig Cryptominer (modified)
Variant: Custom build with C2 update mechanism
FUNCTIONALITY
[*] XMR (Monero) mining via RandomX algorithm
[*] Stratum pool connection for work submission
[*] C2 check-in for configuration updates
[*] Process name masquerading (argv[0] = "[kworker/0:0]")
[*] Competitor process killing (kills other miners)
[*] SSH key injection for re-access
NETWORK INDICATORS
Mining Pool: stratum+tcp://pool.minexmr[.]com:4444
C2 Server: hxxp://update.malicious[.]com/config
Wallet: 49jZ5Q3b...Monero_Wallet_Address...
PERSISTENCE
[1] Crontab entry: */5 * * * * /tmp/.X11-unix/.rsync
[2] SSH key added to /root/.ssh/authorized_keys
[3] Systemd service: /etc/systemd/system/rsync-daemon.service
[4] Modified /etc/ld.so.preload for process hiding
PROCESS HIDING
LD_PRELOAD: /usr/lib/.libsystem.so
Hook: readdir() to hide /tmp/.X11-unix/.rsync from ls
Hook: fopen() to hide from /proc/*/maps readingReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md3.1 KB
API Reference: Linux ELF Malware Analysis Tools
readelf - ELF Binary Inspection
Syntax
readelf -h <binary> # ELF header
readelf -S <binary> # Section headers
readelf -l <binary> # Program headers (segments)
readelf -s <binary> # Symbol table
readelf -d <binary> # Dynamic section
readelf -r <binary> # Relocation entries
readelf -n <binary> # Notes sectionKey ELF Header Fields
| Field | Description |
|---|---|
Class |
32-bit or 64-bit |
Machine |
Architecture (x86-64, ARM, MIPS) |
Type |
EXEC (executable), DYN (shared object) |
Entry point |
Code execution start address |
pyelftools - Python ELF Parsing
Usage
from elftools.elf.elffile import ELFFile
with open("binary", "rb") as f:
elf = ELFFile(f)
elf.elfclass # 32 or 64
elf.little_endian # True/False
elf.header.e_machine # Architecture
elf.header.e_entry # Entry point
elf.num_sections() # Section count
elf.get_section_by_name(".symtab") # Symbol tablestrings - String Extraction
Syntax
strings <binary> # ASCII strings (default min 4)
strings -n 8 <binary> # Minimum 8 characters
strings -e l <binary> # 16-bit little-endian (Unicode)
strings -t x <binary> # Print offset in hexstrace - System Call Tracing
Syntax
strace -f ./binary # Follow forks
strace -e trace=network ./binary # Network calls only
strace -e trace=file ./binary # File operations only
strace -e trace=process ./binary # Process operations
strace -o output.txt ./binary # Log to file
strace -c ./binary # Summary statisticsKey System Calls
| Call | Category |
|---|---|
socket, connect, bind |
Network |
fork, execve, clone |
Process |
open, read, write, unlink |
File I/O |
ptrace |
Anti-debug/injection |
ltrace - Library Call Tracing
Syntax
ltrace -f ./binary # Follow child processes
ltrace -e malloc+free ./binary # Specific functions
ltrace -o output.txt ./binary # Log to fileGDB - GNU Debugger
Syntax
gdb ./binary
(gdb) break main
(gdb) break *0x400580 # Break at address
(gdb) run
(gdb) info registers
(gdb) x/20s $rdi # Examine string at RDI
(gdb) x/10i $rip # Disassemble at RIP
(gdb) bt # BacktraceUPX - Packer Detection/Unpacking
Syntax
upx -t <binary> # Test if packed
upx -d <binary> # Decompress/unpack
upx -l <binary> # List compression detailsobjdump - Disassembly
Syntax
objdump -d <binary> # Disassemble .text
objdump -D <binary> # Disassemble all sections
objdump -M intel -d <binary> # Intel syntax
objdump -t <binary> # Symbol tablenm - Symbol Listing
Syntax
nm <binary> # List symbols
nm -D <binary> # Dynamic symbols only
nm -u <binary> # Undefined (imported) symbolsScripts 1
agent.py8.6 KB
#!/usr/bin/env python3
"""Linux ELF malware static analysis agent using pyelftools and binary inspection."""
import hashlib
import math
import os
import sys
import subprocess
from collections import Counter
try:
from elftools.elf.elffile import ELFFile
HAS_ELFTOOLS = True
except ImportError:
HAS_ELFTOOLS = False
def compute_hashes(filepath):
"""Compute MD5, SHA1, and SHA256 hashes of a file."""
md5 = hashlib.md5()
sha1 = hashlib.sha1()
sha256 = hashlib.sha256()
with open(filepath, "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 calculate_entropy(data):
"""Calculate Shannon entropy of binary data."""
if not data:
return 0.0
counter = Counter(data)
length = len(data)
return -sum((c / length) * math.log2(c / length) for c in counter.values())
def analyze_elf_header(filepath):
"""Parse ELF header and extract key properties."""
if not HAS_ELFTOOLS:
return {"error": "pyelftools not installed: pip install pyelftools"}
with open(filepath, "rb") as f:
elf = ELFFile(f)
symtab = elf.get_section_by_name(".symtab")
info = {
"class": f"{elf.elfclass}-bit",
"endian": "Little" if elf.little_endian else "Big",
"machine": elf.header.e_machine,
"type": elf.header.e_type,
"entry_point": f"0x{elf.header.e_entry:X}",
"stripped": symtab is None,
"num_sections": elf.num_sections(),
"num_segments": elf.num_segments(),
}
return info
def analyze_sections(filepath):
"""Analyze ELF sections for entropy and suspicious characteristics."""
if not HAS_ELFTOOLS:
return []
sections = []
with open(filepath, "rb") as f:
elf = ELFFile(f)
for section in elf.iter_sections():
data = section.data()
if len(data) == 0:
continue
entropy = calculate_entropy(data)
sections.append({
"name": section.name,
"type": section["sh_type"],
"size": len(data),
"entropy": round(entropy, 4),
"high_entropy": entropy > 7.0,
"flags": section["sh_flags"],
})
return sections
def extract_strings(filepath, min_length=6):
"""Extract ASCII strings from the binary and categorize by type."""
stdout, _, rc = subprocess.run(
["strings", "-n", str(min_length), filepath],
capture_output=True, text=True, timeout=120
).stdout, "", 0
if not stdout:
return {}
all_strings = stdout.strip().splitlines()
categorized = {
"urls": [], "ips": [], "domains": [], "shell_commands": [],
"crypto_mining": [], "persistence": [], "ssh_related": [],
"total": len(all_strings),
}
for s in all_strings:
s_lower = s.lower()
if any(proto in s_lower for proto in ["http://", "https://", "ftp://"]):
categorized["urls"].append(s)
if any(p in s_lower for p in ["stratum", "xmr", "monero", "pool.", "mining"]):
categorized["crypto_mining"].append(s)
if any(p in s_lower for p in ["crontab", "systemd", "init.d", "rc.local",
"ld.so.preload", "systemctl"]):
categorized["persistence"].append(s)
if any(p in s_lower for p in ["ssh", "authorized_keys", "id_rsa", "shadow", "passwd"]):
categorized["ssh_related"].append(s)
if any(p in s_lower for p in ["bash", "wget", "curl", "chmod", "/tmp/", "/dev/"]):
categorized["shell_commands"].append(s)
import re
if re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", s):
categorized["ips"].append(s)
if re.match(r"[a-zA-Z0-9.-]+\.(com|net|org|io|ru|cn|xyz)", s):
categorized["domains"].append(s)
return categorized
def check_packing(filepath):
"""Check if the binary is packed with UPX or other packers."""
with open(filepath, "rb") as f:
data = f.read(4096)
indicators = []
if b"UPX!" in data:
indicators.append("UPX packer detected (UPX! magic)")
if b"UPX0" in data or b"UPX1" in data:
indicators.append("UPX section names found")
stdout, _, _ = subprocess.run(["upx", "-t", filepath],
capture_output=True, text=True,
stderr=subprocess.STDOUT, timeout=120).stdout, "", 0
if stdout and "packed" in stdout.lower():
indicators.append("UPX verification confirms packing")
return indicators
def analyze_dynamic_linking(filepath):
"""Analyze dynamic linking information and imported functions."""
stdout, _, rc = subprocess.run(["readelf", "-d", filepath],
capture_output=True, text=True, timeout=120).stdout, "", 0
dynamic_info = {"libraries": [], "rpath": None}
if stdout:
for line in stdout.splitlines():
if "NEEDED" in line:
lib = line.split("[")[-1].rstrip("]") if "[" in line else ""
dynamic_info["libraries"].append(lib)
if "RPATH" in line or "RUNPATH" in line:
dynamic_info["rpath"] = line.split("[")[-1].rstrip("]")
readelf_proc = subprocess.run(
["readelf", "-r", filepath],
capture_output=True, text=True,
timeout=120,
)
import re as _re
suspicious_funcs = _re.compile(r'socket|connect|exec|fork|open|write|bind|listen|send|recv')
stdout2 = "\n".join(
line for line in (readelf_proc.stdout or "").splitlines()
if suspicious_funcs.search(line)
)
dynamic_info["suspicious_imports"] = [
line.strip() for line in (stdout2 or "").splitlines() if line.strip()
]
return dynamic_info
def detect_malware_type(strings_data):
"""Classify malware type based on extracted strings."""
classifications = []
if strings_data.get("crypto_mining"):
classifications.append("Cryptominer")
if any("flood" in s.lower() or "ddos" in s.lower()
for s in strings_data.get("shell_commands", [])):
classifications.append("DDoS Botnet")
if strings_data.get("ssh_related") and strings_data.get("persistence"):
classifications.append("Backdoor/Trojan")
if any("insmod" in s or "modprobe" in s or "init_module" in s
for s in strings_data.get("shell_commands", [])):
classifications.append("Rootkit")
if any("ransom" in s.lower() or "encrypt" in s.lower() or "bitcoin" in s.lower()
for cat in strings_data.values() if isinstance(cat, list) for s in cat):
classifications.append("Ransomware")
return classifications or ["Unknown"]
if __name__ == "__main__":
print("=" * 60)
print("Linux ELF Malware Analysis Agent")
print("Static analysis with pyelftools, strings, readelf")
print("=" * 60)
target = sys.argv[1] if len(sys.argv) > 1 else None
if target and os.path.exists(target):
print(f"\n[*] Analyzing: {target}")
print(f"[*] Size: {os.path.getsize(target)} bytes")
hashes = compute_hashes(target)
print(f"[*] MD5: {hashes['md5']}")
print(f"[*] SHA256: {hashes['sha256']}")
elf_info = analyze_elf_header(target)
print(f"\n--- ELF Header ---")
for k, v in elf_info.items():
print(f" {k}: {v}")
packing = check_packing(target)
if packing:
for p in packing:
print(f"[!] {p}")
sections = analyze_sections(target)
high_ent = [s for s in sections if s.get("high_entropy")]
if high_ent:
print(f"\n[!] High entropy sections (possible packing/encryption):")
for s in high_ent:
print(f" {s['name']}: entropy={s['entropy']}, size={s['size']}")
strings_data = extract_strings(target)
print(f"\n--- Strings Analysis ({strings_data.get('total', 0)} total) ---")
for category in ["urls", "ips", "domains", "crypto_mining", "persistence", "ssh_related"]:
items = strings_data.get(category, [])
if items:
print(f" {category}: {len(items)}")
for item in items[:5]:
print(f" - {item}")
classification = detect_malware_type(strings_data)
print(f"\n[*] Classification: {', '.join(classification)}")
else:
print(f"\n[DEMO] Usage: python agent.py <elf_binary>")
print("[*] Provide a Linux ELF binary for analysis.")