vulnerability management

Implementing Continuous Security Validation with BAS

Deploy Breach and Attack Simulation tools to continuously validate security control effectiveness by safely emulating real-world attack techniques across the kill chain.

attackiqbasbreach-attack-simulationcymulatemitre-attackpicussafebreachsecurity-validation
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Breach and Attack Simulation (BAS) is an automated, continuous approach to validating security control effectiveness by safely executing real-world attack techniques against production security infrastructure. Unlike traditional penetration testing (point-in-time), BAS platforms continuously simulate threats mapped to MITRE ATT&CK, testing endpoint protection, network security, email gateways, SIEM detection, and incident response capabilities. Leading platforms include SafeBreach, AttackIQ, Picus Security (2024 Gartner Customers' Choice), Cymulate, Pentera, and SCYTHE. BAS 2.0 solutions safely emulate real attacker behavior across the entire IT environment without requiring pre-deployed agents on every endpoint.

When to Use

  • When deploying or configuring implementing continuous security validation with bas 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

  • BAS platform license (SafeBreach, AttackIQ, Picus, Cymulate, or Pentera)
  • Deployed security controls to validate (EDR, NGFW, email gateway, SIEM, WAF)
  • MITRE ATT&CK framework familiarity
  • Network segments accessible by BAS agents/simulators
  • Security operations team to act on validation results
  • Change management approval for running simulations in production

Core Concepts

BAS vs Traditional Security Testing

Aspect BAS Penetration Testing Red Team
Frequency Continuous/scheduled Annual/quarterly Annual
Automation Fully automated Manual with tools Manual
Scope Full kill chain Specific targets Goal-oriented
Safety Safe simulation, no exploitation Controlled exploitation Real exploitation
Coverage Thousands of techniques Hundreds of tests Focused scenarios
Output Control gap analysis Vulnerability report Narrative report
Cost model Subscription Per engagement Per engagement

MITRE ATT&CK Coverage Mapping

Tactic Example BAS Simulations Controls Tested
Initial Access Phishing payload delivery, exploit public apps Email gateway, WAF, IPS
Execution PowerShell, WMI, malicious macros EDR, application control
Persistence Registry run keys, scheduled tasks, services EDR, SIEM detection rules
Privilege Escalation Token manipulation, UAC bypass EDR, PAM, SIEM
Defense Evasion Process injection, obfuscation, timestomping EDR, behavioral analytics
Credential Access Mimikatz, Kerberoasting, LSASS dump EDR, credential guard
Discovery AD enumeration, network scanning SIEM, NDR
Lateral Movement PsExec, WMI, RDP, SMB NDR, microsegmentation
Collection Screen capture, keylogging, email collection DLP, UEBA
Exfiltration HTTP/DNS exfil, cloud storage upload DLP, CASB, proxy
Command & Control C2 beaconing, DNS tunneling, encrypted channels NGFW, proxy, NDR

Security Control Validation Score

Control Effectiveness = (Attacks Prevented + Attacks Detected) / Total Attacks Simulated * 100
 
Example:
  Total simulations:  500
  Prevented (blocked): 350
  Detected (alerted):  100
  Missed (no action):   50
 
  Prevention Rate: 350/500 = 70%
  Detection Rate:  100/500 = 20%
  Overall Score:   450/500 = 90%
  Gap Rate:         50/500 = 10%

Workflow

Step 1: Deploy BAS Platform Components

Architecture:
  Management Console (Cloud SaaS):
    - Central orchestration and reporting
    - Attack scenario library management
    - MITRE ATT&CK mapping dashboard
 
  Simulation Agents:
    - Attacker Agent: Simulates threat actor behavior
    - Target Agent: Receives simulated attacks
    - Network Agent: Tests network-level controls
 
  Deploy agents across zones:
    - Corporate network (workstations)
    - DMZ (web servers)
    - Data center (critical servers)
    - Cloud environments (AWS/Azure/GCP)
    - Remote/VPN segment

Step 2: Configure Attack Scenarios

# Example BAS scenario configuration
scenario:
  name: "APT29 (Cozy Bear) Full Kill Chain"
  threat_group: APT29
  mitre_attack_techniques:
    - T1566.001  # Spearphishing Attachment
    - T1059.001  # PowerShell Execution
    - T1547.001  # Registry Run Key Persistence
    - T1003.001  # LSASS Memory Credential Dump
    - T1021.002  # SMB/Windows Admin Shares
    - T1071.001  # Web Protocol C2
    - T1048.003  # DNS Exfiltration
 
  phases:
    - name: "Initial Access"
      actions:
        - deliver_phishing_payload:
            type: office_macro
            target: email_gateway
            variants: [docm, xlsm, ppam]
 
    - name: "Execution & Persistence"
      actions:
        - execute_powershell:
            encoded: true
            amsi_bypass: true
        - create_scheduled_task:
            technique: T1053.005
 
    - name: "Credential Access"
      actions:
        - dump_lsass:
            method: [procdump, comsvcs, nanodump]
 
    - name: "Lateral Movement"
      actions:
        - psexec_lateral:
            target: internal_server
        - wmi_lateral:
            target: file_server
 
    - name: "Exfiltration"
      actions:
        - dns_exfiltration:
            data_size: 10MB
            encoding: base64

Step 3: Map Results to Security Controls

def map_bas_results_to_controls(simulation_results):
    """Map BAS results to security control effectiveness."""
    control_scores = {}
 
    control_mapping = {
        "email_gateway": ["T1566.001", "T1566.002", "T1566.003"],
        "edr": ["T1059.001", "T1003.001", "T1055", "T1547.001"],
        "ngfw": ["T1071.001", "T1071.004", "T1048"],
        "siem": ["T1053.005", "T1021.002", "T1087"],
        "dlp": ["T1048.003", "T1567", "T1041"],
        "ndr": ["T1071", "T1021", "T1040"],
    }
 
    for control, techniques in control_mapping.items():
        relevant = [r for r in simulation_results
                    if r["technique_id"] in techniques]
        if not relevant:
            continue
 
        prevented = sum(1 for r in relevant if r["result"] == "prevented")
        detected = sum(1 for r in relevant if r["result"] == "detected")
        missed = sum(1 for r in relevant if r["result"] == "missed")
        total = len(relevant)
 
        control_scores[control] = {
            "total_tests": total,
            "prevented": prevented,
            "detected": detected,
            "missed": missed,
            "prevention_rate": round(prevented / total * 100, 1),
            "detection_rate": round(detected / total * 100, 1),
            "effectiveness": round((prevented + detected) / total * 100, 1),
        }
 
    return control_scores

Step 4: Schedule Continuous Validation

Validation Schedule:
  Daily:
    - Malware delivery simulation (email gateway test)
    - C2 communication simulation (firewall/proxy test)
    - Known ransomware behavior simulation (EDR test)
 
  Weekly:
    - Full kill chain simulation (APT scenario)
    - Lateral movement simulation (network segmentation test)
    - Data exfiltration simulation (DLP test)
 
  Monthly:
    - Full MITRE ATT&CK coverage assessment
    - New threat group TTP simulation
    - Regression testing after security control changes
 
  On-Demand:
    - After firewall rule changes
    - After EDR policy updates
    - After new threat intelligence (zero-day response)

Best Practices

  1. Start with known threat group simulations relevant to your industry
  2. Always run simulations in safe mode first before enabling full emulation
  3. Coordinate with SOC team so they can distinguish BAS traffic from real attacks
  4. Use BAS results to prioritize SIEM detection rule development
  5. Track control effectiveness scores over time to demonstrate security posture improvement
  6. Integrate BAS with ticketing systems to auto-generate remediation tickets for gaps
  7. Run validation after every security control change to catch regressions
  8. Map all simulations to MITRE ATT&CK for standardized reporting

Common Pitfalls

  • Running BAS without informing the SOC, causing unnecessary incident response
  • Testing only prevention and ignoring detection/response validation
  • Not acting on BAS findings, leading to persistent security gaps
  • Deploying BAS agents only in one network zone, missing cross-zone gaps
  • Focusing only on commodity threats instead of APT-relevant scenarios
  • Treating BAS as a replacement for penetration testing rather than a complement
Source materials

References and resources

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

References 3

api-reference.md1.6 KB

API Reference: Breach and Attack Simulation Agent

Dependencies

Library Version Purpose
requests >=2.28 HTTP client for SIEM detection validation

CLI Usage

python scripts/agent.py \
  --target 10.0.1.50 \
  --siem-url https://siem.example.com \
  --siem-key YOUR_KEY \
  --output-dir /reports/

Functions

simulate_technique(technique, target) -> dict

Simulates a MITRE ATT&CK technique and records detection/blocked status.

check_siem_detection(siem_url, api_key, technique_id, time_window) -> dict

Queries SIEM API for alerts matching the simulated technique within time window.

compute_detection_coverage(results) -> dict

Calculates overall detection rate and per-tactic coverage breakdown.

generate_report(target, siem_url, siem_key) -> dict

Runs 7 ATT&CK technique simulations and generates detection gap report.

ATT&CK Techniques Tested

ID Name Tactic
T1566.001 Spearphishing Attachment Initial Access
T1059.001 PowerShell Execution
T1003.001 LSASS Memory Credential Access
T1021.002 SMB Admin Shares Lateral Movement
T1486 Data Encrypted for Impact Impact
T1071.001 Web Protocols C2
T1048.003 Exfiltration Over Unencrypted Exfiltration

Output Schema

{
  "coverage": {"total_tests": 7, "detected": 5, "missed": 2, "detection_rate_pct": 71.4},
  "gaps": [{"technique_id": "T1003.001", "technique_name": "LSASS Memory"}],
  "recommendations": ["Create detection rule for T1003.001"]
}
standards.md1.0 KB

Standards and References - Continuous Security Validation with BAS

BAS Platforms

Industry Standards

  • MITRE ATT&CK Framework: https://attack.mitre.org/
  • Gartner BAS Market Guide: Breach and Attack Simulation Tools
  • NIST CSF 2.0 DE.CM: Security Continuous Monitoring
  • CIS Controls v8.1 Control 18: Penetration Testing

Gartner Recognition (2024)

  • Picus Security: 2024 Customers' Choice for BAS Tools
  • Category evolution: BAS -> Adversarial Exposure Validation (2025)

Key Metrics

Metric Description Target
Prevention Rate % of attacks blocked > 80%
Detection Rate % of attacks alerted > 90% (combined)
MITRE Coverage % of techniques tested > 60%
Validation Frequency How often tests run Daily/Weekly
workflows.md1.7 KB

Workflows - BAS Continuous Security Validation

Workflow 1: BAS Validation Cycle

┌──────────────┐   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ Select Attack│──>│ Execute Safe │──>│ Collect      │──>│ Map to       │
│ Scenarios    │   │ Simulation   │   │ Results      │   │ Controls     │
└──────────────┘   └──────────────┘   └──────────────┘   └──────────────┘

       ┌─────────────────────────────────────────────────────────┘
       v
┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ Identify     │──>│ Create       │──>│ Re-Validate  │
│ Control Gaps │   │ Remediation  │   │ After Fix    │
└──────────────┘   └──────────────┘   └──────────────┘

Workflow 2: Post-Change Regression Test

Security Control Change (firewall rule, EDR policy, SIEM rule)

    v
Trigger BAS regression test for affected technique categories

    v
Compare results: before vs after change

    ├── Improvement: Document and close
    └── Regression: Alert security team, rollback if needed

Scripts 2

agent.py5.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Breach and Attack Simulation (BAS) agent for continuous security validation using MITRE ATT&CK."""

import argparse
import json
import logging
import os
import sys
from datetime import datetime
from typing import List

try:
    import requests
except ImportError:
    sys.exit("requests required: pip install requests")

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

ATTACK_TECHNIQUES = [
    {"id": "T1566.001", "name": "Spearphishing Attachment", "tactic": "Initial Access",
     "test_type": "email", "payload": "eicar_test_attachment"},
    {"id": "T1059.001", "name": "PowerShell", "tactic": "Execution",
     "test_type": "endpoint", "payload": "benign_ps_download_cradle"},
    {"id": "T1003.001", "name": "LSASS Memory", "tactic": "Credential Access",
     "test_type": "endpoint", "payload": "procdump_lsass_simulation"},
    {"id": "T1021.002", "name": "SMB/Windows Admin Shares", "tactic": "Lateral Movement",
     "test_type": "network", "payload": "smb_admin_share_access"},
    {"id": "T1486", "name": "Data Encrypted for Impact", "tactic": "Impact",
     "test_type": "endpoint", "payload": "benign_file_encryption"},
    {"id": "T1071.001", "name": "Web Protocols", "tactic": "Command and Control",
     "test_type": "network", "payload": "http_c2_beacon_simulation"},
    {"id": "T1048.003", "name": "Exfiltration Over Unencrypted Protocol", "tactic": "Exfiltration",
     "test_type": "network", "payload": "dns_exfil_simulation"},
]


def simulate_technique(technique: dict, target: str) -> dict:
    """Simulate a single ATT&CK technique and record detection status."""
    start_time = datetime.utcnow().isoformat()
    detected = False
    blocked = False
    alert_id = ""
    try:
        if technique["test_type"] == "network":
            resp = requests.get(f"http://{target}/health", timeout=5)
            detected = resp.status_code != 200
        elif technique["test_type"] == "email":
            detected = False
        elif technique["test_type"] == "endpoint":
            detected = False
    except requests.RequestException:
        blocked = True
        detected = True
    return {
        "technique_id": technique["id"],
        "technique_name": technique["name"],
        "tactic": technique["tactic"],
        "test_type": technique["test_type"],
        "start_time": start_time,
        "detected": detected,
        "blocked": blocked,
        "alert_generated": alert_id,
    }


def check_siem_detection(siem_url: str, api_key: str, technique_id: str,
                          time_window_minutes: int = 15) -> dict:
    """Check if SIEM generated an alert for the simulated technique."""
    try:
        resp = requests.get(
            f"{siem_url}/api/alerts",
            headers={"Authorization": f"Bearer {api_key}"},
            params={"technique": technique_id, "minutes": time_window_minutes},
            timeout=15)
        if resp.status_code == 200:
            alerts = resp.json().get("alerts", [])
            return {"detected": len(alerts) > 0, "alert_count": len(alerts)}
    except requests.RequestException:
        pass
    return {"detected": False, "alert_count": 0}


def compute_detection_coverage(results: List[dict]) -> dict:
    """Compute detection coverage across tested techniques."""
    total = len(results)
    detected = sum(1 for r in results if r["detected"])
    blocked = sum(1 for r in results if r["blocked"])
    by_tactic = {}
    for r in results:
        tactic = r["tactic"]
        if tactic not in by_tactic:
            by_tactic[tactic] = {"total": 0, "detected": 0}
        by_tactic[tactic]["total"] += 1
        if r["detected"]:
            by_tactic[tactic]["detected"] += 1
    return {
        "total_tests": total,
        "detected": detected,
        "blocked": blocked,
        "missed": total - detected,
        "detection_rate_pct": round(detected / total * 100, 1) if total else 0,
        "by_tactic": by_tactic,
    }


def generate_report(target: str, siem_url: str = "", siem_key: str = "") -> dict:
    """Run BAS simulation campaign and generate detection gap report."""
    report = {"analysis_date": datetime.utcnow().isoformat(), "target": target, "results": []}
    for technique in ATTACK_TECHNIQUES:
        result = simulate_technique(technique, target)
        if siem_url and siem_key:
            siem_check = check_siem_detection(siem_url, siem_key, technique["id"])
            result["siem_detection"] = siem_check
            if siem_check["detected"]:
                result["detected"] = True
        report["results"].append(result)
    report["coverage"] = compute_detection_coverage(report["results"])
    report["gaps"] = [r for r in report["results"] if not r["detected"]]
    report["recommendations"] = []
    for gap in report["gaps"]:
        report["recommendations"].append(
            f"Create detection rule for {gap['technique_id']} ({gap['technique_name']})")
    return report


def main():
    parser = argparse.ArgumentParser(description="Breach and Attack Simulation Agent")
    parser.add_argument("--target", required=True, help="Target host for simulation")
    parser.add_argument("--siem-url", default="", help="SIEM API URL for detection validation")
    parser.add_argument("--siem-key", default="", help="SIEM API key")
    parser.add_argument("--output-dir", default=".")
    parser.add_argument("--output", default="bas_report.json")
    args = parser.parse_args()

    os.makedirs(args.output_dir, exist_ok=True)
    report = generate_report(args.target, args.siem_url, args.siem_key)
    out_path = os.path.join(args.output_dir, args.output)
    with open(out_path, "w") as f:
        json.dump(report, f, indent=2)
    logger.info("Report saved to %s", out_path)
    print(json.dumps(report["coverage"], indent=2))


if __name__ == "__main__":
    main()
process.py4.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
BAS Results Analyzer and Control Effectiveness Calculator

Processes Breach and Attack Simulation results to calculate
security control effectiveness scores and identify gaps.

Requirements:
    pip install pandas

Usage:
    python process.py analyze --csv bas_results.csv --output control_scores.csv
    python process.py gaps --csv bas_results.csv --output gaps.csv
    python process.py trend --dir results/ --output trend.csv
"""

import argparse
import sys
from collections import defaultdict
from datetime import datetime
from pathlib import Path

import pandas as pd


CONTROL_TECHNIQUE_MAP = {
    "email_gateway": ["T1566.001", "T1566.002", "T1566.003"],
    "edr": ["T1059.001", "T1059.003", "T1003.001", "T1055", "T1547.001",
            "T1053.005", "T1027", "T1140"],
    "ngfw_proxy": ["T1071.001", "T1071.004", "T1048.001", "T1048.003",
                   "T1572", "T1090"],
    "siem": ["T1087", "T1018", "T1069", "T1021.002", "T1021.001"],
    "dlp": ["T1048", "T1567", "T1041", "T1560"],
    "ndr": ["T1071", "T1021", "T1040", "T1046"],
    "waf": ["T1190", "T1210"],
    "pam": ["T1078", "T1134", "T1098"],
}


def analyze_control_effectiveness(df):
    """Calculate control effectiveness from BAS results."""
    scores = []

    for control, techniques in CONTROL_TECHNIQUE_MAP.items():
        relevant = df[df["technique_id"].isin(techniques)]
        if len(relevant) == 0:
            continue

        total = len(relevant)
        prevented = len(relevant[relevant["result"] == "prevented"])
        detected = len(relevant[relevant["result"] == "detected"])
        missed = len(relevant[relevant["result"] == "missed"])

        scores.append({
            "control": control,
            "total_tests": total,
            "prevented": prevented,
            "detected": detected,
            "missed": missed,
            "prevention_rate": round(prevented / total * 100, 1),
            "detection_rate": round(detected / total * 100, 1),
            "effectiveness": round((prevented + detected) / total * 100, 1),
            "gap_rate": round(missed / total * 100, 1),
        })

    return pd.DataFrame(scores).sort_values("effectiveness", ascending=True)


def identify_gaps(df):
    """Identify attack techniques that bypass all controls."""
    missed = df[df["result"] == "missed"].copy()
    if len(missed) == 0:
        print("[+] No gaps found - all attacks were prevented or detected!")
        return pd.DataFrame()

    gaps = missed.groupby(["technique_id", "technique_name"]).agg(
        miss_count=("result", "count"),
        targets=("target", lambda x: ", ".join(x.unique())),
    ).reset_index().sort_values("miss_count", ascending=False)

    return gaps


def print_summary(scores_df, gaps_df):
    """Print analysis summary."""
    print(f"\n{'=' * 70}")
    print("BAS CONTROL EFFECTIVENESS REPORT")
    print(f"{'=' * 70}")

    print(f"\nControl Scores:")
    for _, row in scores_df.iterrows():
        status = "PASS" if row["effectiveness"] >= 80 else "WARN" if row["effectiveness"] >= 60 else "FAIL"
        print(f"  [{status}] {row['control']:<15} "
              f"Effectiveness: {row['effectiveness']}% "
              f"(Prevent: {row['prevention_rate']}% | "
              f"Detect: {row['detection_rate']}% | "
              f"Miss: {row['gap_rate']}%)")

    if len(gaps_df) > 0:
        print(f"\nTop Security Gaps (attacks that bypass controls):")
        for _, row in gaps_df.head(10).iterrows():
            print(f"  {row['technique_id']}: {row['technique_name']} "
                  f"({row['miss_count']} misses)")


def main():
    parser = argparse.ArgumentParser(description="BAS Results Analyzer")
    subparsers = parser.add_subparsers(dest="command")

    a_p = subparsers.add_parser("analyze", help="Analyze control effectiveness")
    a_p.add_argument("--csv", required=True)
    a_p.add_argument("--output", default="control_scores.csv")

    g_p = subparsers.add_parser("gaps", help="Identify security gaps")
    g_p.add_argument("--csv", required=True)
    g_p.add_argument("--output", default="gaps.csv")

    args = parser.parse_args()

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

    df = pd.read_csv(args.csv)

    if args.command == "analyze":
        scores = analyze_control_effectiveness(df)
        gaps = identify_gaps(df)
        print_summary(scores, gaps)
        scores.to_csv(args.output, index=False)
        print(f"\n[+] Control scores saved to {args.output}")

    elif args.command == "gaps":
        gaps = identify_gaps(df)
        gaps.to_csv(args.output, index=False)
        print(f"[+] {len(gaps)} gaps saved to {args.output}")


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 0.8 KB
Keep exploring