threat hunting

Hunting for Data Exfiltration Indicators

Hunt for data exfiltration through network traffic analysis, detecting unusual data flows, DNS tunneling, cloud storage uploads, and encrypted channel abuse.

data-exfiltrationdlpmitre-attacknetwork-analysisproactive-detectionthreat-hunting
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When hunting for data theft in compromised environments
  • After detecting unusual outbound data volumes or patterns
  • When investigating potential insider threat data theft
  • During incident response to determine what data was stolen
  • When threat intel indicates data exfiltration campaigns targeting your sector

Prerequisites

  • Network proxy/firewall logs with byte-level data transfer metrics
  • DLP solution or CASB with cloud upload visibility
  • DNS query logs for DNS exfiltration detection
  • Email gateway logs for attachment monitoring
  • SIEM with data volume anomaly detection capabilities

Workflow

  1. Define Exfiltration Channels: Identify potential channels (HTTP/S uploads, DNS tunneling, email attachments, cloud storage, removable media, encrypted protocols).
  2. Baseline Normal Data Flows: Establish baseline outbound data transfer volumes per user, host, and destination over a 30-day window.
  3. Detect Volume Anomalies: Identify hosts or users transferring significantly more data than baseline to external destinations.
  4. Analyze Transfer Destinations: Check destination domains/IPs against threat intel, identify newly registered domains, personal cloud storage, and foreign infrastructure.
  5. Inspect Protocol Abuse: Look for DNS tunneling (large/frequent TXT queries), ICMP tunneling, or data hidden in allowed protocols.
  6. Correlate with File Access: Link exfiltration indicators to file access events on sensitive file shares, databases, or repositories.
  7. Report and Contain: Document findings with evidence, estimate data exposure, and recommend containment actions.

Key Concepts

Concept Description
T1041 Exfiltration Over C2 Channel
T1048 Exfiltration Over Alternative Protocol
T1048.001 Exfiltration Over Symmetric Encrypted Non-C2
T1048.002 Exfiltration Over Asymmetric Encrypted Non-C2
T1048.003 Exfiltration Over Unencrypted/Obfuscated Non-C2
T1567 Exfiltration Over Web Service
T1567.002 Exfiltration to Cloud Storage
T1052 Exfiltration Over Physical Medium
T1029 Scheduled Transfer
T1030 Data Transfer Size Limits (staging)
T1537 Transfer Data to Cloud Account
T1020 Automated Exfiltration

Tools & Systems

Tool Purpose
Splunk SIEM for data volume analysis and SPL queries
Zeek Network metadata for data flow analysis
Microsoft Defender for Cloud Apps CASB for cloud exfiltration
Netskope Cloud DLP and exfiltration detection
Suricata Network IDS for protocol anomaly detection
RITA DNS exfiltration and beacon detection
ExtraHop Network traffic analysis for data flow

Common Scenarios

  1. Cloud Storage Exfiltration: User uploads sensitive documents to personal Google Drive or Dropbox via browser.
  2. DNS Tunneling: Malware exfiltrates data encoded in DNS subdomain queries to attacker-controlled nameserver.
  3. HTTPS Upload: Compromised system POSTs large data blobs to C2 server over encrypted HTTPS.
  4. Email Attachment Exfiltration: Insider forwards sensitive documents to personal email accounts.
  5. Staging and Compression: Adversary stages data in compressed archives before slow exfiltration to avoid detection.

Output Format

Hunt ID: TH-EXFIL-[DATE]-[SEQ]
Exfiltration Channel: [HTTP/DNS/Email/Cloud/USB]
Source: [Host/User]
Destination: [Domain/IP/Service]
Data Volume: [Bytes/MB/GB]
Time Period: [Start - End]
Protocol: [HTTPS/DNS/SMTP/SMB]
Files Involved: [Count/Types]
Risk Level: [Critical/High/Medium/Low]
Confidence: [High/Medium/Low]
Source materials

References and resources

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

References 3

api-reference.md1.4 KB

API Reference: Data Exfiltration Detection

Exfiltration Methods (MITRE ATT&CK)

Technique ID Description
Exfiltration Over C2 Channel T1041 Via existing C2
Exfiltration Over Alternative Protocol T1048 DNS, ICMP, etc.
Exfiltration Over Web Service T1567 Cloud storage
Automated Exfiltration T1020 Scripted transfer

