Featured image of post SOAR Playbook: Ransomware Response

SOAR Playbook: Ransomware Response

A structured SOAR playbook for ransomware incidents — from initial detection through isolation, scope assessment, recovery coordination, and post-incident hardening.

Overview

Ransomware incidents demand the fastest, most disciplined response of any security event. Every minute of delay allows encryption to spread further, backup systems to be targeted, and recovery costs to compound. This playbook automates the containment decisions that must happen in the first five minutes — before a human analyst can even open a ticket.

The playbook covers:

  • Automatic isolation of affected endpoints
  • Scope determination (is this one machine or an active campaign?)
  • Backup integrity verification
  • Communication workflows to IT, management, and legal
  • Recovery orchestration

Detection Sources (Triggers)

The playbook fires from any of the following:

Source Signal
EDR (CrowdStrike / SentinelOne) Ransomware behavioural detection, shadow copy deletion, mass file rename
SIEM High volume file extension changes (.locked, .enc, .crypt) on file servers
Endpoint vssadmin delete shadows or wmic shadowcopy delete process execution
User report Ransom note discovered and reported to helpdesk

Decision Tree

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Ransomware Alert Triggered
  Is this a true positive?
  (EDR confidence ≥ HIGH or
   ransom note confirmed?)
     YES  │  NO
          │   └──► Escalate to analyst for review
  How many endpoints affected?
    ┌─────┴──────┐
  1–3            4+
  hosts          hosts
    │              │
    ▼              ▼
Isolate         Initiate
silently        Crisis Bridge
                Notify CISO
         Isolate all affected hosts
         Block lateral movement (network segmentation)
          ┌─────────┴──────────┐
       Backups              Backups
       intact?              compromised?
          │                      │
          ▼                      ▼
    Begin recovery          Engage DR plan
    from clean backup       Notify legal/insurance

Step-by-Step Logic

Step 1 — Validate the Alert

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def validate_ransomware_alert(alert):
    confidence_score = 0

    # EDR detection from a known ransomware family
    if alert.edr_classification in KNOWN_RANSOMWARE_FAMILIES:
        confidence_score += 50

    # Shadow copy deletion — near-certain ransomware indicator
    if alert.process_cmdline and any(cmd in alert.process_cmdline for cmd in [
        'vssadmin delete shadows',
        'wmic shadowcopy delete',
        'bcdedit /set recoveryenabled no'
    ]):
        confidence_score += 40

    # Mass file rename (>100 files with new extension in 60 seconds)
    if alert.file_rename_count > 100:
        confidence_score += 30

    # Ransom note file created
    if alert.file_created and any(
        note in alert.file_created.lower()
        for note in ['readme', 'decrypt', 'how_to', 'ransom', 'restore_files']
    ):
        confidence_score += 30

    return confidence_score >= 50, confidence_score

Step 2 — Isolate Affected Endpoints

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def isolate_endpoints(affected_hosts, edr_client):
    isolation_results = []

    for host in affected_hosts:
        try:
            # CrowdStrike network containment
            result = edr_client.contain_host(device_id=host.device_id)
            isolation_results.append({
                'hostname': host.hostname,
                'status': 'ISOLATED',
                'timestamp': datetime.utcnow().isoformat(),
                'method': 'EDR network containment'
            })
        except Exception as e:
            # Fallback: firewall-level block
            firewall_block_host(host.ip_address)
            isolation_results.append({
                'hostname': host.hostname,
                'status': 'ISOLATED_FALLBACK',
                'method': 'Firewall ACL'
            })

    return isolation_results

def assess_blast_radius(initial_host, siem_client, lookback_minutes=30):
    """Find other hosts that communicated with the affected host
       in the window before detection."""
    query = f"""
    index=network_traffic
    (src_ip="{initial_host.ip}" OR dest_ip="{initial_host.ip}")
    earliest=-{lookback_minutes}m
    | stats values(src_ip) as sources, values(dest_ip) as destinations by _time
    """
    results = siem_client.search(query)
    lateral_candidates = set()
    for r in results:
        lateral_candidates.update(r['sources'] + r['destinations'])
    lateral_candidates.discard(initial_host.ip)
    return list(lateral_candidates)

Step 3 — Identify the Ransomware Family

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import hashlib
import requests

def identify_ransomware_family(ransom_note_text, encrypted_file_extension):
    """
    Query ID Ransomware (public API) to identify the family
    from the ransom note or encrypted file extension.
    """
    # Check extension against known families database
    known_extensions = {
        '.lockbit': 'LockBit',
        '.blackcat': 'BlackCat/ALPHV',
        '.hive':    'Hive',
        '.phobos':  'Phobos',
        '.dharma':  'Dharma/CrySis',
        '.ryuk':    'Ryuk',
    }
    family = known_extensions.get(encrypted_file_extension.lower(), 'Unknown')

    # Cross-reference with VirusTotal if we have a sample hash
    return {
        'family': family,
        'extension': encrypted_file_extension,
        'note_preview': ransom_note_text[:200] if ransom_note_text else None
    }

