CyberNugget

L64 · Anatomy of a ransomware attack

Module 9: Detection and Incident Response · ~20 min · Lesson 64 of 71

🎯 What you'll learn

  • The stages of a modern ransomware intrusion, and why encryption is the last one
  • Why "double extortion" means good backups alone don't end the crisis
  • What ransomware looks like in AWS: no malware, just your own encryption and delete APIs
  • What makes a backup survive an attacker with admin rights: immutable, isolated and tested

🔥 Why this matters

On 8 November 2023, LockBit ransomware hit ICBC Financial Services, the US broker-dealer arm of the world's largest bank. It couldn't settle US Treasury trades through its normal systems, so, as Bloomberg reported, settlement details went to counterparties by messenger on a USB stick. Reports said the unit briefly owed BNY Mellon about $9 billion, far more than its own capital, until its parent injected funds. One firm's IT outage briefly moved a corner of the Treasury market.

1. Ransomware is the last step, not the first

Modern ransomware isn't one click turning every screen red. It's a hands-on intrusion that can last days or weeks; encryption is the finale.

Most attacks run as ransomware-as-a-service (RaaS): one group writes the malware and runs the leak site, affiliates carry out the intrusions for a share of the ransom, and initial access brokers sell ways in. LockBit and DarkSide both worked this way.

 1 INITIAL ACCESS     phishing, VPN or RDP without MFA,
   │                  unpatched edge device, stolen creds
   ▼
 2 DISCOVERY          who am I? what's here? where are
   │                  the backups and the crown jewels?
   ▼
 3 PRIV ESCALATION    dump credentials, become domain
   │                  admin or AWS admin
   ▼
 4 LATERAL MOVEMENT   RDP, PsExec, SSH, AssumeRole,
   │                  kubectl into other namespaces
   ▼
 5 EXFILTRATION       copy data out (rclone, S3 sync)
   │
   ▼
 6 INHIBIT RECOVERY   delete backups, snapshots,
   │                  shadow copies; disable logging
   ▼
 7 ENCRYPT            all at once, often at night or
   │                  on a holiday weekend
   ▼
 8 EXTORT             ransom note, leak-site countdown

In MITRE ATT&CK terms (L61), step 6 is T1490 Inhibit System Recovery and step 7 is T1486 Data Encrypted for Impact. Every step before 7 is a chance to detect them (L62). Vendor reports of how long the middle takes range from under a day to over a week, and change yearly.

2. Getting in

