Skip to main content

 

Splunk Lantern

Scoping a password spray breach with federated search across Amazon S3 and Snowflake

This article is one of three investigation examples in a series. See Investigating security incidents across Amazon S3 and Snowflake with federated search for the reference architecture, dataset list, and prerequisites used in this example.

A burst of SSH authentication failures arrives from a single external address. The first priority is to determine whether the activity is a spray, whether any account accepted a password, and what data the successful identity could access.

For related research, see the Detect Password Spray Attempts and the Compromised User Account analytic stories.

How federated search in Splunk Cloud Platform helps with this use case

Step 1: What did the source do before it started guessing?

Use Amazon S3 as the source.

FROM s3_vpc_flowlogs WHERE srcaddr="203.0.113.88" AND earliest=-90d
| stats count() AS flows, dc(dstaddr) AS targets BY action, dstport
| sort -flows

The source generated 48 rejected flows across 44 internal addresses on ports 22, 445, 1433, 3306, 3389, and 5432. That's an administrative-port sweep. It then created one accepted port-22 flow that remained open for 28 minutes.

clipboard_73c07542-3907-4ea0-8dd5-2282ce4eb011.png

The firewall history shows reconnaissance and the eventual path in before the authentication logs establish which account was accepted.

You should treat the source address as an incident pivot across the entire environment. Preserve the first-seen, accepted-flow, and authentication timestamps.

Step 2: How many accounts did it try, and did any of them work?

Use an index in Splunk Cloud Platform as the source.

index=linux_secure sourcetype=linux_secure "203.0.113.88"
| rex field=_raw "(?<outcome>Failed|Accepted) password for (?<acct>[^ ]+) from"
| stats count() AS attempts BY outcome, acct
| sort outcome, -attempts

The source tried 16 accounts. There were 48 failures spread evenly across those accounts and one accepted login for hchen. The broad, flat distribution is characteristic of password spraying rather than a brute-force attack against one user.

clipboard_7239a197-5b84-4af4-a504-7fcc81d5993a.png

You should disable or step-up authenticate hchen, invalidate active sessions, rotate credentials, and use the source address to search for other successful access.

Step 3: Who were they aiming at?

Use Snowflake and an index in Splunk Cloud Platform as the sources.

index=linux_secure sourcetype=linux_secure "203.0.113.88" "Failed password"
| rex field=_raw "Failed password for (?<acct>[^ ]+) from"
| stats count() AS attempts BY acct
| join type=inner left=L right=R where L.acct=R.OS_ACCOUNT
  [FROM sf_employee_status | fields OS_ACCOUNT, FULL_NAME, DEPARTMENT, EMPLOYMENT_STATUS, CLEARANCE_LEVEL]
| eval account='L.acct', attempts='L.attempts', who='R.FULL_NAME',
  dept='R.DEPARTMENT', status='R.EMPLOYMENT_STATUS', clearance='R.CLEARANCE_LEVEL'
| fields account, who, dept, status, clearance, attempts
| sort status, account

All 17 identities resolve to real employees, which indicates that the spray list was targeted rather than a generic dictionary. The set includes 11 active, four resigned, and two terminated employees. Six accounts belonging to people who had already left were still receiving authentication attempts, which is a separate identity-lifecycle finding.

When the result is sorted by attempts, 16 accounts were tried three times each. hchen was tried twice because the third attempt succeeded. The account belongs to a senior engineer in finance with high clearance; it's the only high-clearance account in the set.

clipboard_2df7fdb5-3d25-42da-ac46-378bf261de5c.png

Snowflake adds the identity and employment context needed to prioritize containment. It also reveals dormant or stale accounts that the attack exposed, but didn't necessarily create.

You should separate the response into two tracks: contain the successful high-clearance account immediately, and open an identity-governance remediation for resigned or terminated accounts that remain reachable.

Step 4: What did they take?

Use Amazon S3 and Snowflake as the sources.

FROM s3_cloudtrail WHERE userIdentity="hchen" AND eventName="GetObject" AND sourceIPAddress="203.0.113.88" AND earliest=-90d
| stats count() AS gets BY objectKey, bucketName
| join type=inner left=L right=R where L.objectKey=R.OBJECT_KEY
  [FROM sf_export_manifest | stats dc(C_CUSTKEY) AS accounts BY OBJECT_KEY]