DNS Exfiltration Indicators

Indicator Threshold
Shannon entropy > 3.5
Subdomain length > 40 chars
Query volume per domain > 100/hour
TXT record responses > 500 bytes

Zeek Log Fields

conn.log

Field Description
ts Timestamp
id.orig_h Source IP
id.resp_h Destination IP
orig_bytes Bytes from source
resp_bytes Bytes from destination

dns.log

Field Description
query DNS query name
qtype_name Query type (A, TXT, etc.)
answers Response answers

Python Libraries

Library Use
csv Parse Zeek TSV logs
math Shannon entropy calculation
collections.defaultdict Aggregate statistics
dpkt PCAP parsing
scapy Packet-level analysis

Shannon Entropy Formula

H(X) = -sum(p(x) * log2(p(x)))

Normal domain: H < 3.0, Exfil encoded: H > 3.5

standards.md2.2 KB

Standards and References - Data Exfiltration Hunting

MITRE ATT&CK Exfiltration (TA0010)

Technique Name Channel
T1041 Exfiltration Over C2 Channel Uses existing C2 connection
T1048.001 Symmetric Encrypted Non-C2 Custom encrypted protocol
T1048.002 Asymmetric Encrypted Non-C2 TLS to non-C2 server
T1048.003 Unencrypted/Obfuscated Non-C2 FTP, HTTP, raw TCP
T1567.001 Exfiltration to Code Repository GitHub, GitLab
T1567.002 Exfiltration to Cloud Storage S3, GDrive, Dropbox, OneDrive
T1567.003 Exfiltration to Text Storage Pastebin, paste.ee
T1567.004 Exfiltration Over Webhook Slack, Discord, Teams webhooks
T1052.001 Exfiltration Over USB Removable media
T1537 Transfer Data to Cloud Account Cloud-to-cloud exfiltration
T1020 Automated Exfiltration Script-based bulk transfer
T1029 Scheduled Transfer Periodic small transfers
T1030 Data Transfer Size Limits Size-limited staged transfer

Detection Thresholds

Metric Alert Threshold Notes
Outbound data per host/day > 2x 30-day average Volume anomaly
DNS query length > 50 characters DNS tunneling indicator
DNS TXT record queries > 100/hour per domain DNS exfiltration
Cloud upload volume > 500MB/day per user Cloud exfiltration
Email attachment size > 25MB per email Email exfiltration
Off-hours data transfer Any > 100MB Unusual timing
Transfer to new destination > 50MB first time New destination risk

Data Sources

Source Event Type Exfiltration Indicator
Proxy logs HTTP POST/PUT Large upload bytes
Firewall Connection data Bytes-out anomalies
DNS server Query logs Long subdomain names, TXT queries
Email gateway Message logs Attachment sizes, external recipients
CASB Cloud activity Uploads to personal cloud
Sysmon Event 3 Network connections Process-level data transfer
DLP Content inspection Sensitive data classification
USB audit Removable media Device insertion + file copy
workflows.md2.4 KB

Detailed Hunting Workflow - Data Exfiltration

Phase 1: Volume Anomaly Detection

Step 1.1 - Outbound Data Volume per Host

index=proxy OR index=firewall
| where NOT match(dest, "(?i)(microsoft|windowsupdate|google|amazonaws)")
| stats sum(bytes_out) as total_bytes_out by src_ip
| eval MB_out=round(total_bytes_out/1048576, 2)
| sort -MB_out
| head 50

Step 1.2 - Statistical Volume Anomaly

index=proxy earliest=-30d
| bin _time span=1d
| stats sum(bytes_out) as daily_bytes by src_ip _time
| eventstats avg(daily_bytes) as avg_daily stdev(daily_bytes) as sd_daily by src_ip
| where daily_bytes > (avg_daily + 3*sd_daily) AND daily_bytes > 104857600
| eval anomaly_factor=round(daily_bytes/avg_daily, 1)
| table _time src_ip daily_bytes avg_daily anomaly_factor

Phase 2: Cloud Storage Exfiltration

Step 2.1 - Cloud Upload Detection

