forked from Cloud-Architekt/AzureSentinel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNewWorkflowUsingSecrets.yaml
79 lines (79 loc) · 4.02 KB
/
NewWorkflowUsingSecrets.yaml
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
id: d0b2208c-b4cb-4f66-8857-0155722266ac
name: 'New GitHub workflow is using secrets - Historic allow list'
description: |
'This detection builds an allow list of historical usage of secrets by Workflows and compares to recent history, flagging growth of secrets use which are not manually included in the allow list and not historically included in the allow list of workflows. This is to determine if someone is hijacking or use secrets in other workflows.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 6h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1552
query: |
let starttime = 14d;
let endtime = 6h;
// Ignore Build/Releases with less/equal this number
let SecretUsageThreshold = 3;
// New Connections need to exhibit execution of more "new" connections than this number.
let NewSecretUsageThreshold = 1;
// List of Repositories and Worfklows (GitHub Actions) to ignore in your space
let BypassRepositories = datatable(organization:string, repository:string)
[
//"yourOrg", "yourRepo"
];
let BypassWorkflows = datatable(job_workflow_ref_s:string, secret:string)
[
//Optional: Add runner group Id to detect first time usage on other runner than expected (self hosted runner to steal token or secret)
//"yourOrg/yourRepo/.github/workflows/pull.yml@refs/heads/main", "ARM_CLIENT_ID",
//"yourOrg/yourRepo/.github/workflows/push.yml@refs/heads/main", "AZURE_SENTINEL_CREDENTIALS_XYZ"
];
let HistoricDefs = GitHubAuditLogPolling_CL
| where TimeGenerated between (ago(starttime) .. ago(endtime))
| where action_s == "workflows.prepared_workflow_job"
| extend secrets = (parse_json(secrets_passed_s))
| mv-expand secrets
| extend secret = tostring(secrets)
| summarize HistoricCount=count() by job_workflow_ref_s, secret, repo_s;
GitHubAuditLogPolling_CL
| where TimeGenerated >= ago(endtime)
| where action_s == "workflows.prepared_workflow_job"
| extend secrets = (parse_json(secrets_passed_s))
| mv-expand secrets
| extend secret = tostring(secrets)
| summarize CurrentCount=count() by job_workflow_ref_s, secret, repo_s
| where CurrentCount > SecretUsageThreshold
| join kind= leftouter (HistoricDefs) on job_workflow_ref_s, secret
// Exlude workflows from bypass list
| join kind=anti BypassWorkflows on $left.job_workflow_ref_s == $right.job_workflow_ref_s and $left.secret == $right.secret
| where CurrentCount >= HistoricCount + NewSecretUsageThreshold or job_workflow_ref_s !in (HistoricDefs)
| extend organization = tostring(split(repo_s, "/")[0])
| extend repository = tostring(split(repo_s, "/")[1])
// Exclude workflows from whitelisted repositories
| join kind=anti BypassRepositories on $left.organization == $right.organization and $left.repository == $right.repository
// Lookup back to PreparedWorkflow action to get Workflow Run Id
| join kind=innerunique (
GitHubAuditLogPolling_CL
| where TimeGenerated >= ago(endtime)
| where action_s == "workflows.prepared_workflow_job"
| summarize arg_min(TimeGenerated, *) by job_workflow_ref_s
| project workflow_run_id_d, job_workflow_ref_s, _timestamp_d
) on $left.job_workflow_ref_s == $right.job_workflow_ref_s
// Use Workflow Run Id for correlation to Created Worfklow Event for enrichment of actor
| join kind=innerunique (
GitHubAuditLogPolling_CL
| where TimeGenerated >= ago(endtime)
| where action_s == "workflows.created_workflow_run"
| project actor_s, workflow_run_id_d, _timestamp_d
) on $left.workflow_run_id_d == $right.workflow_run_id_d
| extend date_time = unixtime_milliseconds_todatetime(_timestamp_d)
| project TimeGenerated = _timestamp_d1, AccountCustomEntity = actor_s, organization, repository, secret, workflow_RefId = job_workflow_ref_s, CurrentCount, HistoricCount, WorkflowRundId = workflow_run_id_d
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
version: 1.0.0
kind: Scheduled