incident response

Implementing Velociraptor for IR Collection

Deploy and configure Velociraptor for scalable endpoint forensic artifact collection during incident response using VQL queries, hunts, and pre-built artifact packs across Windows, Linux, and macOS environments.

dfirendpoint-collectionforensic-artifactsincident-responserapid7threat-huntingvelociraptorvql
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Velociraptor is an advanced open-source endpoint monitoring, digital forensics, and incident response platform developed by Rapid7. It uses the Velociraptor Query Language (VQL) to create custom artifacts that collect, query, and monitor almost any aspect of an endpoint. Velociraptor enables incident response teams to rapidly collect and examine forensic artifacts from across a network, supporting large-scale deployments with minimal performance impact. The client-server architecture with Fleetspeak communication enables real-time data collection from thousands of endpoints simultaneously, with offline endpoints picking up hunts when they reconnect.

When to Use

  • When deploying or configuring implementing velociraptor for ir collection capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • Familiarity with incident response 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

Architecture

Components

  • Velociraptor Server: Central management console with web UI and API
  • Velociraptor Client (Agent): Lightweight agent deployed to endpoints
  • Fleetspeak: Communication framework between client and server
  • VQL Engine: Query language engine for artifact collection
  • Filestore: Server-side storage for collected artifacts
  • Datastore: Metadata storage for hunts, flows, and client information

Supported Platforms

  • Windows (7+, Server 2008R2+)
  • Linux (Debian, Ubuntu, CentOS, RHEL)
  • macOS (10.13+)

Deployment

Server Installation

# Download latest release
wget https://github.com/Velocidex/velociraptor/releases/latest/download/velociraptor-linux-amd64
 
# Generate server configuration
./velociraptor-linux-amd64 config generate -i
 
# Start the server
./velociraptor-linux-amd64 --config server.config.yaml frontend
 
# Or run as systemd service
sudo cp velociraptor-linux-amd64 /usr/local/bin/velociraptor
sudo velociraptor --config /etc/velociraptor/server.config.yaml service install

Client Deployment

# Repack client MSI for Windows deployment
velociraptor --config server.config.yaml config client > client.config.yaml
velociraptor config repack --msi velociraptor-windows-amd64.msi client.config.yaml output.msi
 
# Deploy via Group Policy, SCCM, or Intune
# Client runs as a Windows service: "Velociraptor"
 
# Linux client deployment
velociraptor --config client.config.yaml client -v
 
# macOS client deployment
velociraptor --config client.config.yaml client -v

Docker Deployment

docker run --name velociraptor \
  -v /opt/velociraptor:/velociraptor/data \
  -p 8000:8000 -p 8001:8001 -p 8889:8889 \
  velocidex/velociraptor

Core IR Artifact Collection

Windows Forensic Artifacts

-- Collect Windows Event Logs
SELECT * FROM Artifact.Windows.EventLogs.EvtxHunter(
  EvtxGlob="C:/Windows/System32/winevt/Logs/*.evtx",
  IDRegex="4624|4625|4648|4672|4688|4698|4769|7045"
)
 
-- Collect Prefetch files for execution evidence
SELECT * FROM Artifact.Windows.Forensics.Prefetch()
 
-- Collect Shimcache entries
SELECT * FROM Artifact.Windows.Registry.AppCompatCache()
 
-- Collect Amcache entries
SELECT * FROM Artifact.Windows.Forensics.Amcache()
 
-- Collect UserAssist data
SELECT * FROM Artifact.Windows.Forensics.UserAssist()
 
-- Collect NTFS MFT timestamps
SELECT * FROM Artifact.Windows.NTFS.MFT(
  MFTFilename="C:/$MFT",
  FileRegex=".(exe|dll|ps1|bat|cmd)$"
)
 
-- Collect scheduled tasks
SELECT * FROM Artifact.Windows.System.TaskScheduler()
 
-- Collect running processes with hashes
SELECT * FROM Artifact.Windows.System.Pslist()
 
-- Collect network connections
SELECT * FROM Artifact.Windows.Network.Netstat()
 
-- Collect DNS cache
SELECT * FROM Artifact.Windows.Network.DNSCache()
 
-- Collect browser history
SELECT * FROM Artifact.Windows.Applications.Chrome.History()
 
-- Collect PowerShell history
SELECT * FROM Artifact.Windows.Forensics.PowerShellHistory()
 
-- Collect autoruns/persistence
SELECT * FROM Artifact.Windows.Persistence.PermanentWMIEvents()
SELECT * FROM Artifact.Windows.System.Services()
SELECT * FROM Artifact.Windows.System.StartupItems()

Linux Forensic Artifacts

-- Collect auth logs
SELECT * FROM Artifact.Linux.Sys.AuthLogs()
 
-- Collect bash history
SELECT * FROM Artifact.Linux.Forensics.BashHistory()
 
-- Collect crontab entries
SELECT * FROM Artifact.Linux.Sys.Crontab()
 
