Skip to content

Commit

Permalink
Snowflake Data Exfiltration CR (#1257)
Browse files Browse the repository at this point in the history
* Update Action versions; use SHAs (#1231)

* Update Action versions; use SHAs

* Add dependabot.yml to keep Actions updated

* Update PAT to 0.49.0

* scheduled rules and correlation rule for
snowflake data exfiltration

* transition names

* updates to comply with CR style guide

* cleanup and pack update

* MITRE ATT&CK tags

---------

Co-authored-by: Evan Gibler <[email protected]>
Co-authored-by: Ben Airey <[email protected]>
  • Loading branch information
3 people authored Jul 9, 2024
1 parent e68dabf commit aea5a39
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:

permissions:
contents: read
contents: read

jobs:
release:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
- main

permissions:
contents: read
contents: read

jobs:
upload:
Expand Down
70 changes: 70 additions & 0 deletions correlation_rules/snowflake_data_exfiltration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
AnalysisType: correlation_rule
RuleID: "Snowflake.Data.Exfiltration"
DisplayName: "Snowflake Data Exfiltration"
Enabled: true
Severity: Critical
Description: In April 2024, Mandiant received threat intelligence on database records that were subsequently determined to have originated from a victim’s Snowflake instance. Mandiant notified the victim, who then engaged Mandiant to investigate suspected data theft involving their Snowflake instance. During this investigation, Mandiant determined that the organization’s Snowflake instance had been compromised by a threat actor using credentials previously stolen via infostealer malware. The threat actor used these stolen credentials to access the customer’s Snowflake instance and ultimately exfiltrate valuable data. At the time of the compromise, the account did not have multi-factor authentication (MFA) enabled.
Reference: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Reports:
MITRE ATT&CK:
- TA0010:T1041 # Exfiltration Over C2 Channel
Detection:
- Sequence:
- ID: SnowflakeTempStageCreated
RuleID: Snowflake.TempStageCreated
- ID: SnowflakeCopyIntoStage
RuleID: Snowflake.CopyIntoStage
- ID: SnowflakeFileDownloaded
RuleID: Snowflake.FileDownloaded
Transitions:
- ID: Match SnowflakeTempStageCreated and SnowflakeCopyIntoStage on stage
From: SnowflakeTempStageCreated
To: SnowflakeCopyIntoStage
Match:
- On: stage
- ID: Match SnowflakeCopyIntoStage and SnowflakeFileDownloaded on path
From: SnowflakeCopyIntoStage
To: SnowflakeFileDownloaded
Match:
- On: stage
Schedule:
RateMinutes: 720
TimeoutMinutes: 2
LookbackWindowMinutes: 1440
Tests:
- Name: Data Exfiltration
ExpectedResult: true
RuleOutputs:
- ID: SnowflakeTempStageCreated
Matches:
stage:
LOGS.PUBLIC.data_exfil:
- "2006-01-02T15:04:05Z"
- "2006-01-02T15:04:06Z"
- ID: SnowflakeCopyIntoStage
Matches:
stage:
LOGS.PUBLIC.data_exfil:
- "2006-01-02T15:04:05Z"
- "2006-01-02T15:04:06Z"
- ID: SnowflakeFileDownloaded
Matches:
stage:
LOGS.PUBLIC.data_exfil:
- "2006-01-02T15:04:05Z"
- "2006-01-02T15:04:06Z"
- Name: Data Staged but not Downloaded
ExpectedResult: false
RuleOutputs:
- ID: SnowflakeTempStageCreated
Matches:
stage:
LOGS.PUBLIC.data_exfil:
- "2006-01-02T15:04:05Z"
- "2006-01-02T15:04:06Z"
- ID: SnowflakeCopyIntoStage
Matches:
stage:
LOGS.PUBLIC.data_exfil:
- "2006-01-02T15:04:05Z"
- "2006-01-02T15:04:06Z"
7 changes: 7 additions & 0 deletions packs/snowflake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ PackDefinition:
- Query.Snowflake.BruteForceByIp
- Query.Snowflake.BruteForceByUsername
- Query.Snowflake.ClientIp
- Query.Snowflake.CopyIntoStage
- Query.Snowflake.External.Shares
- Query.Snowflake.FileDownloaded
- Query.Snowflake.KeyUserPasswordLogin
- Query.Snowflake.Multiple.Logins.Followed.By.Success
- Query.Snowflake.SuspectedUserAccess
- Query.Snowflake.TempStageCreated
- Query.Snowflake.UserCreated
- Query.Snowflake.UserEnabled
# Rules
Expand All @@ -25,9 +28,13 @@ PackDefinition:
- Snowflake.BruteForceByUsername
- Snowflake.Client.IP
- Snowflake.Configuration.Drift
- Snowflake.CopyIntoStage
- Snowflake.Data.Exfiltration
- Snowflake.External.Shares
- Snowflake.FileDownloaded
- Snowflake.KeyUserPasswordLogin
- Snowflake.Multiple.Failed.Logins.Followed.By.Success
- Snowflake.TempStageCreated
- Snowflake.User.Access
- Snowflake.UserCreated
- Snowflake.UserEnabled
Expand Down
2 changes: 2 additions & 0 deletions queries/snowflake_queries/scheduled_rule_default_snowflake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def rule(_):
return True
26 changes: 26 additions & 0 deletions queries/snowflake_queries/snowflake_file_downloaded_query.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
AnalysisType: scheduled_query
QueryName: "Query.Snowflake.FileDownloaded"
Enabled: true
Description: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Query: >
SELECT
user_name,
role_name,
start_time AS p_event_time,
query_type,
execution_status,
regexp_substr(query_text, 'GET\\s+(\\$\\$|\\\')?@([a-zA-Z0-9_\\.]+)', 1, 1, 'i', 2) as stage,
regexp_substr(query_text, 'GET\\s+(\\$\\$|\\\')?@([a-zA-Z0-9_\\./]+)(\\$\\$|\\\')?\\s', 1, 1, 'i', 2) as path,
query_text
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_type = 'GET_FILES'
AND path IS NOT NULL
AND p_occurs_since('1 day')
AND execution_status = 'SUCCESS'
LIMIT 100
Schedule:
RateMinutes: 1440
TimeoutMinutes: 1
Tags:
- data exfil
29 changes: 29 additions & 0 deletions queries/snowflake_queries/snowflake_file_downloaded_signal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
AnalysisType: scheduled_rule
Filename: scheduled_rule_default_snowflake.py
RuleID: "Snowflake.FileDownloaded"
Description: >
A file was downloaded from a stage
DisplayName: "Snowflake File Downloaded"
Enabled: true
CreateAlert: false
Reference: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Reports:
MITRE ATT&CK:
- TA0010:T1041 # Exfiltration Over C2 Channel
ScheduledQueries:
- Query.Snowflake.FileDownloaded
Severity: Info
Tests:
- Name: Value Returned By Query
ExpectedResult: true
Log:
{
"execution_status": "SUCCESS",
"path": "LOGS.PUBLIC.data_exfil/DATA.csv",
"query_text": "GET '@LOGS.PUBLIC.data_exfil/DATA.csv' 'file:///Users/evil.genius/Documents'",
"query_type": "GET_FILES",
"role_name": "SYSADMIN",
"stage": "LOGS.PUBLIC.data_exfil",
"start_time": "2024-06-10 19:37:15.698Z",
"user_name": "ADMIN"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
AnalysisType: scheduled_query
QueryName: "Query.Snowflake.CopyIntoStage"
Enabled: true
Description: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Query: >
SELECT
user_name,
role_name,
start_time AS p_event_time,
query_type,
execution_status,
regexp_substr(query_text, 'COPY\\s+INTO\\s+(\\$\\$|\\\')?@([a-zA-Z0-9_\\.]+)', 1, 1, 'i', 2) as stage,
regexp_substr(query_text, 'COPY\\s+INTO\\s+(\\$\\$|\\\')?@([a-zA-Z0-9_\\./]+)(\\$\\$|\\\')?\\s+FROM', 1, 1, 'i', 2) as path,
query_text
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_type = 'UNLOAD'
AND stage IS NOT NULL
AND p_occurs_since('1 day')
AND execution_status = 'SUCCESS'
LIMIT 100
Schedule:
RateMinutes: 1440
TimeoutMinutes: 1
Tags:
- data exfil
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
AnalysisType: scheduled_rule
Filename: scheduled_rule_default_snowflake.py
RuleID: "Snowflake.CopyIntoStage"
Description: >
A table was copied into a stage
DisplayName: "Snowflake Table Copied Into Stage"
Enabled: true
CreateAlert: false
Reference: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Reports:
MITRE ATT&CK:
- TA0010:T1041 # Exfiltration Over C2 Channel
ScheduledQueries:
- Query.Snowflake.CopyIntoStage
Severity: Info
Tests:
- Name: Value Returned By Query
ExpectedResult: true
Log:
{
"execution_status": "SUCCESS",
"path": "LOGS.PUBLIC.data_exfil/DATA.csv",
"query_text": "COPY INTO @LOGS.PUBLIC.data_exfil/DATA.csv\nFROM (SELECT * FROM PANTHER_LOGS.PUBLIC.GITLAB_API_VARIANT LIMIT 100)\nFILE_FORMAT = ( \n TYPE='CSV' \n COMPRESSION=GZIP\n FIELD_DELIMITER=',' \n ESCAPE=NONE \n ESCAPE_UNENCLOSED_FIELD=NONE \n date_format='AUTO' \n time_format='AUTO' \n timestamp_format='AUTO'\n binary_format='UTF-8' \n field_optionally_enclosed_by='\"' \n null_if='' \n EMPTY_FIELD_AS_NULL = FALSE \n) \noverwrite=TRUE \nsingle=FALSE \nmax_file_size=5368709120 \nheader=TRUE",
"query_type": "UNLOAD",
"role_name": "SYSADMIN",
"stage": "LOGS.PUBLIC.data_exfil",
"start_time": "2024-06-10 19:15:37.445Z",
"user_name": "ADMIN"
}
25 changes: 25 additions & 0 deletions queries/snowflake_queries/snowflake_temp_stage_created_query.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
AnalysisType: scheduled_query
QueryName: "Query.Snowflake.TempStageCreated"
Enabled: true
Description: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Query: >
SELECT
user_name,
role_name,
start_time AS p_event_time,
query_type,
execution_status,
regexp_substr(query_text, 'CREATE\\s+(OR\\s+REPLACE\\s+)?(TEMPORARY\\s+|TEMP\\s+)STAGE\\s+(IF\\s+NOT\\s+EXISTS\\s+)?([a-zA-Z0-9_\\.]+)', 1, 1, 'i', 4) as stage,
query_text
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_type = 'CREATE'
AND stage IS NOT NULL
AND p_occurs_since('1 day')
AND execution_status = 'SUCCESS'
LIMIT 100
Schedule:
RateMinutes: 1440
TimeoutMinutes: 1
Tags:
- data exfil
28 changes: 28 additions & 0 deletions queries/snowflake_queries/snowflake_temp_stage_created_signal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
AnalysisType: scheduled_rule
Filename: scheduled_rule_default_snowflake.py
RuleID: "Snowflake.TempStageCreated"
Description: >
A temporary stage was created
DisplayName: "Snowflake Temporary Stage Created"
Enabled: true
CreateAlert: false
Reference: https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion/
Reports:
MITRE ATT&CK:
- TA0010:T1041 # Exfiltration Over C2 Channel
ScheduledQueries:
- Query.Snowflake.TempStageCreated
Severity: Info
Tests:
- Name: Value Returned By Query
ExpectedResult: true
Log:
{
"execution_status": "SUCCESS",
"query_text": "CREATE OR REPLACE TEMP STAGE logs.PUBLIC.data_exfil",
"query_type": "CREATE",
"role_name": "SYSADMIN",
"stage": "logs.PUBLIC.data_exfil",
"start_time": "2024-06-10 19:48:52.068Z",
"user_name": "ADMIN"
}

0 comments on commit aea5a39

Please sign in to comment.