index=proxy
| where match(dest, "(?i)(drive\.google|dropbox|box\.com|onedrive|mega\.nz|wetransfer|sendspace)")
| where method IN ("POST", "PUT")
| stats sum(bytes_out) as uploaded_bytes count by src_ip dest user
| eval MB_uploaded=round(uploaded_bytes/1048576, 2)
| where MB_uploaded > 50
| sort -MB_uploaded

Phase 3: DNS Exfiltration

Step 3.1 - DNS Tunneling Indicators

index=dns
| eval query_len=len(query)
| where query_len > 50
| rex field=query "^(?<subdomain>.+)\.(?<base_domain>[^.]+\.[^.]+)$"
| stats count avg(query_len) as avg_len dc(subdomain) as unique_subs by src_ip base_domain
| where count > 100 AND (avg_len > 40 OR unique_subs > 50)
| sort -count

Phase 4: Email Exfiltration

Step 4.1 - Large Email Attachments to External

index=email
| where match(recipient, "(?i)(gmail|yahoo|hotmail|protonmail|outlook)")
| where attachment_size > 10485760
| stats count sum(attachment_size) as total_size by sender recipient
| eval MB_sent=round(total_size/1048576, 2)
| sort -MB_sent

Phase 5: File Access Correlation

Step 5.1 - Sensitive File Access Before Exfiltration

Correlate file access events on sensitive shares with subsequent outbound data transfers:

index=wineventlog EventCode=5145
| where match(Share_Name, "(?i)(finance|hr|legal|confidential|restricted)")
| stats count values(Relative_Target_Name) as files by Account_Name Source_Address
| join Account_Name [
    search index=proxy method IN ("POST","PUT") earliest=-1h
    | stats sum(bytes_out) as upload_bytes by user
    | rename user as Account_Name
]
| where upload_bytes > 1048576

Scripts 2