-- Collect running processes
SELECT * FROM Artifact.Linux.Sys.Pslist()
 
-- Collect network connections
SELECT * FROM Artifact.Linux.Network.Netstat()
 
-- Collect SSH authorized keys
SELECT * FROM Artifact.Linux.Ssh.AuthorizedKeys()
 
-- Collect systemd services
SELECT * FROM Artifact.Linux.Services()

Triage Collection (All-in-One)

-- Windows Triage Collection artifact
-- Collects event logs, prefetch, registry, browser data, and more
SELECT * FROM Artifact.Windows.KapeFiles.Targets(
  Device="C:",
  _AllFiles=FALSE,
  _EventLogs=TRUE,
  _Prefetch=TRUE,
  _RegistryHives=TRUE,
  _WebBrowsers=TRUE,
  _WindowsTimeline=TRUE
)

Hunt Operations

Creating a Hunt

1. Navigate to Hunt Manager in Velociraptor Web UI
2. Click "New Hunt"
3. Configure:
   - Description: "IR Triage - Case 2025-001"
   - Include/Exclude labels for targeting
   - Artifact selection (e.g., Windows.Forensics.Prefetch)
   - Resource limits (CPU, IOPS, timeout)
4. Launch hunt
5. Monitor progress in real-time

VQL Hunt Examples

-- Hunt for specific file hash across all endpoints
SELECT * FROM Artifact.Generic.Detection.HashHunter(
  Hashes="e99a18c428cb38d5f260853678922e03"
)
 
-- Hunt for YARA signatures in memory
SELECT * FROM Artifact.Windows.Detection.Yara.Process(
  YaraRule='rule malware { strings: $s1 = "malicious_string" condition: $s1 }'
)
 
-- Hunt for Sigma rule matches in event logs
SELECT * FROM Artifact.Server.Import.SigmaRules()
 
-- Hunt for suspicious scheduled tasks
SELECT * FROM Artifact.Windows.System.TaskScheduler()
WHERE Command =~ "powershell|cmd|wscript|mshta|rundll32"
 
-- Hunt for processes with network connections to suspicious IPs
SELECT * FROM Artifact.Windows.Network.Netstat()
WHERE RemoteAddr =~ "10\\.13\\.37\\."

Real-Time Monitoring

-- Monitor for new process creation
SELECT * FROM watch_etw(guid="{22fb2cd6-0e7b-422b-a0c7-2fad1fd0e716}")
WHERE EventData.ImageName =~ "powershell|cmd|wscript"
 
-- Monitor file system changes
SELECT * FROM watch_directory(path="C:/Windows/Temp/")
 
-- Monitor registry changes
SELECT * FROM watch_registry(key="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Run/**")

Integration with SIEM/SOAR

Splunk Integration

Velociraptor Server --> Elastic/OpenSearch --> Splunk HEC
                   --> Direct syslog forwarding
                   --> Velociraptor API --> Custom scripts --> Splunk

Elastic Stack Integration

# Velociraptor server config for Elastic output
Monitoring:
  elastic:
    addresses:
      - https://elastic.local:9200
    username: velociraptor
    password: secure_password
    index: velociraptor

MITRE ATT&CK Mapping

Technique VQL Artifact
T1059 - Command Scripting Windows.EventLogs.EvtxHunter (4104, 4688)
T1053 - Scheduled Task Windows.System.TaskScheduler
T1547 - Boot/Logon Autostart Windows.Persistence.PermanentWMIEvents
T1003 - OS Credential Dumping Windows.Detection.Yara.Process
T1021 - Remote Services Windows.EventLogs.EvtxHunter (4624 Type 3/10)
T1070 - Indicator Removal Windows.EventLogs.Cleared

References

Source materials

References and resources

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

References 3

api-reference.md4.5 KB

API Reference: Velociraptor Incident Response Collection

Libraries Used

Library Purpose
pyvelociraptor Official Python bindings for Velociraptor gRPC API
grpc gRPC transport for API communication
json Parse VQL query results
yaml Read Velociraptor API config files

Installation

pip install pyvelociraptor grpcio pyyaml

Authentication

Velociraptor uses mTLS with an API config file generated by the server:

import pyvelociraptor
import json
import os
 
# Generate API config on the Velociraptor server:
# velociraptor config api_client --name analyst > api_client.yaml
 
config_path = os.environ.get("VELOCIRAPTOR_API_CONFIG", "api_client.yaml")

gRPC API — Query Method

The primary API method is Query(), which executes VQL (Velociraptor Query Language) statements:

import pyvelociraptor
import json
 
def run_vql(config_path, query):
    config = pyvelociraptor.LoadConfigFile(config_path)
    grpc_channel = pyvelociraptor.grpc_channel(config)
    stub = pyvelociraptor.api_pb2_grpc.APIStub(grpc_channel)
 
    request = pyvelociraptor.api_pb2.VQLCollectorArgs(
        max_wait=10,
        max_row=1000,
        Query=[pyvelociraptor.api_pb2.VQLRequest(
            VQL=query,
        )],
    )
 
    results = []
    for response in stub.Query(request):
        if response.Response:
            rows = json.loads(response.Response)
            results.extend(rows)
    return results

