Detection rules › Kusto
GitLab - Abnormal number of repositories deleted
'This hunting queries identify an unusual increase of repo deletion activities adversaries may want to disrupt availability or compromise integrity by deleting business data.'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule body
id: 3efd09bd-a582-4410-b7ec-5ff21cfad7bd
name: GitLab - Abnormal number of repositories deleted
description: |
'This hunting queries identify an unusual increase of repo deletion activities adversaries may want to disrupt availability or compromise integrity by deleting business data.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1485
query: |
let LearningPeriod = 7d;
let BinTime = 1h;
let RunTime = 1h;
let StartTime = 1h;
let NumberOfStds = 3;
let MinThreshold = 10.0;
let EndRunTime = StartTime - RunTime;
let EndLearningTime = StartTime + LearningPeriod;
let GitLabRepositoryDestroyEvents = (GitLabAudit
| where RemoveAction == "project" or RemoveAction == "repository");
GitLabRepositoryDestroyEvents
| where TimeGenerated between (ago(EndLearningTime) .. ago(StartTime))
| summarize count() by bin(TimeGenerated, BinTime)
| summarize AvgInLearning = avg(count_), StdInLearning = stdev(count_)
| extend LearningThreshold = max_of(AvgInLearning + StdInLearning * NumberOfStds, MinThreshold)
| extend Dummy = 1
| join kind=innerunique (GitLabRepositoryDestroyEvents
| where TimeGenerated between (ago(StartTime) .. ago(EndRunTime))
| summarize CountInRunTime = count() by bin(TimeGenerated, BinTime)
| extend Dummy = 1) on Dummy
| project-away Dummy
| where CountInRunTime > LearningThreshold
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AuthorName
version: 1.0.1
kind: Scheduled
Stages and Predicates
Parameters
let LearningPeriod = 7d;
let BinTime = 1h;
let RunTime = 1h;
let StartTime = 1h;
let NumberOfStds = 3;
let MinThreshold = 10.0;
let EndRunTime = StartTime - RunTime;
let EndLearningTime = StartTime + LearningPeriod;
let GitLabRepositoryDestroyEvents is inlined into the numbered stages below.
Stages 1 to 2 define let GitLabRepositoryDestroyEvents (the rule's main pipeline source); stages 3 to 10 run on it.
Stage 1: source
GitLabAudit
Stage 2: where
| where RemoveAction == "project" or RemoveAction == "repository"
Stage 3: where
GitLabRepositoryDestroyEvents
| where TimeGenerated between (ago(EndLearningTime) .. ago(StartTime))
Stage 4: summarize
| summarize count() by bin(TimeGenerated, BinTime)
Stage 5: summarize
| summarize AvgInLearning = avg(count_), StdInLearning = stdev(count_)
Stage 6: extend
| extend LearningThreshold = max_of(AvgInLearning + StdInLearning * NumberOfStds, MinThreshold)
Stage 7: extend
| extend Dummy = 1
Stage 8: join
| join kind=innerunique (GitLabRepositoryDestroyEvents
| where TimeGenerated between (ago(StartTime) .. ago(EndRunTime))
| summarize CountInRunTime = count() by bin(TimeGenerated, BinTime)
| extend Dummy = 1) on Dummy
Stage 9: project-away
| project-away Dummy
Stage 10: where
| where CountInRunTime > LearningThreshold
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CountInRunTime | cross_field_compare |
| field:"CountInRunTime" kind:cross_field_compare value:"LearningThreshold" |
RemoveAction | eq |
| field:"RemoveAction" kind:eq |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AvgInLearning | summarize |
StdInLearning | summarize |
LearningThreshold | extend |