security operations

Analyzing Memory Forensics with LiME and Volatility

Performs Linux memory acquisition using LiME (Linux Memory Extractor) kernel module and analysis with Volatility 3 framework. Extracts process lists, network connections, bash history, loaded kernel modules, and injected code from Linux memory images. Use when performing incident response on compromised Linux systems.

incident-responsekernel-moduleslimelinux-forensicsmemory-forensicsvolatility
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When investigating security incidents that require analyzing memory forensics with lime and volatility
  • When building detection rules or threat hunting queries for this domain
  • When SOC analysts need structured procedures for this analysis type
  • When validating security monitoring coverage for related attack techniques

Prerequisites

  • Familiarity with security operations concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Instructions

Acquire Linux memory using LiME kernel module, then analyze with Volatility 3 to extract forensic artifacts from the memory image.

# LiME acquisition
insmod lime-$(uname -r).ko "path=/evidence/memory.lime format=lime"
 
# Volatility 3 analysis
vol3 -f /evidence/memory.lime linux.pslist
vol3 -f /evidence/memory.lime linux.bash
vol3 -f /evidence/memory.lime linux.sockstat
import volatility3
from volatility3.framework import contexts, automagic
from volatility3.plugins.linux import pslist, bash, sockstat
 
# Programmatic Volatility 3 usage
context = contexts.Context()
automagics = automagic.available(context)

Key analysis steps:

  1. Acquire memory with LiME (format=lime or format=raw)
  2. List processes with linux.pslist, compare with linux.psscan
  3. Extract bash command history with linux.bash
  4. List network connections with linux.sockstat
  5. Check loaded kernel modules with linux.lsmod for rootkits

Examples

# Full forensic workflow
vol3 -f memory.lime linux.pslist | grep -v "\[kthread\]"
vol3 -f memory.lime linux.bash
vol3 -f memory.lime linux.malfind
vol3 -f memory.lime linux.lsmod
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md1.6 KB

API Reference: Analyzing Memory Forensics with LiME and Volatility

LiME (Linux Memory Extractor)

# Build LiME module
cd LiME/src && make
 
# Acquire memory (lime format - includes metadata)
insmod lime-$(uname -r).ko "path=/evidence/mem.lime format=lime"
 
# Acquire memory (raw format)
insmod lime-$(uname -r).ko "path=/evidence/mem.raw format=raw"
 
# Acquire over network
insmod lime.ko "path=tcp:4444 format=lime"
# On forensic workstation: nc target 4444 > mem.lime

Volatility 3 Linux Plugins

Plugin Description
linux.pslist List processes via task_struct
linux.psscan Brute-force scan for task_struct
linux.bash Recovered bash command history
linux.sockstat Network connections
linux.lsmod Loaded kernel modules
linux.malfind Detect injected code
linux.check_afinfo Detect network hooking
linux.tty_check Detect TTY hooking
linux.proc.Maps Process memory maps

Volatility 3 CLI

vol3 -f memory.lime linux.pslist
vol3 -f memory.lime linux.bash
vol3 -f memory.lime linux.sockstat
vol3 -f memory.lime linux.malfind
vol3 -f memory.lime linux.lsmod
vol3 -f memory.lime linux.check_afinfo

Hidden Process Detection

# Compare pslist (linked list) vs psscan (brute force)
vol3 -f mem.lime linux.pslist > pslist.txt
vol3 -f mem.lime linux.psscan > psscan.txt
diff pslist.txt psscan.txt

References

Scripts 1