agent.py5.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for hunting data exfiltration indicators in network traffic."""

import argparse
import csv
import json
import math
from collections import defaultdict
from datetime import datetime, timezone


DNS_EXFIL_ENTROPY_THRESHOLD = 3.5
DNS_LABEL_LENGTH_THRESHOLD = 40
LARGE_UPLOAD_THRESHOLD_MB = 50

SUSPICIOUS_PORTS = {
    20: "FTP Data", 21: "FTP", 22: "SSH/SCP", 53: "DNS",
    443: "HTTPS", 993: "IMAPS", 995: "POP3S",
    8443: "Alt HTTPS", 6667: "IRC",
}


def shannon_entropy(data):
    """Calculate Shannon entropy of a string."""
    if not data:
        return 0.0
    freq = defaultdict(int)
    for c in data:
        freq[c] += 1
    length = len(data)
    return -sum((count/length) * math.log2(count/length) for count in freq.values())


def analyze_dns_queries(filepath):
    """Analyze DNS query log for exfiltration indicators."""
    findings = []
    domain_stats = defaultdict(lambda: {"count": 0, "total_length": 0, "queries": []})
    try:
        with open(filepath, "r") as f:
            reader = csv.DictReader(f, delimiter="\t")
            for row in reader:
                query = row.get("query", "")
                if not query:
                    continue
                parts = query.split(".")
                if len(parts) < 2:
                    continue
                domain = ".".join(parts[-2:])
                subdomain = ".".join(parts[:-2])
                domain_stats[domain]["count"] += 1
                domain_stats[domain]["total_length"] += len(subdomain)
                domain_stats[domain]["queries"].append(subdomain)
    except (OSError, csv.Error):
        return findings

    for domain, stats in domain_stats.items():
        if stats["count"] < 5:
            continue
        avg_subdomain_len = stats["total_length"] / stats["count"]
        all_subdomains = "".join(stats["queries"])
        entropy = shannon_entropy(all_subdomains)
        if entropy > DNS_EXFIL_ENTROPY_THRESHOLD and avg_subdomain_len > 20:
            findings.append({
                "type": "dns_exfiltration",
                "domain": domain,
                "query_count": stats["count"],
                "avg_subdomain_length": round(avg_subdomain_len, 1),
                "entropy": round(entropy, 3),
                "severity": "CRITICAL",
            })
    return findings


def analyze_network_flows(filepath):
    """Analyze network flow data for large outbound transfers."""
    findings = []
    dest_bytes = defaultdict(int)
    try:
        with open(filepath, "r") as f:
            reader = csv.DictReader(f, delimiter="\t")
            for row in reader:
                dst = row.get("id.resp_h", row.get("dst", ""))
                orig_bytes = int(row.get("orig_bytes", 0) or 0)
                dest_bytes[dst] += orig_bytes
    except (OSError, csv.Error, ValueError):
        return findings

    for dst, total in dest_bytes.items():
        mb = total / (1024 * 1024)
        if mb >= LARGE_UPLOAD_THRESHOLD_MB:
            findings.append({
                "type": "large_outbound_transfer",
                "destination": dst,
                "total_bytes": total,
                "total_mb": round(mb, 2),
                "severity": "HIGH",
            })
    return findings


def analyze_off_hours_traffic(filepath):
    """Check for significant data transfers during off-hours."""
    findings = []
    off_hours_transfers = defaultdict(int)
    try:
        with open(filepath, "r") as f:
            reader = csv.DictReader(f, delimiter="\t")
            for row in reader:
                ts = float(row.get("ts", 0))
                hour = datetime.fromtimestamp(ts).hour
                if hour < 6 or hour > 22:
                    dst = row.get("id.resp_h", row.get("dst", ""))
                    orig_bytes = int(row.get("orig_bytes", 0) or 0)
                    off_hours_transfers[dst] += orig_bytes
    except (OSError, csv.Error, ValueError):
        return findings

    for dst, total in off_hours_transfers.items():
        mb = total / (1024 * 1024)
        if mb >= 10:
            findings.append({
                "type": "off_hours_transfer",
                "destination": dst,
                "total_mb": round(mb, 2),
                "severity": "MEDIUM",
            })
    return findings


def main():
    parser = argparse.ArgumentParser(
        description="Data exfiltration indicator hunter"
    )
    parser.add_argument("--conn-log", help="Zeek conn.log or network flow CSV")
    parser.add_argument("--dns-log", help="Zeek dns.log or DNS query CSV")
    parser.add_argument("--output", "-o", help="Output JSON report")
    parser.add_argument("--verbose", "-v", action="store_true")
    args = parser.parse_args()

    if not args.conn_log and not args.dns_log:
        parser.error("At least one of --conn-log or --dns-log is required")

    print("[*] Data Exfiltration Indicator Hunter")
    report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}

    if args.dns_log:
        report["findings"].extend(analyze_dns_queries(args.dns_log))
    if args.conn_log:
        report["findings"].extend(analyze_network_flows(args.conn_log))
        report["findings"].extend(analyze_off_hours_traffic(args.conn_log))

    report["risk_level"] = (
        "CRITICAL" if any(f["severity"] == "CRITICAL" for f in report["findings"])
        else "HIGH" if any(f["severity"] == "HIGH" for f in report["findings"])
        else "MEDIUM" if report["findings"] else "LOW"
    )
    report["total_findings"] = len(report["findings"])

    print(f"[*] {report['total_findings']} exfiltration indicators found")
    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()
process.py9.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Data Exfiltration Detection Script
Analyzes network logs for unusual data transfer volumes, DNS tunneling,
cloud storage uploads, and protocol abuse indicators.
"""

import json
import csv
import argparse
import datetime
import math
from collections import defaultdict
from pathlib import Path

CLOUD_STORAGE_DOMAINS = {
    "drive.google.com", "docs.google.com", "storage.googleapis.com",
    "dropbox.com", "dl.dropboxusercontent.com",
    "box.com", "upload.box.com",
    "onedrive.live.com", "sharepoint.com",
    "mega.nz", "mega.co.nz",
    "wetransfer.com", "sendspace.com",
    "mediafire.com", "4shared.com",
    "pastebin.com", "paste.ee", "hastebin.com",
    "github.com", "gitlab.com", "bitbucket.org",
    "discord.com", "cdn.discordapp.com",
    "api.telegram.org", "slack.com",
}

LEGITIMATE_HIGH_VOLUME = {
    "windowsupdate.com", "microsoft.com", "windows.com",
    "googleapis.com", "gstatic.com",
    "amazonaws.com", "cloudfront.net",
    "apple.com", "icloud.com",
    "adobe.com", "akamai.net",
}


def parse_logs(input_path: str) -> list[dict]:
    path = Path(input_path)
    if path.suffix == ".json":
        with open(path, "r", encoding="utf-8") as f:
            data = json.load(f)
            return data if isinstance(data, list) else data.get("events", [])
    elif path.suffix == ".csv":
        with open(path, "r", encoding="utf-8-sig") as f:
            return [dict(row) for row in csv.DictReader(f)]
    return []