Common VQL Queries

List Connected Clients

clients = run_vql(config_path, """
    SELECT client_id, os_info.hostname as hostname,
           os_info.system as os, last_seen_at
    FROM clients()
    WHERE last_seen_at > now() - 3600
""")

Collect Artifacts from an Endpoint

# Start a collection (hunt) on a specific client
collection = run_vql(config_path, """
    SELECT collect_client(
        client_id='C.abc123def456',
        artifacts=['Windows.KapeFiles.Targets'],
        parameters=dict(Device='C:', VSSAnalysis='Y')
    ) FROM scope()
""")
flow_id = collection[0]["collect_client"]["flow_id"]

Monitor Collection Status

status = run_vql(config_path, f"""
    SELECT * FROM flows(client_id='C.abc123def456')
    WHERE session_id = '{flow_id}'
""")
# Fields: state, create_time, total_collected_rows, total_uploaded_bytes

Retrieve Flow Results

results = run_vql(config_path, f"""
    SELECT * FROM flow_results(
        client_id='C.abc123def456',
        flow_id='{flow_id}',
        artifact='Windows.KapeFiles.Targets'
    )
""")

Hunt Across All Clients

hunt = run_vql(config_path, """
    SELECT hunt(
        description='Search for suspicious scheduled tasks',
        artifacts=['Windows.System.TaskScheduler'],
        parameters=dict()
    ) FROM scope()
""")
hunt_id = hunt[0]["hunt"]["hunt_id"]

Search for IOCs Across Fleet

ioc_results = run_vql(config_path, """
    SELECT * FROM hunt_results(hunt_id='H.abc123')
    WHERE OSPath =~ 'mimikatz|lazagne|rubeus'
""")

Key VQL Functions

Function Purpose
clients() List all enrolled clients
collect_client() Start artifact collection on endpoint
flows() List collection flows for a client
flow_results() Get results from a completed flow
hunt() Create a new hunt across clients
hunt_results() Get results from a hunt
artifact_definitions() List available artifacts
source() Read server-side event log data
upload() Upload files from endpoint to server

Built-in Artifact Categories

Category Examples
Windows Triage Windows.KapeFiles.Targets, Windows.EventLogs.Evtx
Process Forensics Windows.System.Pslist, Generic.System.Pstree
Persistence Windows.Persistence.PermanentWMIEvents, Windows.System.TaskScheduler
Network Windows.Network.Netstat, Windows.Network.ArpCache
Memory Windows.Detection.Yara.Process, Windows.System.VAD
Linux Linux.Sys.Users, Linux.Search.FileFinder
macOS MacOS.System.Users, MacOS.Applications.Chrome.History

Output Format

{
  "client_id": "C.abc123def456",
  "hostname": "WORKSTATION-01",
  "os": "windows",
  "flow_id": "F.xyz789",
  "state": "FINISHED",
  "artifacts_collected": ["Windows.KapeFiles.Targets"],
  "total_collected_rows": 1542,
  "total_uploaded_bytes": 52428800,
  "create_time": "2025-01-15T10:30:00Z"
}
standards.md1.8 KB

Standards and Frameworks for Velociraptor IR Collection

NIST SP 800-86 - Guide to Integrating Forensic Techniques

  • Evidence collection procedures for digital investigations
  • Chain of custody requirements for forensic data
  • Volatile and non-volatile evidence prioritization

ForensicArtifacts Standard

SANS DFIR Collection Standards

  • FOR500: Windows Forensic Analysis artifact prioritization
  • FOR508: Advanced Incident Response collection methodology
  • Evidence acquisition order of volatility
  • Triage collection best practices

Velociraptor Query Language (VQL) Reference

MITRE ATT&CK Framework

  • Artifact mapping to ATT&CK techniques
  • Detection-oriented collection strategies
  • Threat-informed artifact selection
  • Reference: https://attack.mitre.org/

Sigma Detection Standard

  • Velociraptor supports Sigma rule execution on endpoints
  • Direct event log analysis without SIEM forwarding
  • Community detection rules integration
  • Reference: https://github.com/SigmaHQ/sigma

CISA Recommended Practices

Rapid7 Integration Standards

  • InsightIDR SIEM integration documentation
  • Managed Detection and Response workflows
  • Velociraptor alert forwarding specifications
workflows.md3.1 KB

Velociraptor IR Collection Workflows

Workflow 1: Rapid Triage Collection

START: Incident Detected - Triage Needed
  |
  v
[Identify Target Endpoints]
  |-- Search clients by hostname, IP, or label
  |-- Verify client connectivity status
  |-- Label endpoints as "investigation_targets"
  |
  v
[Launch Triage Collection]
  |-- Select triage artifact pack
  |-- Configure collection parameters
  |-- Set resource limits (CPU, bandwidth)
  |-- Launch flow on target endpoints
  |
  v
