Initial commit - 611 cybersecurity skills across all subdomains

This commit is contained in:
mukul975
2026-02-25 10:47:44 +01:00
commit 22a7ab1462
1765 changed files with 280648 additions and 0 deletions
@@ -0,0 +1,186 @@
---
name: containing-active-security-breach
description: Rapidly contain an active security breach by isolating compromised systems, blocking attacker communications, and preserving evidence while minimizing business disruption.
domain: cybersecurity
subdomain: incident-response
tags: [incident-response, containment, breach-response, network-isolation, dfir]
version: "1.0"
author: mahipal
license: MIT
---
# Containing an Active Security Breach
## When to Use
- Active unauthorized access detected on network or systems
- IDS/IPS alerts indicate ongoing exploitation or data exfiltration
- SOC analysts confirm a true positive security incident requiring immediate containment
- Lateral movement or privilege escalation observed in real time
- Ransomware encryption activity detected before full deployment
## Prerequisites
- Incident Response Plan with defined containment procedures
- Network access to firewalls, switches, and endpoint management consoles
- EDR/XDR platform deployed across endpoints (CrowdStrike, SentinelOne, Microsoft Defender for Endpoint)
- SIEM access with real-time log correlation (Splunk, Elastic, QRadar)
- Pre-approved authority to isolate systems (documented in IR plan)
- Forensic imaging tools ready for evidence preservation
## Workflow
### Step 1: Validate and Classify the Incident
```bash
# Check SIEM for correlated alerts - Splunk example
index=security sourcetype=ids_alerts severity=critical
| stats count by src_ip, dest_ip, signature
| where count > 5
| sort -count
# Verify endpoint alerts via CrowdStrike Falcon API
curl -X GET "https://api.crowdstrike.com/detects/queries/detects/v1?filter=status:'new'+max_severity_displayname:'Critical'" \
-H "Authorization: Bearer $FALCON_TOKEN"
```
### Step 2: Identify Scope of Compromise
```bash
# Identify all systems communicating with attacker C2
# Using Zeek connection logs
cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p duration orig_bytes resp_bytes \
| awk '$3 == 443 && $5 > 1000000' | sort -t$'\t' -k5 -rn | head -20
# Check for lateral movement in Windows Event Logs
wevtutil qe Security /q:"*[System[(EventID=4624)] and EventData[Data[@Name='LogonType']='3']]" /f:text /c:50
# Query Active Directory for recent authentication anomalies
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 100 |
Group-Object -Property {$_.Properties[5].Value} | Sort-Object Count -Descending
```
### Step 3: Execute Network Containment
```bash
# Block attacker IP at perimeter firewall (Palo Alto example)
set cli pager off
configure
set rulebase security rules emergency-block from any to any source [attacker_ip] action deny
set rulebase security rules emergency-block from any to any destination [attacker_ip] action deny
commit force
# Isolate compromised VLAN at switch level (Cisco)
configure terminal
interface vlan 100
shutdown
end
write memory
# Block C2 domains at DNS level
# Add to DNS sinkhole or RPZ
echo "attacker-c2-domain.com CNAME ." >> /etc/bind/rpz.local
rndc reload
```
### Step 4: Isolate Compromised Endpoints
```bash
# CrowdStrike - Network contain host via API
curl -X POST "https://api.crowdstrike.com/devices/entities/devices-actions/v2?action_name=contain" \
-H "Authorization: Bearer $FALCON_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": ["device_id_1", "device_id_2"]}'
# Microsoft Defender for Endpoint - Isolate machine
curl -X POST "https://api.securitycenter.microsoft.com/api/machines/{machineId}/isolate" \
-H "Authorization: Bearer $MDE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"Comment": "IR-2024-001: Active breach containment", "IsolationType": "Full"}'
# SentinelOne - Disconnect from network
curl -X POST "https://usea1.sentinelone.net/web/api/v2.1/agents/actions/disconnect" \
-H "Authorization: ApiToken $S1_TOKEN" \
-H "Content-Type: application/json" \
-d '{"filter": {"ids": ["agent_id"]}, "data": {}}'
```
### Step 5: Preserve Volatile Evidence Before Full Isolation
```bash
# Capture live memory from compromised Windows host
winpmem_mini_x64.exe memdump_hostname_$(date +%Y%m%d).raw
# Capture network connections and running processes
netstat -anob > netstat_capture_$(date +%Y%m%d_%H%M).txt
tasklist /V /FO CSV > process_list_$(date +%Y%m%d_%H%M).csv
wmic process list full > process_detail_$(date +%Y%m%d_%H%M).txt
# Linux volatile evidence collection
dd if=/proc/kcore of=/mnt/forensics/memory_$(hostname)_$(date +%Y%m%d).raw bs=1M
ss -tulnp > /mnt/forensics/network_$(hostname).txt
ps auxwwf > /mnt/forensics/processes_$(hostname).txt
```
### Step 6: Disable Compromised Accounts
```bash
# Disable compromised Active Directory accounts
Import-Module ActiveDirectory
Disable-ADAccount -Identity "compromised_user"
Set-ADUser -Identity "compromised_user" -Description "Disabled - IR-2024-001 $(Get-Date)"
# Revoke all active sessions
Revoke-AzureADUserAllRefreshToken -ObjectId "user_object_id"
# Reset service account credentials
Set-ADAccountPassword -Identity "svc_compromised" -Reset -NewPassword (ConvertTo-SecureString "TempP@ss$(Get-Random)" -AsPlainText -Force)
```
### Step 7: Validate Containment Effectiveness
```bash
# Verify no active C2 communications
tcpdump -i eth0 host attacker_ip -c 100 -w verification_capture.pcap
# Check for new lateral movement attempts
index=security sourcetype=wineventlog EventCode=4624 LogonType=3
earliest=-15m
| stats count by src_ip, dest_ip
| where src_ip IN ("compromised_hosts")
# Validate endpoint isolation status
curl -X GET "https://api.crowdstrike.com/devices/entities/devices/v2?ids=device_id" \
-H "Authorization: Bearer $FALCON_TOKEN" | jq '.resources[].status'
```
## Key Concepts
| Concept | Description |
|---------|-------------|
| Short-term Containment | Immediate actions to stop active damage (network isolation, account disable) |
| Long-term Containment | Sustainable measures while investigation continues (VLAN segmentation, enhanced monitoring) |
| Evidence Preservation | Capturing volatile data before containment actions destroy forensic artifacts |
| Blast Radius | Total scope of systems, accounts, and data affected by the breach |
| Containment Boundary | Network and logical perimeter established to prevent further spread |
| Kill Chain Disruption | Breaking the attacker's operational chain at the earliest possible stage |
| Business Continuity | Maintaining critical operations while containing the threat |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| CrowdStrike Falcon | Endpoint detection, network containment of hosts |
| Microsoft Defender for Endpoint | Endpoint isolation and automated investigation |
| Palo Alto NGFW | Perimeter firewall rules for IP/domain blocking |
| Splunk/Elastic SIEM | Real-time alert correlation and scope analysis |
| Zeek (Bro) | Network traffic analysis for C2 identification |
| Velociraptor | Remote forensic collection and endpoint querying |
| Active Directory | Account management and authentication control |
## Common Scenarios
1. **Ransomware Pre-Encryption**: Attacker has deployed ransomware binary but encryption hasn't started. Isolate patient zero, block C2, and prevent lateral deployment.
2. **Active Data Exfiltration**: Data is being exfiltrated to external server. Block egress to C2, capture network evidence, isolate affected systems.
3. **Compromised Domain Controller**: Attacker has DC access. Isolate DC from network, reset KRBTGT twice, rotate all privileged credentials.
4. **Supply Chain Compromise**: Malicious update deployed across environment. Block update server, isolate systems that received the update, assess scope.
5. **Insider Threat - Active Exfil**: Employee actively copying sensitive data. Disable account, block USB access, preserve evidence chain.
## Output Format
- Containment action log with timestamps (who, what, when)
- Network isolation verification report
- List of compromised/isolated systems with justification
- Evidence preservation checksums and chain of custody records
- Containment effectiveness validation results
- Stakeholder notification with current status and next steps
@@ -0,0 +1,130 @@
# Breach Containment Action Report
## Incident Information
| Field | Value |
|-------|-------|
| Incident ID | IR-YYYY-NNN |
| Date/Time Detected | YYYY-MM-DD HH:MM UTC |
| Containment Started | YYYY-MM-DD HH:MM UTC |
| Containment Completed | YYYY-MM-DD HH:MM UTC |
| Incident Commander | [Name] |
| Severity Level | [Critical/High/Medium/Low] |
## Incident Summary
[Brief description of the breach - what was detected, initial indicators, how the breach was discovered]
## Scope of Compromise
### Affected Systems
| Hostname | IP Address | Role | Compromise Evidence | Containment Action |
|----------|-----------|------|--------------------|--------------------|
| | | | | |
### Compromised Accounts
| Account Name | Account Type | Last Logon | Containment Action | Status |
|-------------|-------------|------------|-------------------|--------|
| | | | | |
### Affected Data
| Data Classification | Data Type | Volume | Exfiltration Confirmed | Evidence |
|--------------------|-----------|--------|----------------------|----------|
| | | | | |
## Attack Timeline
| Time (UTC) | Event | Source | Details |
|-----------|-------|--------|---------|
| | Initial access detected | | |
| | Lateral movement observed | | |
| | Containment initiated | | |
| | Containment verified | | |
## Containment Actions Taken
### Network Containment
- [ ] Attacker IPs blocked at perimeter firewall
- IPs blocked: [list]
- Firewall rule name/ID: [reference]
- [ ] C2 domains sinkholed
- Domains: [list]
- Method: [DNS sinkhole/RPZ/hosts file]
- [ ] Compromised network segments isolated
- VLANs/subnets: [list]
- Method: [ACL/VLAN shutdown/firewall rule]
### Endpoint Containment
- [ ] Compromised hosts network-contained via EDR
- EDR platform: [CrowdStrike/SentinelOne/MDE]
- Hosts isolated: [list]
- [ ] Malicious processes terminated
- Processes: [list with PIDs]
- [ ] Unauthorized software quarantined
- Files: [list with hashes]
### Identity Containment
- [ ] Compromised user accounts disabled
- Accounts: [list]
- [ ] Active sessions revoked
- Method: [Azure AD/On-prem AD]
- [ ] Service account credentials rotated
- Accounts: [list]
- [ ] MFA tokens reset
- Users: [list]
### DNS/Web Containment
- [ ] Malicious domains blocked at DNS
- [ ] Web proxy rules updated
- [ ] SSL certificates revoked (if applicable)
## Evidence Preserved
### Volatile Evidence (Collected Before Isolation)
| Evidence Type | Host | Collection Time | SHA256 Hash | Collector |
|--------------|------|-----------------|-------------|-----------|
| Memory dump | | | | |
| Network connections | | | | |
| Process list | | | | |
| DNS cache | | | | |
### Network Evidence
| Capture Type | Source | Time Range | File Size | SHA256 Hash |
|-------------|--------|------------|-----------|-------------|
| PCAP | | | | |
| NetFlow | | | | |
## Containment Verification
### Verification Checks
- [ ] No active C2 communications detected post-containment
- [ ] No new lateral movement attempts observed
- [ ] All compromised accounts confirmed disabled
- [ ] Isolated systems confirmed unreachable from network
- [ ] Business-critical services tested and operational
- [ ] Enhanced monitoring deployed on adjacent systems
### Monitoring Status
| Monitor Type | Scope | Status | Alert Threshold |
|-------------|-------|--------|----------------|
| Network traffic | Compromised segments | Active/Pending | |
| EDR alerts | All endpoints | Active/Pending | |
| Authentication logs | Domain-wide | Active/Pending | |
| Data loss prevention | Sensitive repositories | Active/Pending | |
## Business Impact Assessment
| Service/System | Impact Level | Workaround Available | Estimated Restore |
|---------------|-------------|---------------------|-------------------|
| | | | |
## Next Steps
1. [ ] Complete forensic imaging of all compromised systems
2. [ ] Begin eradication phase - remove attacker persistence
3. [ ] Conduct root cause analysis
4. [ ] Prepare for recovery phase
5. [ ] Schedule stakeholder briefing
## Approvals
| Role | Name | Signature | Date |
|------|------|-----------|------|
| Incident Commander | | | |
| CISO | | | |
| IT Director | | | |
| Legal Counsel | | | |
@@ -0,0 +1,66 @@
# Standards and Framework References
## NIST SP 800-61 Rev. 3 - Incident Response Recommendations
- **Respond (RS) Function**: Containment falls under RS.MI (Incident Mitigation)
- RS.MI-01: Incidents are contained
- RS.MI-02: Incidents are eradicated
- **Detect (DE) Function**: Scope identification maps to DE.AE (Adverse Event Analysis)
- DE.AE-02: Potentially adverse events are analyzed to better understand associated activities
- DE.AE-03: Information is correlated from multiple sources
- Reference: https://csrc.nist.gov/pubs/sp/800/61/r3/final
## NIST SP 800-61 Rev. 2 - Computer Security Incident Handling Guide
- **Section 3.3**: Containment, Eradication, and Recovery
- 3.3.1: Choosing a Containment Strategy
- 3.3.2: Evidence Gathering and Handling
- 3.3.3: Identifying the Attacking Hosts
- Containment strategy criteria: potential damage, evidence preservation needs, service availability, time/resources, effectiveness duration, solution scope
- Reference: https://csrc.nist.gov/pubs/sp/800/61/r2/final
## SANS PICERL Framework
- **Phase 3 - Containment**: The SANS Incident Handler's Handbook defines containment as actions to limit damage from an incident
- Short-term containment: Immediate response to stop the bleeding
- System back-up: Forensic image before remediation
- Long-term containment: Temporary fixes allowing production use
- Reference: https://www.sans.org/white-papers/33901
## MITRE ATT&CK Framework - Relevant Techniques to Contain
### Initial Access (TA0001)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1566 | Phishing | Block sender, quarantine messages |
| T1190 | Exploit Public-Facing Application | Patch/WAF rule, isolate service |
| T1133 | External Remote Services | Disable VPN/RDP access |
| T1078 | Valid Accounts | Disable/reset compromised accounts |
### Lateral Movement (TA0008)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1021 | Remote Services | Block SMB/RDP/WinRM between segments |
| T1550 | Use Alternate Authentication Material | Reset tokens, rotate KRBTGT |
| T1570 | Lateral Tool Transfer | Block file sharing protocols |
### Command and Control (TA0011)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1071 | Application Layer Protocol | Block C2 domains/IPs at firewall |
| T1573 | Encrypted Channel | SSL inspection, block non-standard TLS |
| T1572 | Protocol Tunneling | Block DNS tunneling, inspect traffic |
### Exfiltration (TA0010)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1041 | Exfiltration Over C2 Channel | Sinkhole C2 domains |
| T1048 | Exfiltration Over Alternative Protocol | Block DNS/ICMP exfil |
| T1567 | Exfiltration Over Web Service | Block cloud storage uploads |
## CISA Incident Response Playbooks
- Federal Government Cybersecurity Incident and Vulnerability Response Playbooks
- Containment actions aligned with federal response guidelines
- Reference: https://www.cisa.gov/sites/default/files/publications/Federal_Government_Cybersecurity_Incident_and_Vulnerability_Response_Playbooks_508C.pdf
## ISO/IEC 27035 - Information Security Incident Management
- Part 2: Guidelines to plan and prepare for incident response
- Containment classified as part of "Response" phase
- Emphasis on proportional response and business impact consideration
@@ -0,0 +1,107 @@
# Containing an Active Security Breach - Detailed Workflow
## Pre-Containment Decision Framework
### Containment Strategy Selection Matrix
| Factor | Low Impact | Medium Impact | High Impact |
|--------|-----------|---------------|-------------|
| Data sensitivity | Monitor and assess | Partial isolation | Full network isolation |
| Active exfiltration | Block egress IPs | Block + isolate segment | Air-gap + full isolation |
| Lateral movement | Enhanced monitoring | Segment isolation | Domain-wide lockdown |
| Business criticality | Targeted containment | Phased containment | Emergency containment with DR |
| Ransomware deployment | Isolate patient zero | Segment + block C2 | Enterprise-wide isolation |
## Step-by-Step Procedure
### Phase 1: Incident Validation (0-15 minutes)
1. Receive alert from SIEM/EDR/SOC analyst
2. Verify alert is true positive by correlating multiple data sources
3. Classify incident severity using organization's severity matrix
4. Activate incident response team based on severity level
5. Establish incident communication channel (war room or Slack/Teams channel)
6. Assign Incident Commander and document in ticketing system
### Phase 2: Scope Assessment (15-45 minutes)
1. Query SIEM for all related alerts in the past 72 hours
2. Identify all compromised hosts using EDR telemetry
3. Map network connections from compromised hosts to identify lateral movement
4. Check authentication logs for compromised account usage across systems
5. Identify affected data repositories and assess data classification
6. Document the attack timeline and current threat actor position
7. Determine the attack vector (how did they get in)
### Phase 3: Short-Term Containment (30-60 minutes)
1. **Network Level**:
- Block attacker external IPs at perimeter firewall
- Sinkhole C2 domains at DNS level
- Apply ACLs to isolate compromised network segments
- Enable enhanced packet capture on affected segments
2. **Endpoint Level**:
- Network-contain compromised hosts via EDR
- Disable compromised user accounts in Active Directory
- Revoke OAuth tokens and API keys
- Kill malicious processes identified by EDR
3. **Identity Level**:
- Force password reset on compromised accounts
- Disable MFA bypass methods used by attacker
- Revoke VPN certificates for compromised users
- Block compromised service account authentication
### Phase 4: Evidence Preservation (During Containment)
1. Capture live memory from key compromised systems before full isolation
2. Export relevant SIEM logs to secure evidence storage
3. Take forensic disk images of critical compromised systems
4. Preserve network capture data (PCAP) from affected segments
5. Screenshot active sessions and running process trees
6. Hash all evidence files and create chain of custody documentation
### Phase 5: Long-Term Containment (1-24 hours)
1. Implement network microsegmentation around affected areas
2. Deploy additional monitoring sensors in compromised zones
3. Set up honeypots to detect continued attacker activity
4. Apply temporary firewall rules with logging for affected segments
5. Enable enhanced audit logging on systems adjacent to compromise
6. Implement file integrity monitoring on critical systems
7. Set up network traffic baseline comparison
### Phase 6: Containment Verification (Ongoing)
1. Monitor for new alerts from previously compromised systems
2. Verify no new C2 communications from any internal host
3. Check for new account creation or privilege escalation attempts
4. Validate that isolated systems cannot reach external networks
5. Test that critical business services remain functional
6. Brief stakeholders on containment status and next steps
## Escalation Criteria
- Containment fails (attacker regains access): Escalate to CISO, consider external IR firm
- Business-critical systems affected: Engage business continuity team
- Data exfiltration confirmed: Engage legal and compliance teams
- Nation-state indicators: Engage FBI/CISA
- Ransomware spreading despite containment: Consider full network shutdown
## Communication Templates
### Internal Escalation (Initial)
```
SUBJECT: [SEVERITY-CRITICAL] Active Security Breach - Containment in Progress
INCIDENT ID: IR-YYYY-NNN
TIME DETECTED: YYYY-MM-DD HH:MM UTC
CURRENT STATUS: Containment in progress
AFFECTED SYSTEMS: [count] hosts, [count] accounts
INCIDENT COMMANDER: [Name]
NEXT UPDATE: [time]
```
### Status Update (During Containment)
```
SUBJECT: [UPDATE] IR-YYYY-NNN - Containment Status
CONTAINMENT STATUS: [Partial/Complete/Pending]
SYSTEMS ISOLATED: [count]
ACCOUNTS DISABLED: [count]
C2 COMMUNICATIONS: [Blocked/Active/Unknown]
BUSINESS IMPACT: [Description]
NEXT STEPS: [Actions]
NEXT UPDATE: [time]
```
@@ -0,0 +1,517 @@
#!/usr/bin/env python3
"""
Active Security Breach Containment Automation Script
Automates containment actions during an active security breach:
- Queries SIEM for scope assessment
- Isolates endpoints via EDR API
- Blocks IPs/domains at firewall
- Disables compromised AD accounts
- Generates containment action log
Requirements:
pip install requests ldap3 python-dateutil pyyaml
"""
import argparse
import csv
import hashlib
import json
import logging
import os
import socket
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional
try:
import requests
except ImportError:
print("Install requests: pip install requests")
sys.exit(1)
try:
from ldap3 import Server, Connection, MODIFY_REPLACE, ALL
except ImportError:
ldap3_available = False
else:
ldap3_available = True
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.StreamHandler(),
logging.FileHandler(f"containment_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"),
],
)
logger = logging.getLogger("breach_containment")
class ContainmentActionLog:
"""Tracks all containment actions with timestamps for audit trail."""
def __init__(self, incident_id: str):
self.incident_id = incident_id
self.actions = []
self.start_time = datetime.now(timezone.utc)
def log_action(self, action_type: str, target: str, result: str, details: str = ""):
entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"incident_id": self.incident_id,
"action_type": action_type,
"target": target,
"result": result,
"details": details,
"operator": os.getenv("USERNAME", os.getenv("USER", "unknown")),
}
self.actions.append(entry)
logger.info(f"[{action_type}] {target}: {result} - {details}")
def export_csv(self, filepath: str):
if not self.actions:
logger.warning("No actions to export")
return
with open(filepath, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=self.actions[0].keys())
writer.writeheader()
writer.writerows(self.actions)
logger.info(f"Containment log exported to {filepath}")
def export_json(self, filepath: str):
report = {
"incident_id": self.incident_id,
"containment_start": self.start_time.isoformat(),
"containment_end": datetime.now(timezone.utc).isoformat(),
"total_actions": len(self.actions),
"actions": self.actions,
}
with open(filepath, "w") as f:
json.dump(report, f, indent=2)
logger.info(f"Containment report exported to {filepath}")
class CrowdStrikeContainment:
"""CrowdStrike Falcon endpoint containment via API."""
def __init__(self, client_id: str, client_secret: str, base_url: str = "https://api.crowdstrike.com"):
self.base_url = base_url
self.client_id = client_id
self.client_secret = client_secret
self.token = None
def authenticate(self):
resp = requests.post(
f"{self.base_url}/oauth2/token",
data={"client_id": self.client_id, "client_secret": self.client_secret},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
resp.raise_for_status()
self.token = resp.json()["access_token"]
logger.info("Authenticated to CrowdStrike Falcon API")
def _headers(self):
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
def get_device_id_by_hostname(self, hostname: str) -> Optional[str]:
resp = requests.get(
f"{self.base_url}/devices/queries/devices/v1",
headers=self._headers(),
params={"filter": f"hostname:'{hostname}'"},
)
resp.raise_for_status()
resources = resp.json().get("resources", [])
return resources[0] if resources else None
def contain_host(self, device_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/devices/entities/devices-actions/v2",
headers=self._headers(),
params={"action_name": "contain"},
json={"ids": [device_id]},
)
resp.raise_for_status()
return resp.json()
def lift_containment(self, device_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/devices/entities/devices-actions/v2",
headers=self._headers(),
params={"action_name": "lift_containment"},
json={"ids": [device_id]},
)
resp.raise_for_status()
return resp.json()
def get_detections(self, severity: str = "Critical") -> list:
resp = requests.get(
f"{self.base_url}/detects/queries/detects/v1",
headers=self._headers(),
params={"filter": f"max_severity_displayname:'{severity}'+status:'new'", "limit": 100},
)
resp.raise_for_status()
return resp.json().get("resources", [])
class SentinelOneContainment:
"""SentinelOne endpoint containment via API."""
def __init__(self, api_token: str, base_url: str):
self.base_url = base_url
self.api_token = api_token
def _headers(self):
return {"Authorization": f"ApiToken {self.api_token}", "Content-Type": "application/json"}
def disconnect_agent(self, agent_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/web/api/v2.1/agents/actions/disconnect",
headers=self._headers(),
json={"filter": {"ids": [agent_id]}, "data": {}},
)
resp.raise_for_status()
return resp.json()
def reconnect_agent(self, agent_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/web/api/v2.1/agents/actions/connect",
headers=self._headers(),
json={"filter": {"ids": [agent_id]}, "data": {}},
)
resp.raise_for_status()
return resp.json()
class ActiveDirectoryContainment:
"""Active Directory account containment via LDAP."""
def __init__(self, server_addr: str, domain: str, username: str, password: str):
if not ldap3_available:
raise ImportError("ldap3 package required: pip install ldap3")
self.server = Server(server_addr, get_info=ALL)
self.domain = domain
self.conn = Connection(self.server, user=f"{domain}\\{username}", password=password, auto_bind=True)
def disable_account(self, sam_account_name: str) -> bool:
search_base = ",".join([f"DC={part}" for part in self.domain.split(".")])
self.conn.search(
search_base,
f"(sAMAccountName={sam_account_name})",
attributes=["userAccountControl", "distinguishedName"],
)
if not self.conn.entries:
logger.warning(f"Account {sam_account_name} not found in AD")
return False
dn = self.conn.entries[0].distinguishedName.value
current_uac = int(self.conn.entries[0].userAccountControl.value)
# Set ACCOUNTDISABLE flag (bit 1, value 2)
new_uac = current_uac | 0x0002
self.conn.modify(dn, {"userAccountControl": [(MODIFY_REPLACE, [str(new_uac)])]})
logger.info(f"Disabled AD account: {sam_account_name}")
return True
def reset_password(self, sam_account_name: str, new_password: str) -> bool:
search_base = ",".join([f"DC={part}" for part in self.domain.split(".")])
self.conn.search(search_base, f"(sAMAccountName={sam_account_name})", attributes=["distinguishedName"])
if not self.conn.entries:
return False
dn = self.conn.entries[0].distinguishedName.value
encoded_pw = f'"{new_password}"'.encode("utf-16-le")
self.conn.modify(dn, {"unicodePwd": [(MODIFY_REPLACE, [encoded_pw])]})
logger.info(f"Reset password for AD account: {sam_account_name}")
return True
class FirewallContainment:
"""Block IPs and domains at network perimeter."""
@staticmethod
def block_ips_iptables(ip_list: list, chain: str = "INPUT") -> list:
results = []
for ip in ip_list:
try:
cmd = ["iptables", "-A", chain, "-s", ip, "-j", "DROP"]
subprocess.run(cmd, capture_output=True, text=True, check=True)
cmd_out = ["iptables", "-A", "OUTPUT", "-d", ip, "-j", "DROP"]
subprocess.run(cmd_out, capture_output=True, text=True, check=True)
results.append({"ip": ip, "status": "blocked", "method": "iptables"})
logger.info(f"Blocked IP via iptables: {ip}")
except subprocess.CalledProcessError as e:
results.append({"ip": ip, "status": "failed", "error": str(e)})
logger.error(f"Failed to block IP {ip}: {e}")
return results
@staticmethod
def block_ips_windows_firewall(ip_list: list) -> list:
results = []
for ip in ip_list:
try:
rule_name = f"IR_Block_{ip.replace('.', '_')}"
cmd = [
"netsh", "advfirewall", "firewall", "add", "rule",
f"name={rule_name}", "dir=in", "action=block",
f"remoteip={ip}", "protocol=any",
]
subprocess.run(cmd, capture_output=True, text=True, check=True)
cmd_out = [
"netsh", "advfirewall", "firewall", "add", "rule",
f"name={rule_name}_out", "dir=out", "action=block",
f"remoteip={ip}", "protocol=any",
]
subprocess.run(cmd_out, capture_output=True, text=True, check=True)
results.append({"ip": ip, "status": "blocked", "method": "windows_firewall"})
logger.info(f"Blocked IP via Windows Firewall: {ip}")
except subprocess.CalledProcessError as e:
results.append({"ip": ip, "status": "failed", "error": str(e)})
logger.error(f"Failed to block IP {ip}: {e}")
return results
@staticmethod
def block_domains_hosts_file(domain_list: list) -> list:
results = []
hosts_path = r"C:\Windows\System32\drivers\etc\hosts" if os.name == "nt" else "/etc/hosts"
try:
with open(hosts_path, "a") as f:
for domain in domain_list:
f.write(f"\n0.0.0.0 {domain} # IR Containment Block")
results.append({"domain": domain, "status": "sinkholed", "method": "hosts_file"})
logger.info(f"Sinkholed domain: {domain}")
except PermissionError:
logger.error("Insufficient permissions to modify hosts file. Run as administrator.")
for domain in domain_list:
results.append({"domain": domain, "status": "failed", "error": "permission_denied"})
return results
class SplunkScopeAssessment:
"""Query Splunk SIEM for incident scope assessment."""
def __init__(self, base_url: str, token: str):
self.base_url = base_url
self.token = token
def _headers(self):
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
def search(self, query: str, earliest: str = "-24h", latest: str = "now") -> dict:
resp = requests.post(
f"{self.base_url}/services/search/jobs",
headers=self._headers(),
data={
"search": f"search {query}",
"earliest_time": earliest,
"latest_time": latest,
"output_mode": "json",
},
verify=False,
)
resp.raise_for_status()
return resp.json()
def find_related_hosts(self, attacker_ip: str) -> dict:
query = f"""index=security (src_ip="{attacker_ip}" OR dest_ip="{attacker_ip}")
| stats count values(dest_ip) as targets values(src_ip) as sources by sourcetype
| sort -count"""
return self.search(query)
def find_compromised_accounts(self, host_list: list) -> dict:
hosts_filter = " OR ".join([f'src="{h}"' for h in host_list])
query = f"""index=security EventCode=4624 ({hosts_filter})
| stats count values(src) as source_hosts by Account_Name, Logon_Type
| where Logon_Type IN ("3","10")
| sort -count"""
return self.search(query)
def collect_volatile_evidence(output_dir: str) -> dict:
"""Collect volatile evidence from current system before containment."""
os.makedirs(output_dir, exist_ok=True)
evidence = {}
# Network connections
try:
if os.name == "nt":
result = subprocess.run(["netstat", "-anob"], capture_output=True, text=True)
else:
result = subprocess.run(["ss", "-tulnp"], capture_output=True, text=True)
netconn_file = os.path.join(output_dir, "network_connections.txt")
with open(netconn_file, "w") as f:
f.write(result.stdout)
evidence["network_connections"] = {
"file": netconn_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect network connections: {e}")
# Running processes
try:
if os.name == "nt":
result = subprocess.run(["tasklist", "/V", "/FO", "CSV"], capture_output=True, text=True)
else:
result = subprocess.run(["ps", "auxwwf"], capture_output=True, text=True)
proc_file = os.path.join(output_dir, "running_processes.txt")
with open(proc_file, "w") as f:
f.write(result.stdout)
evidence["running_processes"] = {
"file": proc_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect process list: {e}")
# DNS cache
try:
if os.name == "nt":
result = subprocess.run(["ipconfig", "/displaydns"], capture_output=True, text=True)
else:
dns_cache_file = "/var/cache/nscd/hosts" if os.path.exists("/var/cache/nscd/hosts") else ""
result = subprocess.run(["cat", dns_cache_file], capture_output=True, text=True) if dns_cache_file else None
if result and result.stdout:
dns_file = os.path.join(output_dir, "dns_cache.txt")
with open(dns_file, "w") as f:
f.write(result.stdout)
evidence["dns_cache"] = {
"file": dns_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect DNS cache: {e}")
# ARP table
try:
result = subprocess.run(["arp", "-a"], capture_output=True, text=True)
arp_file = os.path.join(output_dir, "arp_table.txt")
with open(arp_file, "w") as f:
f.write(result.stdout)
evidence["arp_table"] = {
"file": arp_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect ARP table: {e}")
# Logged-in users
try:
if os.name == "nt":
result = subprocess.run(["query", "user"], capture_output=True, text=True)
else:
result = subprocess.run(["who"], capture_output=True, text=True)
users_file = os.path.join(output_dir, "logged_in_users.txt")
with open(users_file, "w") as f:
f.write(result.stdout)
evidence["logged_in_users"] = {
"file": users_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect logged-in users: {e}")
return evidence
def run_containment(args):
"""Execute the full containment workflow."""
action_log = ContainmentActionLog(args.incident_id)
logger.info(f"Starting containment for incident: {args.incident_id}")
# Step 1: Collect volatile evidence if requested
if args.collect_evidence:
evidence_dir = os.path.join(args.output_dir, "evidence", args.incident_id)
logger.info(f"Collecting volatile evidence to {evidence_dir}")
evidence = collect_volatile_evidence(evidence_dir)
for etype, edata in evidence.items():
action_log.log_action("evidence_collection", etype, "collected", f"SHA256: {edata['sha256']}")
# Step 2: Block IPs at firewall
if args.block_ips:
ip_list = [ip.strip() for ip in args.block_ips.split(",")]
logger.info(f"Blocking {len(ip_list)} IPs at firewall")
if os.name == "nt":
results = FirewallContainment.block_ips_windows_firewall(ip_list)
else:
results = FirewallContainment.block_ips_iptables(ip_list)
for r in results:
action_log.log_action("ip_block", r["ip"], r["status"], r.get("method", r.get("error", "")))
# Step 3: Block domains
if args.block_domains:
domain_list = [d.strip() for d in args.block_domains.split(",")]
logger.info(f"Sinkholing {len(domain_list)} domains")
results = FirewallContainment.block_domains_hosts_file(domain_list)
for r in results:
action_log.log_action("domain_block", r["domain"], r["status"], r.get("method", ""))
# Step 4: Isolate endpoints via CrowdStrike
if args.crowdstrike_isolate and args.cs_client_id and args.cs_client_secret:
cs = CrowdStrikeContainment(args.cs_client_id, args.cs_client_secret)
try:
cs.authenticate()
action_log.log_action("edr_auth", "crowdstrike", "success", "API authenticated")
hostnames = [h.strip() for h in args.crowdstrike_isolate.split(",")]
for hostname in hostnames:
device_id = cs.get_device_id_by_hostname(hostname)
if device_id:
cs.contain_host(device_id)
action_log.log_action("endpoint_isolation", hostname, "contained", f"Device ID: {device_id}")
else:
action_log.log_action("endpoint_isolation", hostname, "failed", "Device not found in Falcon")
except Exception as e:
action_log.log_action("edr_auth", "crowdstrike", "failed", str(e))
logger.error(f"CrowdStrike containment failed: {e}")
# Step 5: Disable AD accounts
if args.disable_accounts and args.ad_server and ldap3_available:
try:
ad = ActiveDirectoryContainment(
args.ad_server, args.ad_domain, args.ad_username, args.ad_password
)
accounts = [a.strip() for a in args.disable_accounts.split(",")]
for account in accounts:
result = ad.disable_account(account)
action_log.log_action(
"account_disable", account, "disabled" if result else "failed",
"AD account disabled" if result else "Account not found",
)
except Exception as e:
action_log.log_action("account_disable", "AD", "failed", str(e))
logger.error(f"AD containment failed: {e}")
# Export containment action log
os.makedirs(args.output_dir, exist_ok=True)
csv_path = os.path.join(args.output_dir, f"containment_log_{args.incident_id}.csv")
json_path = os.path.join(args.output_dir, f"containment_report_{args.incident_id}.json")
action_log.export_csv(csv_path)
action_log.export_json(json_path)
logger.info(f"Containment workflow completed for {args.incident_id}")
logger.info(f"Total actions taken: {len(action_log.actions)}")
return action_log
def main():
parser = argparse.ArgumentParser(description="Active Security Breach Containment Automation")
parser.add_argument("--incident-id", required=True, help="Incident tracking ID (e.g., IR-2024-001)")
parser.add_argument("--output-dir", default="./containment_output", help="Output directory for logs and reports")
parser.add_argument("--collect-evidence", action="store_true", help="Collect volatile evidence before containment")
parser.add_argument("--block-ips", help="Comma-separated list of IPs to block at firewall")
parser.add_argument("--block-domains", help="Comma-separated list of domains to sinkhole")
parser.add_argument("--crowdstrike-isolate", help="Comma-separated hostnames to isolate via CrowdStrike")
parser.add_argument("--cs-client-id", default=os.getenv("CS_CLIENT_ID"), help="CrowdStrike API client ID")
parser.add_argument("--cs-client-secret", default=os.getenv("CS_CLIENT_SECRET"), help="CrowdStrike API client secret")
parser.add_argument("--disable-accounts", help="Comma-separated AD accounts to disable")
parser.add_argument("--ad-server", default=os.getenv("AD_SERVER"), help="Active Directory server address")
parser.add_argument("--ad-domain", default=os.getenv("AD_DOMAIN"), help="Active Directory domain")
parser.add_argument("--ad-username", default=os.getenv("AD_USERNAME"), help="AD admin username")
parser.add_argument("--ad-password", default=os.getenv("AD_PASSWORD"), help="AD admin password")
args = parser.parse_args()
run_containment(args)
if __name__ == "__main__":
main()