def normalize_event(event: dict) -> dict:
    field_map = {
        "timestamp": ["ts", "timestamp", "_time", "@timestamp"],
        "src_ip": ["src_ip", "id.orig_h", "source_ip", "LocalIP"],
        "dst_ip": ["dst_ip", "id.resp_h", "dest_ip", "RemoteIP"],
        "domain": ["domain", "host", "query", "dest", "RemoteUrl"],
        "bytes_out": ["bytes_out", "orig_bytes", "SentBytes", "bytes_sent"],
        "bytes_in": ["bytes_in", "resp_bytes", "ReceivedBytes", "bytes_recv"],
        "method": ["method", "http_method", "Method"],
        "user": ["user", "User", "AccountName", "user.name"],
        "query_type": ["query_type", "qtype_name", "QueryType"],
    }
    normalized = {}
    for target, sources in field_map.items():
        for src in sources:
            if src in event and event[src] and event[src] != "-":
                normalized[target] = str(event[src])
                break
        if target not in normalized:
            normalized[target] = ""
    return normalized


def is_legitimate(domain: str) -> bool:
    domain = domain.lower()
    return any(domain.endswith(d) for d in LEGITIMATE_HIGH_VOLUME)


def is_cloud_storage(domain: str) -> bool:
    domain = domain.lower()
    return any(domain.endswith(d) or d in domain for d in CLOUD_STORAGE_DOMAINS)


def detect_volume_anomalies(events: list[dict]) -> list[dict]:
    host_data = defaultdict(lambda: {"bytes_out": 0, "destinations": set(), "count": 0})
    for e in events:
        src = e.get("src_ip", "")
        domain = e.get("domain", "") or e.get("dst_ip", "")
        if not src or is_legitimate(domain):
            continue
        try:
            bytes_out = int(e.get("bytes_out", 0) or 0)
        except ValueError:
            bytes_out = 0
        host_data[src]["bytes_out"] += bytes_out
        host_data[src]["destinations"].add(domain)
        host_data[src]["count"] += 1

    findings = []
    threshold_bytes = 100 * 1024 * 1024  # 100 MB

    for src, data in host_data.items():
        if data["bytes_out"] > threshold_bytes:
            mb = data["bytes_out"] / (1024 * 1024)
            risk = min(90, 30 + int(mb / 100) * 10)
            findings.append({
                "detection_type": "VOLUME_ANOMALY",
                "technique": "T1041",
                "src_ip": src,
                "bytes_out": data["bytes_out"],
                "mb_out": round(mb, 2),
                "unique_destinations": len(data["destinations"]),
                "connection_count": data["count"],
                "risk_score": risk,
                "risk_level": "CRITICAL" if risk >= 70 else "HIGH" if risk >= 50 else "MEDIUM",
                "indicators": [f"High outbound volume: {round(mb, 2)} MB to {len(data['destinations'])} destinations"],
            })

    return sorted(findings, key=lambda x: x["bytes_out"], reverse=True)


def detect_cloud_exfiltration(events: list[dict]) -> list[dict]:
    cloud_uploads = defaultdict(lambda: {"bytes_out": 0, "services": set(), "count": 0})
    for e in events:
        domain = e.get("domain", "")
        method = e.get("method", "").upper()
        if not is_cloud_storage(domain):
            continue
        if method not in ("POST", "PUT", "PATCH", ""):
            continue
        src = e.get("src_ip", "") or e.get("user", "")
        try:
            bytes_out = int(e.get("bytes_out", 0) or 0)
        except ValueError:
            bytes_out = 0
        cloud_uploads[src]["bytes_out"] += bytes_out
        cloud_uploads[src]["services"].add(domain)
        cloud_uploads[src]["count"] += 1

    findings = []
    for src, data in cloud_uploads.items():
        if data["bytes_out"] > 50 * 1024 * 1024:  # 50 MB
            mb = data["bytes_out"] / (1024 * 1024)
            findings.append({
                "detection_type": "CLOUD_EXFILTRATION",
                "technique": "T1567.002",
                "source": src,
                "bytes_out": data["bytes_out"],
                "mb_out": round(mb, 2),
                "cloud_services": list(data["services"]),
                "upload_count": data["count"],
                "risk_score": 60,
                "risk_level": "HIGH",
                "indicators": [f"Cloud upload: {round(mb, 2)} MB to {', '.join(data['services'])}"],
            })

    return sorted(findings, key=lambda x: x["bytes_out"], reverse=True)