[Monitor Collection Progress]
  |-- View flow status in Velociraptor UI
  |-- Check for collection errors
  |-- Verify artifact completeness
  |
  v
[Download and Analyze Results]
  |-- Export collected data
  |-- Import into timeline tool
  |-- Begin forensic analysis
  |
  v
END: Triage Data Available for Analysis

Workflow 2: Enterprise-Wide Hunt

START: IOC or Threat Intelligence Received
  |
  v
[Create Hunt]
  |-- Define hunt description and scope
  |-- Select target artifacts
  |-- Configure IOC-based VQL queries
  |-- Set include/exclude labels
  |
  v
[Launch Hunt]
  |-- Deploy to all matching endpoints
  |-- Offline endpoints queued for pickup
  |-- Monitor completion percentage
  |
  v
[Analyze Hunt Results]
  |-- Review matches and anomalies
  |-- Identify compromised endpoints
  |-- Label affected systems
  |
  v
[Escalate Findings]
  |-- Create detailed flows for hits
  |-- Collect additional artifacts
  |-- Feed results into IR process
  |
  v
END: Hunt Complete - Findings Documented

Workflow 3: Live Incident Response

START: Active Compromise Detected
  |
  v
[Connect to Affected Endpoint]
  |-- Open VQL shell in Velociraptor UI
  |-- Verify system identity and status
  |
  v
[Volatile Evidence Collection]
  |-- Running processes (pslist)
  |-- Network connections (netstat)
  |-- DNS cache
  |-- Open file handles
  |-- Loaded DLLs
  |-- Memory strings (if needed)
  |
  v
[Persistence Check]
  |-- Scheduled tasks
  |-- Services
  |-- Registry autorun keys
  |-- WMI subscriptions
  |-- Startup folder items
  |
  v
[Non-Volatile Evidence]
  |-- Event logs
  |-- Prefetch files
  |-- MFT entries
  |-- Browser history
  |-- PowerShell history
  |
  v
[Containment Decision]
  |-- Enough evidence to contain?
  |-- Isolate endpoint if needed
  |-- Continue monitoring if needed
  |
  v
END: Evidence Collected - Containment Executed

Workflow 4: Deployment at Scale

START: Velociraptor Deployment Project
  |
  v
[Server Setup]
  |-- Deploy server on dedicated host
  |-- Configure SSL certificates
  |-- Set up authentication (SSO/SAML)
  |-- Configure storage backend
  |
  v
[Client Configuration]
  |-- Generate client config from server
  |-- Repack client installers
  |-- Test on pilot group
  |
  v
[Mass Deployment]
  |-- GPO deployment (Windows)
  |-- Configuration management (Linux)
  |-- MDM deployment (macOS)
  |-- Verify connectivity
  |
  v
[Operational Configuration]
  |-- Set up monitoring artifacts
  |-- Configure event forwarding
  |-- Create standard hunt templates
  |-- Document SOPs for analysts
  |
  v
END: Velociraptor Operational at Scale

Scripts 2

agent.py10.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Velociraptor incident response collection agent.