agent.py7.2 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for Linux memory forensics using LiME acquisition and Volatility 3."""

import json
import subprocess
import argparse
from datetime import datetime
from pathlib import Path


def acquire_memory_lime(output_path, lime_format="lime"):
    """Acquire memory using LiME kernel module."""
    kernel_version = subprocess.run(
        ["uname", "-r"], capture_output=True, text=True, timeout=120
    ).stdout.strip()
    lime_module = f"lime-{kernel_version}.ko"
    if not Path(lime_module).exists():
        lime_module = "lime.ko"
    cmd = ["insmod", lime_module, f"path={output_path}", f"format={lime_format}"]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
    return {
        "status": "success" if result.returncode == 0 else "failed",
        "output_path": output_path,
        "format": lime_format,
        "kernel": kernel_version,
        "stderr": result.stderr,
    }


def run_vol3_plugin(image_path, plugin_name, extra_args=None):
    """Run a Volatility 3 plugin and capture output."""
    cmd = ["vol3", "-f", image_path, plugin_name]
    if extra_args:
        cmd.extend(extra_args)
    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=300,
        )
        lines = result.stdout.strip().splitlines()
        return {"plugin": plugin_name, "output": lines, "error": result.stderr.strip()}
    except subprocess.TimeoutExpired:
        return {"plugin": plugin_name, "output": [], "error": "Timeout"}


def parse_pslist_output(lines):
    """Parse Volatility linux.pslist output into structured data."""
    processes = []
    for line in lines:
        parts = line.split()
        if len(parts) >= 4 and parts[0].isdigit():
            processes.append({
                "pid": int(parts[0]),
                "ppid": int(parts[1]) if parts[1].isdigit() else 0,
                "name": parts[-1],
            })
    return processes


def list_processes(image_path):
    """List all processes from memory image."""
    result = run_vol3_plugin(image_path, "linux.pslist")
    return parse_pslist_output(result.get("output", []))


def extract_bash_history(image_path):
    """Extract bash command history from memory."""
    result = run_vol3_plugin(image_path, "linux.bash")
    commands = []
    for line in result.get("output", []):
        parts = line.split(None, 3)
        if len(parts) >= 4 and parts[0].isdigit():
            commands.append({
                "pid": int(parts[0]),
                "name": parts[1],
                "timestamp": parts[2] if len(parts) > 2 else "",
                "command": parts[3] if len(parts) > 3 else "",
            })
    return commands


def list_network_connections(image_path):
    """List network connections from memory."""
    result = run_vol3_plugin(image_path, "linux.sockstat")
    connections = []
    for line in result.get("output", []):
        if "TCP" in line or "UDP" in line:
            connections.append(line.strip())
    return connections


def list_kernel_modules(image_path):
    """List loaded kernel modules to detect rootkits."""
    result = run_vol3_plugin(image_path, "linux.lsmod")
    modules = []
    for line in result.get("output", []):
        parts = line.split()
        if parts and not parts[0].startswith("Offset"):
            modules.append({"name": parts[-1] if parts else line.strip()})
    return modules


def detect_hidden_processes(image_path):
    """Compare pslist vs psscan to find hidden processes."""
    pslist = run_vol3_plugin(image_path, "linux.pslist")
    psscan = run_vol3_plugin(image_path, "linux.psscan")
    pslist_pids = set()
    for line in pslist.get("output", []):
        parts = line.split()
        if parts and parts[0].isdigit():
            pslist_pids.add(int(parts[0]))
    hidden = []
    for line in psscan.get("output", []):
        parts = line.split()
        if parts and parts[0].isdigit():
            pid = int(parts[0])
            if pid not in pslist_pids and pid > 0:
                hidden.append({"pid": pid, "line": line.strip()})
    return hidden


def detect_suspicious_commands(bash_history):
    """Flag suspicious commands in bash history."""
    suspicious_patterns = [
        "curl.*|.*sh", "wget.*&&.*chmod", "base64.*-d",
        "nc.*-e", "python.*-c.*import.*socket",
        "nohup", "rm.*-rf.*/var/log", "history.*-c",
        "iptables.*-F", "chmod.*777", "chattr.*-i",
    ]
    import re
    findings = []
    for entry in bash_history:
        cmd = entry.get("command", "")
        for pattern in suspicious_patterns:
            if re.search(pattern, cmd, re.IGNORECASE):
                findings.append({
                    "pid": entry["pid"],
                    "command": cmd,
                    "pattern": pattern,
                    "severity": "HIGH",
                })
                break
    return findings


def check_malfind(image_path):
    """Run malfind to detect injected code."""
    result = run_vol3_plugin(image_path, "linux.malfind")
    return result.get("output", [])


def main():
    parser = argparse.ArgumentParser(description="LiME + Volatility 3 Forensics Agent")
    parser.add_argument("--image", help="Path to memory image")
    parser.add_argument("--acquire", help="Output path for LiME acquisition")
    parser.add_argument("--output", default="memory_forensics_report.json")
    parser.add_argument("--action", choices=[
        "acquire", "pslist", "bash", "network", "modules",
        "hidden", "malfind", "full_analysis"
    ], default="full_analysis")
    args = parser.parse_args()

    report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}

    if args.action == "acquire" and args.acquire:
        result = acquire_memory_lime(args.acquire)
        report["findings"]["acquisition"] = result
        print(f"[+] Memory acquisition: {result['status']}")
        return

    if not args.image:
        print("[-] --image required for analysis actions")
        return

    if args.action in ("pslist", "full_analysis"):
        procs = list_processes(args.image)
        report["findings"]["processes"] = procs
        print(f"[+] Processes: {len(procs)}")

    if args.action in ("bash", "full_analysis"):
        history = extract_bash_history(args.image)
        report["findings"]["bash_history"] = history
        suspicious = detect_suspicious_commands(history)
        report["findings"]["suspicious_commands"] = suspicious
        print(f"[+] Bash commands: {len(history)}, Suspicious: {len(suspicious)}")

    if args.action in ("network", "full_analysis"):
        conns = list_network_connections(args.image)
        report["findings"]["connections"] = conns
        print(f"[+] Network connections: {len(conns)}")

    if args.action in ("modules", "full_analysis"):
        modules = list_kernel_modules(args.image)
        report["findings"]["kernel_modules"] = modules
        print(f"[+] Kernel modules: {len(modules)}")

    if args.action in ("hidden", "full_analysis"):
        hidden = detect_hidden_processes(args.image)
        report["findings"]["hidden_processes"] = hidden
        print(f"[+] Hidden processes: {len(hidden)}")

    with open(args.output, "w") as f:
        json.dump(report, f, indent=2, default=str)
    print(f"[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
Keep exploring