Four doors account for most initial access:

  • Remote access without strong MFA: VPNs and remote desktop gateways. Colonial Pipeline (May
    1. began with a legacy VPN account, unused but still active, with no MFA, as its CEO told the US Senate. Responders said the password may have come from a leak.
  • Unpatched edge devices, which face the internet by design. ICBC's entry was widely reported as Citrix Bleed (CVE-2023-4966), which leaked session tokens from NetScaler devices; ICBC hasn't published a root cause.
  • Exposed RDP with weak or reused passwords.
  • Stolen credentials and phishing. Infostealer malware harvests saved passwords and session cookies (L22), which brokers sell. Phishing (L66) delivers the same.

The cloud has its own front door: a leaked access key (L52) or a stolen CI token (L57).

At Colonial the attackers stole about 100 GB and encrypted IT systems only, yet the company shut its 5,500-mile pipeline (around 45% of the East Coast's fuel) for about five days as a precaution. It paid 75 bitcoin (about $4.4 million); the US Justice Department later recovered 63.7.

3. Inside: discovery, escalation, lateral movement

Once in, attackers live off the land: they use your admins' own tools, so nothing looks like malware. On Windows networks that means Active Directory queries, credential dumping and RDP. In AWS it's the enumeration L52 described: GetCallerIdentity, List*, Describe*, then AssumeRole into anything the trust policies allow (L46).

Two targets get special attention: admin credentials, because encrypting thousands of machines at once needs admin rights, and backups, because a victim who can restore doesn't pay. Attackers hunt for backup consoles early and destroy backups before encrypting anything.

4. Double extortion: steal, then encrypt

Around 2019 the Maze group popularized double extortion: copy the data out before encrypting, then threaten to publish it on a leak site if the victim restores from backup instead of paying.

            ┌── lever 1: ENCRYPTION ──▶ "pay for the key"
 attacker ──┤                           (backups defeat this)
            └── lever 2: STOLEN DATA ─▶ "pay or we publish"
                                        (backups do nothing)

Some add more pressure (a DDoS, emailing your customers). Others skip encryption entirely: Cl0p's 2023 MOVEit campaign was data theft and extortion alone.

So ransomware is two incidents at once: an availability incident (L01) that backups fix, and a confidentiality incident, a breach with notification duties (L68), that no backup undoes.

5. Ransomware in the cloud

In AWS, an attacker with enough permissions needs no malware. Your own APIs do the work:

  • Re-encrypt S3 objects with a key you don't hold. In January 2025, Halcyon reported a group it called Codefinger using stolen AWS keys to rewrite S3 objects with SSE-C, server-side encryption with a customer-provided key. AWS doesn't store SSE-C keys, so only the attacker could decrypt. They also set lifecycle rules to delete the data in seven days.
  • The same with a foreign KMS key. Rewrite objects with SSE-KMS using a key in the attacker's own account (L19), then cut off your access to it.
  • Schedule deletion of your KMS keys. Everything encrypted under them, including backups, becomes unreadable once the 7 to 30 day waiting period ends.
  • Destroy the way back. Delete EBS snapshots, AWS Backup recovery points and old S3 object versions; drop MongoDB collections and leave a note (L53's 2017 ransom wave).

Same pattern as on-premises: steal, destroy recovery, lock what's left.

6. Backups that survive

A backup survives only if an admin in your production account can't delete it. The modern rule of thumb is 3-2-1-1-0:

Digit Means In AWS terms
3 Three copies of the data Production plus two backups
2 On two different media or services e.g. EBS snapshots and AWS Backup
1 One copy off-site Another region
1 One copy offline or immutable Vault Lock or Object Lock in compliance mode
0 Zero errors when you test a restore Scheduled restore tests
 PROD ACCOUNT (attacker has admin)    BACKUP ACCOUNT, own OU
 ┌────────────────────────────┐       ┌──────────────────────┐
 │ MongoDB, EBS, S3           │       │ vault: locked,       │
 │   │ backup plan            │ copy  │ compliance mode,     │
 │   ▼                        │──────▶│ 35-day minimum       │
 │ local vault (fast restore) │       │ own KMS key          │
 │ attacker CAN delete these  │       │ different admins     │
 └────────────────────────────┘       │ prod roles: no       │
                                      │ access at all        │
                                      └──────────────────────┘
  • Immutable. AWS Backup Vault Lock in compliance mode locks after a grace period of at least three days; then nobody, not even the root user, can delete recovery points early or remove the lock. Governance mode can be lifted by users with special permissions. S3 Object Lock does the same for objects.
  • Isolated. Copy backups to a separate account and region, encrypted with a KMS key that lives there. A backup under a key in the compromised account dies with that key. (AWS's logically air-gapped vaults, added in 2024, are another option; check what they support today.)
  • Tested. A backup you've never restored is a hope. AWS Backup's restore testing restores on a schedule and reports how long it took: your real recovery time.

🧪 Worked example: an S3 ransom, read from CloudTrail

A leaked key for svc-report-export (L52) has s3:* on a statements bucket and, far too broadly (L46), backup:*. Simplified events, not raw JSON:

UTC    caller             event                     result
02:03  svc-report-export  GetCallerIdentity         ok
02:05  svc-report-export  ListBuckets               ok
02:07  svc-report-export  GetBucketVersioning       ok
         bucket=example-statements  status=Enabled
02:09  svc-report-export  PutBucketLifecycle-       ok
         Configuration    rule: expire noncurrent versions, 1 day
02:11  svc-report-export  CopyObject  x 48,210      ok
 -02:40  SSE-C (AES256), same object keys, overwritten
02:41  svc-report-export  PutObject README-RESTORE  ok
02:44  svc-report-export  DeleteRecoveryPoint x 31  ok, LOCAL vault

What each line tells you:

  • 02:07 to 02:09. Versioning would keep old versions, so the attacker set a rule to expire them after a day. Only data-event logging (L52) makes 02:11 visible.
  • 02:11. Copying each object onto itself with SSE-C is the encryption. The originals survive as old versions, for one more day.
  • 02:44. The local vault wasn't locked, so its recovery points are gone. The backup account's copies never appear here: prod credentials have no access to it.

Recovery: remove the lifecycle rule within the day and restore the old versions, or restore from the backup account. An SCP (deep dive 1) would have stopped 02:09 and 02:11. And with GetObject on the bucket, assume the statements were read: it's a data breach too.

🛠 Try it (optional, ~5 min)

A thought exercise for one data store you own (no real identifiers in your notes):

  1. Where is the newest copy that an admin in the production account cannot delete?
  2. Which KMS key encrypts that copy, and which account is the key in?
  3. When was it last restored, and how long did the restore take?
  4. If the attacker had been inside for ten days, is there a copy older than that?

If question 1 has no answer, that's your most important finding this week.

🧠 Key takeaways

  • Ransomware is the end of an intrusion; initial access, discovery and backup deletion come first.
  • Double extortion means backups fix availability, not the breach of confidentiality.
  • In the cloud the "malware" is your own APIs: SSE-C, foreign or deleted KMS keys, lifecycle rules.
  • Surviving backups are immutable (compliance-mode locks), isolated (another account and key) and tested.
  • MFA on remote access and fast edge-device patching close the commonest doors.

📖 Words to know

Term Meaning
Ransomware-as-a-service Developers supply malware and leak sites; affiliates break in and share the ransom
Living off the land Attacking with the victim's own admin tools so nothing looks like malware
Double extortion Stealing data before encrypting it, then threatening to publish it
SSE-C S3 server-side encryption with a key the caller supplies and AWS doesn't keep
Vault Lock AWS Backup setting that stops recovery points being deleted early; compliance mode is unchangeable
3-2-1-1-0 Three copies, two media, one off-site, one immutable, zero restore errors

⏭ Next time

L65 is a tabletop exercise: a breach unfolds hour by hour, and you make the calls at each stage.

Deep dive 1

Blocking cloud-native ransomware with SCPs and alarms

The cloud attacks in section 5 all use legitimate API calls. That's bad news for malware scanners but good news for you: a call you can name is a call you can deny. Organization policies (L27's deep dive) apply even to an attacker holding admin credentials in a member account.

Which calls to fence off

Attack step API call Guardrail
Re-encrypt with SSE-C PutObject, CopyObject (authorized as s3:PutObject) with SSE-C headers Deny when the SSE-C header is present
Re-encrypt with a foreign key s3:PutObject naming a KMS key outside your accounts Deny unless the key ARN is yours
Expire old versions s3:PutLifecycleConfiguration Only the IaC deploy role may change it
Kill your keys kms:ScheduleKeyDeletion, kms:DisableKey, kms:PutKeyPolicy Only a break-glass role; alarm on every call
Delete backups backup:DeleteRecoveryPoint, backup:DeleteBackupVault Vault Lock, plus deny outside the backup admin role

Worked example: an SCP for the workload OU

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "NoSSEC",
      "Effect": "Deny",
      "Action": "s3:PutObject",
      "Resource": "*",
      "Condition": {"Null": {
        "s3:x-amz-server-side-encryption-customer-algorithm":
          "false"}}
    },
    {
      "Sid": "OnlyOurKmsKeys",
      "Effect": "Deny",
      "Action": "s3:PutObject",
      "Resource": "*",
      "Condition": {
        "Null": {"s3:x-amz-server-side-encryption-aws-kms-key-id":
          "false"},
        "StringNotLike": {
          "s3:x-amz-server-side-encryption-aws-kms-key-id":
          "arn:aws:kms:*:111122223333:key/*"}}
    },
    {
      "Sid": "ProtectRecovery",
      "Effect": "Deny",
      "Action": ["kms:ScheduleKeyDeletion", "kms:DisableKey",
                 "s3:PutLifecycleConfiguration",
                 "backup:DeleteRecoveryPoint"],
      "Resource": "*",
      "Condition": {"ArnNotLike": {"aws:PrincipalArn": [
        "arn:aws:iam::*:role/example-breakglass",
        "arn:aws:iam::*:role/example-iac-deploy"]}}
    }
  ]
}