Step 4 — Verify Backup Integrity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def verify_backup_integrity(affected_systems, backup_client):
    """
    Check whether backups for affected systems exist and
    were last written BEFORE the ransomware activity window.
    """
    backup_status = []

    for system in affected_systems:
        backups = backup_client.get_backups(system.hostname)

        if not backups:
            backup_status.append({
                'system': system.hostname,
                'status': 'NO_BACKUP',
                'action': 'ESCALATE_TO_DR'
            })
            continue

        latest_backup = max(backups, key=lambda b: b.timestamp)
        attack_start = system.first_detection_time

        if latest_backup.timestamp < attack_start:
            backup_status.append({
                'system': system.hostname,
                'status': 'CLEAN_BACKUP_AVAILABLE',
                'backup_time': latest_backup.timestamp.isoformat(),
                'action': 'PROCEED_WITH_RECOVERY'
            })
        else:
            backup_status.append({
                'system': system.hostname,
                'status': 'BACKUP_POTENTIALLY_ENCRYPTED',
                'action': 'MANUAL_VERIFICATION_REQUIRED'
            })

    return backup_status

Step 5 — Notify Stakeholders

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def notify_stakeholders(incident, scope, family_info, backup_status):
    severity = 'P1' if scope['hosts_affected'] >= 4 else 'P2'

    # SOC channel
    teams_post_to_channel(
        channel='#soc-alerts',
        title=f"[{severity}] RANSOMWARE INCIDENT — {incident.id}",
        body=f"""
**Family:** {family_info['family']}
**Hosts isolated:** {len(scope['isolated_hosts'])}
**Backup status:** {sum(1 for b in backup_status if b['status'] == 'CLEAN_BACKUP_AVAILABLE')} clean / {len(backup_status)} total
**Extension:** {family_info['extension']}
        """
    )

    # For P1, also notify CISO and IT manager via email
    if severity == 'P1':
        send_email(
            to=['ciso@company.ae', 'it-manager@company.ae'],
            subject=f"[URGENT] Active Ransomware Incident — {scope['hosts_affected']} systems affected",
            body=build_executive_summary(incident, scope, family_info)
        )

    # Create P1 incident ticket
    ticket = servicenow_create_incident(
        priority=1,
        category='Ransomware',
        short_desc=f"Ransomware: {family_info['family']}{scope['hosts_affected']} hosts",
        description=build_full_report(incident, scope, family_info, backup_status)
    )

    return ticket

Step 6 — Block Known IOCs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def block_ransomware_iocs(family_info, firewall_client, proxy_client):
    """
    Pull known C2 IPs and domains for the identified family from MISP
    and block them at the perimeter immediately.
    """
    if family_info['family'] == 'Unknown':
        return []

    iocs = misp_search_by_tag(f'ransomware:{family_info["family"].lower()}')
    blocked = []

    for ioc in iocs:
        if ioc['type'] == 'ip-dst':
            firewall_client.block_ip(ioc['value'], comment=f"Ransomware C2 — {family_info['family']}")
            blocked.append(ioc['value'])
        elif ioc['type'] == 'domain':
            proxy_client.block_domain(ioc['value'])
            blocked.append(ioc['value'])

    return blocked

Recovery Checklist (Post-Containment)

Once the incident is contained, the playbook generates a structured recovery checklist assigned to the IT team:

1
2
3
4
5
6
7
8
9
□ Verify all affected hosts are isolated from the network
□ Confirm backup integrity for each affected system
□ Rebuild affected systems from clean image (do not decrypt in place)
□ Restore data from last clean backup
□ Reset credentials for all accounts active on affected systems
□ Rotate service account passwords for systems in blast radius
□ Patch the initial access vector before reconnecting to network
□ Enable additional monitoring on rebuilt systems for 30 days
□ Conduct post-incident review within 72 hours

ATT&CK Coverage

Tactic Technique Playbook Action
Execution T1059 — Command & Scripting Block process execution, alert on shadow copy commands
Defense Evasion T1490 — Inhibit System Recovery Trigger immediate isolation
Impact T1486 — Data Encrypted for Impact Core detection trigger
Lateral Movement T1021 — Remote Services Scope assessment, segment network

Contact me at contact@malsayegh.ae to discuss ransomware preparedness or playbook adaptation.

comments powered by Disqus
All rights Reserved for malsayegh.ae
Built with Hugo
Theme Stack designed by Jimmy