Interfaces with the Velociraptor DFIR platform API to schedule artifact
collections on endpoints, retrieve results, and generate IR reports.
Supports common forensic artifacts including process listings, network
connections, autoruns, event logs, and file system evidence.
"""
import argparse
import json
import os
import sys
import time
from datetime import datetime, timezone

try:
    import requests
except ImportError:
    print("[!] 'requests' library required: pip install requests", file=sys.stderr)
    sys.exit(1)

try:
    import grpc
    HAS_GRPC = True
except ImportError:
    HAS_GRPC = False


def get_velo_config():
    """Return Velociraptor API configuration."""
    api_url = os.environ.get("VELOCIRAPTOR_API_URL", "https://localhost:8001")
    api_key = os.environ.get("VELOCIRAPTOR_API_KEY", "")
    cert_path = os.environ.get("VELOCIRAPTOR_CERT", "")
    return api_url.rstrip("/"), api_key, cert_path


def velo_api_call(api_url, api_key, endpoint, method="GET", data=None, cert_path=None):
    """Make an authenticated API call to Velociraptor."""
    url = f"{api_url}{endpoint}"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }
    verify = cert_path if cert_path else False
    if method == "POST":
        resp = requests.post(url, headers=headers, json=data, verify=verify, timeout=60)
    else:
        resp = requests.get(url, headers=headers, verify=verify, timeout=60)
    resp.raise_for_status()
    return resp.json()


def search_clients(api_url, api_key, query, cert_path=None):
    """Search for Velociraptor clients by hostname, label, or client ID."""
    print(f"[*] Searching for clients: {query}")
    data = {"query": query, "count": 100}
    result = velo_api_call(api_url, api_key, "/api/v1/SearchClients", "POST", data, cert_path)
    clients = result.get("items", [])
    print(f"[+] Found {len(clients)} client(s)")
    for c in clients:
        os_info = c.get("os_info", {})
        print(f"    {c.get('client_id', 'N/A'):20s} | "
              f"{os_info.get('hostname', 'unknown'):20s} | "
              f"{os_info.get('system', 'unknown'):10s} | "
              f"Last seen: {c.get('last_seen_at', 'N/A')}")
    return clients


def collect_artifact(api_url, api_key, client_id, artifacts, parameters=None, cert_path=None):
    """Schedule an artifact collection on a specific client."""
    print(f"[*] Scheduling collection on {client_id}: {', '.join(artifacts)}")
    specs = []
    for artifact in artifacts:
        spec = {"artifact": artifact}
        if parameters and artifact in parameters:
            spec["parameters"] = {"env": [
                {"key": k, "value": v} for k, v in parameters[artifact].items()
            ]}
        specs.append(spec)

    data = {
        "client_id": client_id,
        "artifacts": artifacts,
        "specs": specs,
    }
    result = velo_api_call(api_url, api_key, "/api/v1/CollectArtifact", "POST", data, cert_path)
    flow_id = result.get("flow_id", "")
    print(f"[+] Collection started, flow ID: {flow_id}")
    return flow_id


def get_flow_status(api_url, api_key, client_id, flow_id, cert_path=None):
    """Check the status of a collection flow."""
    data = {"client_id": client_id, "flow_id": flow_id}
    result = velo_api_call(api_url, api_key, "/api/v1/GetFlowDetails", "POST", data, cert_path)
    context = result.get("context", {})
    state = context.get("state", "UNSET")
    return state, context


def wait_for_collection(api_url, api_key, client_id, flow_id, max_wait=300, cert_path=None):
    """Poll until a collection flow completes."""
    print(f"[*] Waiting for collection to complete (max {max_wait}s)...")
    elapsed = 0
    interval = 10
    while elapsed < max_wait:
        state, context = get_flow_status(api_url, api_key, client_id, flow_id, cert_path)
        if state == "FINISHED":
            total_rows = context.get("total_collected_rows", 0)
            total_bytes = context.get("total_uploaded_bytes", 0)
            print(f"[+] Collection complete: {total_rows} rows, "
                  f"{total_bytes / 1024:.1f} KB uploaded")
            return True, context
        if state == "ERROR":
            print(f"[!] Collection failed: {context.get('status', 'unknown')}", file=sys.stderr)
            return False, context
        print(f"    State: {state} ({elapsed}s elapsed)")
        time.sleep(interval)
        elapsed += interval
    print("[!] Timed out waiting for collection", file=sys.stderr)
    return False, {}


def get_flow_results(api_url, api_key, client_id, flow_id, artifact, cert_path=None):
    """Retrieve collected artifact results."""
    print(f"[*] Retrieving results for {artifact}")
    data = {
        "client_id": client_id,
        "flow_id": flow_id,
        "artifact": artifact,
        "count": 10000,
    }
    result = velo_api_call(api_url, api_key, "/api/v1/GetTable", "POST", data, cert_path)
    rows = result.get("rows", [])
    columns = result.get("columns", [])
    print(f"[+] Retrieved {len(rows)} row(s), {len(columns)} column(s)")
    return rows, columns


IR_ARTIFACT_SETS = {
    "triage": [
        "Windows.System.Pslist",
        "Windows.Network.Netstat",
        "Windows.Sys.Users",
        "Windows.System.TaskScheduler",
        "Generic.System.Pstree",
    ],
    "persistence": [
        "Windows.Sysinternals.Autoruns",
        "Windows.System.TaskScheduler",
        "Windows.Registry.Run",
        "Windows.System.Services",
    ],
    "network": [
        "Windows.Network.Netstat",
        "Windows.Network.ArpCache",
        "Windows.Network.DNSCache",
        "Windows.Network.InterfaceAddresses",
    ],
    "logs": [
        "Windows.EventLogs.Cleared",
        "Windows.EventLogs.RDPAuth",
        "Windows.EventLogs.PowershellScriptblock",
    ],
    "linux_triage": [
        "Linux.Sys.Pslist",
        "Linux.Network.Netstat",
        "Linux.Sys.Users",
        "Linux.Sys.Crontab",
        "Linux.Sys.LastUserLogin",
    ],
}


def format_summary(client_id, artifacts, flow_context, results_summary):
    """Print collection summary."""
    print(f"\n{'='*60}")
    print(f"  Velociraptor IR Collection Report")
    print(f"{'='*60}")
    print(f"  Client ID   : {client_id}")
    print(f"  Flow ID     : {flow_context.get('session_id', 'N/A')}")
    print(f"  State       : {flow_context.get('state', 'N/A')}")
    print(f"  Artifacts   : {len(artifacts)}")
    print(f"  Total Rows  : {flow_context.get('total_collected_rows', 0)}")

    for artifact_name, row_count in results_summary.items():
        print(f"    {artifact_name:50s}: {row_count} rows")


def main():
    parser = argparse.ArgumentParser(
        description="Velociraptor IR collection agent"
    )
    sub = parser.add_subparsers(dest="command")

    p_search = sub.add_parser("search", help="Search for clients")
    p_search.add_argument("--query", required=True, help="Search query (hostname, label, client ID)")

    p_collect = sub.add_parser("collect", help="Collect artifacts from client")
    p_collect.add_argument("--client-id", required=True, help="Velociraptor client ID")
    p_collect.add_argument("--artifacts", nargs="+", help="Specific artifact names to collect")
    p_collect.add_argument("--preset", choices=list(IR_ARTIFACT_SETS.keys()),
                          help="Use a predefined IR artifact set")
    p_collect.add_argument("--wait", type=int, default=300, help="Max wait time in seconds")

    p_status = sub.add_parser("status", help="Check collection status")
    p_status.add_argument("--client-id", required=True)
    p_status.add_argument("--flow-id", required=True)

    parser.add_argument("--api-url", help="Velociraptor API URL (or VELOCIRAPTOR_API_URL env)")
    parser.add_argument("--api-key", help="API key (or VELOCIRAPTOR_API_KEY env)")
    parser.add_argument("--cert", help="CA cert path (or VELOCIRAPTOR_CERT env)")
    parser.add_argument("--output", "-o", help="Output JSON report path")
    parser.add_argument("--verbose", "-v", action="store_true")
    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        sys.exit(1)

    if args.api_url:
        os.environ["VELOCIRAPTOR_API_URL"] = args.api_url
    if args.api_key:
        os.environ["VELOCIRAPTOR_API_KEY"] = args.api_key
    if args.cert:
        os.environ["VELOCIRAPTOR_CERT"] = args.cert

    api_url, api_key, cert_path = get_velo_config()
    if not api_key:
        print("[!] Set VELOCIRAPTOR_API_KEY env var or use --api-key", file=sys.stderr)
        sys.exit(1)

    result = {}

    if args.command == "search":
        clients = search_clients(api_url, api_key, args.query, cert_path)
        result = {"action": "search", "query": args.query, "clients": clients}

    elif args.command == "collect":
        artifacts = args.artifacts or IR_ARTIFACT_SETS.get(args.preset, [])
        if not artifacts:
            print("[!] Specify --artifacts or --preset", file=sys.stderr)
            sys.exit(1)
        flow_id = collect_artifact(api_url, api_key, args.client_id, artifacts, cert_path=cert_path)
        success, context = wait_for_collection(api_url, api_key, args.client_id, flow_id, args.wait, cert_path)
        results_summary = {}
        if success:
            for artifact in artifacts:
                try:
                    rows, cols = get_flow_results(api_url, api_key, args.client_id, flow_id, artifact, cert_path)
                    results_summary[artifact] = len(rows)
                except Exception as e:
                    results_summary[artifact] = f"Error: {e}"
        format_summary(args.client_id, artifacts, context, results_summary)
        result = {"action": "collect", "client_id": args.client_id, "flow_id": flow_id,
                  "state": context.get("state", "UNKNOWN"), "artifacts": results_summary}

    elif args.command == "status":
        state, context = get_flow_status(api_url, api_key, args.client_id, args.flow_id, cert_path)
        print(f"[*] Flow {args.flow_id}: {state}")
        result = {"action": "status", "flow_id": args.flow_id, "state": state, "context": context}

    report = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "tool": "Velociraptor",
        "result": result,
    }
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"\n[+] Report saved to {args.output}")
    elif args.verbose:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
process.py12.3 KB
Display-only source. This catalog never executes bundled scripts.
"""
Velociraptor IR Collection Automation Script
Manages artifact collection, hunt creation, and result analysis via Velociraptor API.
"""

import json
import os
import csv
import hashlib
from datetime import datetime
from pathlib import Path
from collections import defaultdict


class VelociraptorCollector:
    """Manages Velociraptor artifact collection for incident response."""

    TRIAGE_ARTIFACTS_WINDOWS = [
        "Windows.EventLogs.EvtxHunter",
        "Windows.Forensics.Prefetch",
        "Windows.Registry.AppCompatCache",
        "Windows.Forensics.Amcache",
        "Windows.Forensics.UserAssist",
        "Windows.System.TaskScheduler",
        "Windows.System.Pslist",
        "Windows.Network.Netstat",
        "Windows.Network.DNSCache",
        "Windows.Forensics.PowerShellHistory",
        "Windows.System.Services",
        "Windows.System.StartupItems",
        "Windows.Persistence.PermanentWMIEvents",
    ]

    TRIAGE_ARTIFACTS_LINUX = [
        "Linux.Sys.AuthLogs",
        "Linux.Forensics.BashHistory",
        "Linux.Sys.Crontab",
        "Linux.Sys.Pslist",
        "Linux.Network.Netstat",
        "Linux.Ssh.AuthorizedKeys",
        "Linux.Services",
    ]

    def __init__(self, server_url=None, api_key=None, output_dir="velociraptor_results"):
        self.server_url = server_url or "https://localhost:8001"
        self.api_key = api_key
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        self.collection_manifest = []

    def generate_vql_triage_pack(self, target_os="windows", output_file=None):
        """Generate VQL artifact collection pack for triage."""
        artifacts = (
            self.TRIAGE_ARTIFACTS_WINDOWS
            if target_os == "windows"
            else self.TRIAGE_ARTIFACTS_LINUX
        )

        vql_queries = []
        for artifact in artifacts:
            vql_queries.append({
                "artifact": artifact,
                "vql": f"SELECT * FROM Artifact.{artifact}()",
                "description": f"Collect {artifact.split('.')[-1]} artifacts",
            })

        pack = {
            "name": f"IR Triage Pack - {target_os.title()}",
            "version": "1.0",
            "generated": datetime.utcnow().isoformat(),
            "target_os": target_os,
            "artifacts": vql_queries,
        }

        if output_file is None:
            output_file = self.output_dir / f"triage_pack_{target_os}.json"

        with open(output_file, "w") as f:
            json.dump(pack, f, indent=2)

        print(f"[+] Generated {target_os} triage pack: {output_file}")
        print(f"    Artifacts: {len(vql_queries)}")
        return pack

    def generate_hunt_config(self, hunt_name, description, artifacts, parameters=None,
                              include_labels=None, exclude_labels=None):
        """Generate hunt configuration for enterprise-wide collection."""
        hunt_config = {
            "hunt_name": hunt_name,
            "description": description,
            "created": datetime.utcnow().isoformat(),
            "artifacts": artifacts,
            "parameters": parameters or {},
            "targeting": {
                "include_labels": include_labels or [],
                "exclude_labels": exclude_labels or [],
            },
            "resource_limits": {
                "cpu_limit": 50,
                "iops_limit": 100,
                "timeout_seconds": 600,
                "max_rows": 100000,
                "max_upload_bytes": 104857600,
            },
        }

        config_file = self.output_dir / f"hunt_{hunt_name.replace(' ', '_')}.json"
        with open(config_file, "w") as f:
            json.dump(hunt_config, f, indent=2)

        print(f"[+] Generated hunt config: {config_file}")
        return hunt_config

    def generate_ioc_hunt(self, iocs, hunt_name="IOC Hunt"):
        """Generate VQL-based IOC hunt queries."""
        vql_queries = []

        if "hashes" in iocs:
            hash_list = "|".join(iocs["hashes"])
            vql_queries.append({
                "name": "Hash Hunt",
                "vql": f"""SELECT * FROM Artifact.Generic.Detection.HashHunter(
                    Hashes='{hash_list}'
                )""",
            })

        if "ips" in iocs:
            ip_regex = "|".join(ip.replace(".", "\\.") for ip in iocs["ips"])
            vql_queries.append({
                "name": "Network Connection Hunt",
                "vql": f"""SELECT * FROM Artifact.Windows.Network.Netstat()
                    WHERE RemoteAddr =~ '{ip_regex}'""",
            })

        if "domains" in iocs:
            domain_regex = "|".join(d.replace(".", "\\.") for d in iocs["domains"])
            vql_queries.append({
                "name": "DNS Cache Hunt",
                "vql": f"""SELECT * FROM Artifact.Windows.Network.DNSCache()
                    WHERE Name =~ '{domain_regex}'""",
            })

        if "filenames" in iocs:
            file_regex = "|".join(iocs["filenames"])
            vql_queries.append({
                "name": "File Hunt",
                "vql": f"""SELECT * FROM Artifact.Windows.NTFS.MFT(
                    FileRegex='{file_regex}'
                )""",
            })

        if "yara_rules" in iocs:
            for rule_name, rule_content in iocs["yara_rules"].items():
                vql_queries.append({
                    "name": f"YARA Hunt - {rule_name}",
                    "vql": f"""SELECT * FROM Artifact.Windows.Detection.Yara.Process(
                        YaraRule='{rule_content}'
                    )""",
                })

        hunt_file = self.output_dir / f"ioc_hunt_{hunt_name.replace(' ', '_')}.json"
        with open(hunt_file, "w") as f:
            json.dump({"name": hunt_name, "queries": vql_queries}, f, indent=2)

        print(f"[+] Generated IOC hunt with {len(vql_queries)} queries: {hunt_file}")
        return vql_queries

    def generate_collection_checklist(self, case_id, target_hosts):
        """Generate collection checklist for IR case."""
        checklist = {
            "case_id": case_id,
            "generated": datetime.utcnow().isoformat(),
            "targets": [],
        }

        for host in target_hosts:
            target = {
                "hostname": host,
                "collections": [
                    {"artifact": "Volatile Data", "status": "pending", "items": [
                        "Running processes", "Network connections", "DNS cache",
                        "Logged-in users", "Open files",
                    ]},
                    {"artifact": "Event Logs", "status": "pending", "items": [
                        "Security.evtx", "System.evtx", "Application.evtx",
                        "PowerShell/Operational.evtx", "Sysmon/Operational.evtx",
                    ]},
                    {"artifact": "Execution Evidence", "status": "pending", "items": [
                        "Prefetch files", "Amcache.hve", "Shimcache",
                        "UserAssist", "BAM/DAM",
                    ]},
                    {"artifact": "Persistence Mechanisms", "status": "pending", "items": [
                        "Scheduled tasks", "Services", "Registry Run keys",
                        "WMI subscriptions", "Startup items",
                    ]},
                    {"artifact": "File System", "status": "pending", "items": [
                        "MFT entries", "USN Journal", "Recycle Bin",
                        "Recent files", "Downloads folder",
                    ]},
                    {"artifact": "User Activity", "status": "pending", "items": [
                        "Browser history", "PowerShell history", "RDP cache",
                        "Recent documents", "Jump lists",
                    ]},
                ],
            }
            checklist["targets"].append(target)

        checklist_file = self.output_dir / f"collection_checklist_{case_id}.json"
        with open(checklist_file, "w") as f:
            json.dump(checklist, f, indent=2)

        print(f"[+] Collection checklist for {len(target_hosts)} hosts: {checklist_file}")
        return checklist

    def analyze_collection_results(self, results_dir):
        """Analyze collected Velociraptor results for suspicious indicators."""
        results_path = Path(results_dir)
        findings = []

        for json_file in results_path.glob("**/*.json"):
            try:
                with open(json_file) as f:
                    data = json.load(f)
                if isinstance(data, list):
                    for item in data:
                        finding = self._check_for_indicators(item, str(json_file))
                        if finding:
                            findings.append(finding)
            except (json.JSONDecodeError, KeyError):
                continue

        findings_file = self.output_dir / "analysis_findings.json"
        with open(findings_file, "w") as f:
            json.dump(findings, f, indent=2, default=str)

        print(f"[+] Analysis complete: {len(findings)} findings -> {findings_file}")
        return findings

    def _check_for_indicators(self, item, source_file):
        """Check a single result item for suspicious indicators."""
        suspicious_processes = [
            "mimikatz", "rubeus", "lazagne", "sharphound", "bloodhound",
            "cobaltstrike", "beacon", "psexec", "wmiexec", "smbexec",
        ]
        suspicious_commands = [
            "invoke-mimikatz", "invoke-expression", "downloadstring",
            "net user /add", "net localgroup administrators",
            "reg save hklm\\sam", "reg save hklm\\system",
            "ntdsutil", "vssadmin create shadow",
        ]

        name = str(item.get("Name", "") or item.get("CommandLine", "")).lower()

        for proc in suspicious_processes:
            if proc in name:
                return {
                    "severity": "CRITICAL",
                    "indicator": f"Suspicious process: {proc}",
                    "detail": item,
                    "source": source_file,
                }

        for cmd in suspicious_commands:
            if cmd in name:
                return {
                    "severity": "HIGH",
                    "indicator": f"Suspicious command: {cmd}",
                    "detail": item,
                    "source": source_file,
                }

        return None

    def generate_report(self):
        """Generate collection summary report."""
        report = {
            "title": "Velociraptor IR Collection Report",
            "generated": datetime.utcnow().isoformat(),
            "collections": self.collection_manifest,
            "output_directory": str(self.output_dir),
        }

        report_file = self.output_dir / "collection_report.json"
        with open(report_file, "w") as f:
            json.dump(report, f, indent=2)

        print(f"[+] Collection report: {report_file}")
        return report


def main():
    import argparse

    parser = argparse.ArgumentParser(description="Velociraptor IR Collection Manager")
    parser.add_argument("--action", choices=[
        "triage-pack", "hunt-config", "ioc-hunt", "checklist", "analyze",
    ], required=True)
    parser.add_argument("--os", default="windows", choices=["windows", "linux"])
    parser.add_argument("--case-id", default="IR-2025-001")
    parser.add_argument("--hosts", nargs="+", help="Target hostnames")
    parser.add_argument("--iocs", help="JSON file with IOCs")
    parser.add_argument("--results-dir", help="Directory with collection results")
    parser.add_argument("-o", "--output", default="velociraptor_results")

    args = parser.parse_args()
    collector = VelociraptorCollector(output_dir=args.output)

    if args.action == "triage-pack":
        collector.generate_vql_triage_pack(target_os=args.os)
    elif args.action == "hunt-config":
        collector.generate_hunt_config("IR Hunt", "Incident response hunt",
                                        collector.TRIAGE_ARTIFACTS_WINDOWS)
    elif args.action == "ioc-hunt":
        if args.iocs:
            with open(args.iocs) as f:
                iocs = json.load(f)
            collector.generate_ioc_hunt(iocs)
    elif args.action == "checklist":
        hosts = args.hosts or ["WKS001", "SRV001", "DC01"]
        collector.generate_collection_checklist(args.case_id, hosts)
    elif args.action == "analyze":
        if args.results_dir:
            collector.analyze_collection_results(args.results_dir)


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.2 KB
Keep exploring