Read it carefully before copying the idea:

  • "Null": {...: "false"} means "the header is present", so any request using SSE-C is denied.
  • The second statement needs both conditions: the header is present and isn't one of your keys. A negated operator such as StringNotLike is true when the key is missing, so on its own it would deny every upload that relies on bucket default encryption. The condition compares against the key's ARN. Test how your clients specify keys (ID, alias or ARN) before enforcing, or you'll block your own uploads. Here every key is assumed to live in one account; with several, list them all.
  • An exception by role name is only as strong as control over that role: protect who can assume example-breakglass and alert when anyone does.
  • SCPs don't apply to the management account, and they only limit principals in your organization. A resource control policy (RCP) puts a similar deny on the bucket side, whoever the caller is. Rewind and others have described RCPs used to block SSE-C.

As always with org-wide denies, roll out carefully (L51's deep dive): check CloudTrail first for any legitimate use of SSE-C or lifecycle changes.

Alarms for what you allow

Some calls must stay possible, so watch them. An EventBridge rule on CloudTrail events can page the on-call for ScheduleKeyDeletion, PutBucketLifecycleConfiguration on data buckets, or a burst of CopyObject with SSE-C. KMS key deletion has a waiting period of 7 to 30 days (30 by default), and CancelKeyDeletion undoes it during that time; set the longest waiting period you can live with.

🧠 Extra takeaways

  • Cloud ransomware uses named API calls, so deny the dangerous ones at the organization level.
  • Block SSE-C unless you use it, and allow SSE-KMS only with your own keys.
  • Restrict key deletion, lifecycle changes and recovery-point deletion to a guarded break-glass role.
  • Alarm on the calls you can't deny; a 30-day key deletion window gives you time to cancel.
Deep dive 2

Recovering clean: choosing the restore point and rebuilding

Having a surviving backup is half the battle. The other half is restoring without restoring the attacker, fast enough to matter. Colonial's experience is the warning: reports say the decryptor it paid for was so slow that the company leaned on its own backups anyway.

The restore point problem

The attacker was inside for days before encrypting. Backups taken during that time may contain their web shell, a new admin user, or a changed config.

 day:  1    3    5    7    9    11   13
       │    │    │    │    │    │    │
 backups ●    ●    ●    ●    ●    ●    ●
            ▲              ▲           ▲
            │              │           └ encryption (day 13)
            │              └ attacker created admin user
            └ initial access (day 3, found later in VPN logs)

 restore day 1 data: clean, but lose 12 days of changes
 restore day 11 data: recent, but carries the admin user

The usual answer combines the two:

  1. Rebuild infrastructure from code, not from backups. Clusters, nodes and images come from your IaC and your registry (signed images, L49), not from a snapshot of a possibly-compromised server.
  2. Restore data from the newest copy, then clean it. Data (Mongo collections, S3 objects) is restored from a recent point and checked against what the investigation found: remove the users, keys, scheduled jobs or records the attacker created.
  3. Replay what's missing from upstream sources where you can: trade feeds, partner files or event logs for the gap.

Your retention period must be longer than a realistic dwell time. Seven days of backups is not enough if attackers are often inside for longer than that.

Restore into a clean room

Don't restore straight into the environment you're still investigating. Recover into an isolated clean-room account: new credentials, no trust relationships with the compromised accounts, network access only to what the recovery needs. Rotate every credential (L63's deep dive) before the restored systems talk to anything else. Otherwise the attacker's stolen keys work on your freshly restored systems.

Worked example: a restore drill for one Mongo-backed service

A quarterly drill, recorded the same way every time:

Drill 2026-Q4  service: quotes-api (fake)  data: 410 GB
Restore point:   2026-10-31T02:00Z, backup account copy
Target:          clean-room account, new cluster
Steps timed:
  restore snapshot to new cluster ........ 1h 52m
  rebuild app from IaC + signed image .... 0h 25m
  rotate creds, update Secrets Manager ... 0h 18m
  smoke tests + record count check ....... 0h 31m
Total (real RTO) ......................... 3h 06m
Target RTO: 4h  ✔     Data loss (RPO): 24h  ✘ target 4h
Action: add 4-hourly snapshots; re-test in Q1

The drill found the gap that matters. The restore was fast enough, but the restore points were too far apart for the business's tolerance for lost data (L01's deep dive on RTO and RPO). That's exactly what you want to learn in a drill and not on the day.

A note on paying

Paying doesn't skip any of this: you still investigate, rebuild, rotate and notify. The stolen data isn't returned, and decryptors are often slow or buggy. There's also legal risk: the US Treasury's OFAC has warned that paying sanctioned groups can violate sanctions, and NYDFS requires covered firms to report a ransom payment within 24 hours (L68). That decision belongs to executives, legal and the incident commander, with a plan prepared in advance.

🧠 Extra takeaways

  • Rebuild infrastructure from code; restore only data from backups, then clean it.
  • Keep backups longer than a realistic dwell time, so a pre-intrusion copy exists.
  • Recover into an isolated clean room and rotate credentials before reconnecting anything.
  • Time real restore drills; the measured RTO and RPO are the ones that count.

The quiz for this lesson and the Tests section need JavaScript.