def detect_dns_exfiltration(events: list[dict]) -> list[dict]:
    domain_stats = defaultdict(lambda: {"queries": 0, "unique_subs": set(), "total_len": 0})
    for e in events:
        domain = e.get("domain", "")
        if not domain or "." not in domain:
            continue
        parts = domain.split(".")
        if len(parts) < 3:
            continue
        base = ".".join(parts[-2:])
        sub = ".".join(parts[:-2])
        domain_stats[base]["queries"] += 1
        domain_stats[base]["unique_subs"].add(sub)
        domain_stats[base]["total_len"] += len(domain)

    findings = []
    for base, stats in domain_stats.items():
        if stats["queries"] < 50 or is_legitimate(base):
            continue
        avg_len = stats["total_len"] / stats["queries"]
        unique = len(stats["unique_subs"])
        risk = 0
        indicators = []
        if unique > 50:
            risk += 30
            indicators.append(f"High unique subdomains: {unique}")
        if avg_len > 40:
            risk += 25
            indicators.append(f"Long query avg: {avg_len:.1f}")
        if stats["queries"] > 500:
            risk += 15
            indicators.append(f"High volume: {stats['queries']} queries")
        if risk >= 30:
            findings.append({
                "detection_type": "DNS_EXFILTRATION",
                "technique": "T1048.003",
                "domain": base,
                "query_count": stats["queries"],
                "unique_subdomains": unique,
                "avg_query_length": round(avg_len, 1),
                "risk_score": risk,
                "risk_level": "CRITICAL" if risk >= 70 else "HIGH" if risk >= 50 else "MEDIUM",
                "indicators": indicators,
            })

    return sorted(findings, key=lambda x: x["risk_score"], reverse=True)


def run_hunt(input_path: str, output_dir: str) -> None:
    print(f"[*] Data Exfiltration Hunt - {datetime.datetime.now().isoformat()}")
    events = [normalize_event(e) for e in parse_logs(input_path)]
    print(f"[*] Loaded {len(events)} events")

    vol_findings = detect_volume_anomalies(events)
    cloud_findings = detect_cloud_exfiltration(events)
    dns_findings = detect_dns_exfiltration(events)
    all_findings = vol_findings + cloud_findings + dns_findings

    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    with open(output_path / "exfil_findings.json", "w", encoding="utf-8") as f:
        json.dump({
            "hunt_id": f"TH-EXFIL-{datetime.date.today().isoformat()}",
            "total_events": len(events),
            "findings": all_findings,
        }, f, indent=2)

    with open(output_path / "hunt_report.md", "w", encoding="utf-8") as f:
        f.write(f"# Data Exfiltration Hunt Report\n\n")
        f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
        f.write(f"**Volume Anomalies**: {len(vol_findings)}\n")
        f.write(f"**Cloud Exfil**: {len(cloud_findings)}\n")
        f.write(f"**DNS Exfil**: {len(dns_findings)}\n\n")
        for finding in all_findings[:20]:
            f.write(f"### [{finding['risk_level']}] {finding['detection_type']}\n")
            f.write(f"- {', '.join(finding['indicators'])}\n\n")

    print(f"[+] {len(all_findings)} findings written to {output_dir}")


def main():
    parser = argparse.ArgumentParser(description="Data Exfiltration Detection")
    subparsers = parser.add_subparsers(dest="command")
    hunt_p = subparsers.add_parser("hunt")
    hunt_p.add_argument("--input", "-i", required=True)
    hunt_p.add_argument("--output", "-o", default="./exfil_output")
    subparsers.add_parser("queries")
    args = parser.parse_args()

    if args.command == "hunt":
        run_hunt(args.input, args.output)
    elif args.command == "queries":
        print("=== Data Exfiltration Queries ===\n")
        print("--- Volume Anomaly ---")
        print("index=proxy | stats sum(bytes_out) as total by src_ip\n| eval MB=round(total/1048576,2)\n| where MB > 100 | sort -MB")
    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 0.7 KB
Keep exploring