| eval object='L.objectKey', bucket='L.bucketName', gets='L.gets', accounts='R.accounts'
| fields object, bucket, gets, accounts
| sort object

Five objects were accessed in seven GetObject calls. Each object contains 3,750 customer records.

clipboard_12ecf1d0-6673-4278-8a0f-f393132fb0df.png

The sf_export_manifest subsearch aggregates by object before the join, so Snowflake returns 12 rows rather than tens of thousands of underlying customer-to-object mappings. Subsearches can cap at 10,000 results and 60 seconds; aggregating close to the source helps keep the federated search focused.

You should preserve the five object keys, determine whether the access was read-only or followed by copy or sharing activity, and use the object list as the scope for business-impact analysis.

Step 5: How big is the breach?

Use Snowflake as the source.

FROM sf_customer AS c
JOIN sf_export_manifest AS m ON c.C_CUSTKEY = m.C_CUSTKEY
LEFT JOIN sf_customer_revenue AS r ON c.C_CUSTKEY = r.C_CUSTKEY
WHERE m.OBJECT_KEY IN ("customer_export/2026-07-21/part-0000.parquet",
  "customer_export/2026-07-21/part-0006.parquet",
  "customer_export/2026-07-22/part-0004.parquet",
  "customer_export/2026-07-23/part-0002.parquet",
  "customer_export/2026-07-23/part-0011.parquet")
SELECT dc(c.C_CUSTKEY) AS accounts, dc(m.OBJECT_KEY) AS objects, dc(c.COUNTRY) AS countries,
  dc(c.C_MKTSEGMENT) AS segments, sum(c.C_ACCTBAL) AS balance, sum(r.ANNUAL_REVENUE) AS revenue

One aggregated row reports 18,750 customer accounts across five objects and 25 countries and five market segments. The affected records represent approximately $83,630,025 in account balances and $3,385,933,072 in annual revenue.

clipboard_e3b54f30-ffd3-4e08-a927-20ad03cd8c8f.png

The SOC can now give legal, privacy, and executive stakeholders a quantified scope quickly, without pulling 18,750 customer records into Splunk Cloud Platform.

You should use this result to activate the breach-response process, validate the figures with the data owner, identify affected data elements, and preserve the exact query and object list as evidence.

Step 6: Which regulators are involved?

Use Snowflake as the source.

FROM sf_customer AS c
JOIN sf_export_manifest AS m ON c.C_CUSTKEY = m.C_CUSTKEY
WHERE m.OBJECT_KEY IN ("customer_export/2026-07-21/part-0000.parquet",
  "customer_export/2026-07-21/part-0006.parquet",
  "customer_export/2026-07-22/part-0004.parquet",
  "customer_export/2026-07-23/part-0002.parquet",
  "customer_export/2026-07-23/part-0011.parquet")
AND c.COUNTRY IN ("FRANCE", "GERMANY", "ROMANIA")
GROUP BY c.COUNTRY
SELECT dc(c.C_CUSTKEY) AS accounts, sum(c.C_ACCTBAL) AS balance
ORDER BY accounts DESC

France has 771 affected accounts, Romania 741, and Germany 731. Together, the three countries represent 2,243 accounts and approximately $10.0M in balances across three supervisory authorities on a single 72-hour clock under GDPR Article 33.

clipboard_9125c10a-3101-4957-b4c6-2f685b162636.png

A security event becomes an actionable breach report. The result is small enough to hand to the privacy and legal teams while retaining Snowflake as the authoritative source for the underlying customer data.

You should notify the privacy and legal stakeholders, validate the regulatory interpretation for the customer's circumstances, and begin the notification decision process using the country-level result and the evidence trail from the preceding searches.

Next steps

Continue with the next investigation example in this series: Tracing unowned cloud infrastructure with federated search across Amazon S3 and Snowflake.

  • Written by Nithin Krishna Reghunathan (Staff Engineering Product Manager) and Nikita Voitov (Partner Solutions Engineer)
  • Splunk, A Cisco Company