Pure Failed Login
Id | ed32b115-5001-43a7-a2bb-f53026db4d97 |
Rulename | Pure Failed Login |
Description | Detect failed login attacks and delete user |
Severity | High |
Tactics | CredentialAccess |
Techniques | T1212 |
Kind | NRT |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Pure Storage/Analytic Rules/PureFailedLogin.yaml |
Version | 1.0.0 |
Arm template | ed32b115-5001-43a7-a2bb-f53026db4d97.json |
Syslog
| where SyslogMessage has "purity.alert" and SyslogMessage has "invalid username or password"
| extend Message = SyslogMessage
| extend ParsedLog = extract_all(@"((?P<process>.*?)\[(?P<processid>.*?)\][\s\S]*?Array name:\s*'(?P<arrayname>\S+)'[\s\S]*?Controller:\s*'?(?P<controller>[^']+)'?[\s\S]*Interface:\s*'(?P<interface>\S+)'.*?User:\s'(?P<login>.*?)'\sLocation: '(?P<location>[^']+)'\sSublocation: '(?P<sublocation>[^']+)\s*(?P<part2log>[\s\S]*))", dynamic(['process', 'processid', 'arrayname', 'controller', 'interface','login', 'location', 'sublocation', 'part2log']), Message)
| mv-expand ParsedLog
| extend ResidueLog = tostring(ParsedLog[8])
| extend Rlog = extract_all(@"[\s\S]*Action:\s'(?P<action>[^']+)'[\s\S]*Method:\s'(?P<method>[^']+)'[\s\S]*Result:\s(?P<result>[^']+)[\s\S]*Description:\s'(?P<description>[^']*)'", dynamic(['action', 'method', 'result', 'description']), ResidueLog)
| mv-expand Rlog
| extend PureLogType = ParsedLog[0], PureProcessID = ParsedLog[1], PureArrayName = ParsedLog[2], PureController = ParsedLog[3], PureInterface = ParsedLog[4], PureLogin = ParsedLog [5], PureLocation = ParsedLog [6], PureSublocation = ParsedLog [7], PureAction = Rlog [0], PureMethod = Rlog [1], PureResult = Rlog [2], PureDescription = Rlog [3]
| project-away ResidueLog, Rlog, ParsedLog
| summarize count() by tostring(PureLogin), tostring(PureArrayName), HostIP
| where count_ >= 10
relevantTechniques:
- T1212
name: Pure Failed Login
alertDetailsOverride:
alertDynamicProperties: []
id: ed32b115-5001-43a7-a2bb-f53026db4d97
suppressionEnabled: false
eventGroupingSettings:
aggregationKind: SingleAlert
severity: High
incidentConfiguration:
createIncident: true
groupingConfiguration:
matchingMethod: AllEntities
groupByEntities: []
reopenClosedIncident: false
groupByAlertDetails: []
lookbackDuration: PT5H
groupByCustomDetails: []
enabled: false
suppressionDuration: 5h
description: Detect failed login attacks and delete user
version: 1.0.0
entityMappings:
- entityType: IP
fieldMappings:
- columnName: HostIP
identifier: Address
- entityType: Account
fieldMappings:
- columnName: PureLogin
identifier: Name
- entityType: Host
fieldMappings:
- columnName: PureArrayName
identifier: HostName
tactics:
- CredentialAccess
kind: NRT
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Pure Storage/Analytic Rules/PureFailedLogin.yaml
query: |-
Syslog
| where SyslogMessage has "purity.alert" and SyslogMessage has "invalid username or password"
| extend Message = SyslogMessage
| extend ParsedLog = extract_all(@"((?P<process>.*?)\[(?P<processid>.*?)\][\s\S]*?Array name:\s*'(?P<arrayname>\S+)'[\s\S]*?Controller:\s*'?(?P<controller>[^']+)'?[\s\S]*Interface:\s*'(?P<interface>\S+)'.*?User:\s'(?P<login>.*?)'\sLocation: '(?P<location>[^']+)'\sSublocation: '(?P<sublocation>[^']+)\s*(?P<part2log>[\s\S]*))", dynamic(['process', 'processid', 'arrayname', 'controller', 'interface','login', 'location', 'sublocation', 'part2log']), Message)
| mv-expand ParsedLog
| extend ResidueLog = tostring(ParsedLog[8])
| extend Rlog = extract_all(@"[\s\S]*Action:\s'(?P<action>[^']+)'[\s\S]*Method:\s'(?P<method>[^']+)'[\s\S]*Result:\s(?P<result>[^']+)[\s\S]*Description:\s'(?P<description>[^']*)'", dynamic(['action', 'method', 'result', 'description']), ResidueLog)
| mv-expand Rlog
| extend PureLogType = ParsedLog[0], PureProcessID = ParsedLog[1], PureArrayName = ParsedLog[2], PureController = ParsedLog[3], PureInterface = ParsedLog[4], PureLogin = ParsedLog [5], PureLocation = ParsedLog [6], PureSublocation = ParsedLog [7], PureAction = Rlog [0], PureMethod = Rlog [1], PureResult = Rlog [2], PureDescription = Rlog [3]
| project-away ResidueLog, Rlog, ParsedLog
| summarize count() by tostring(PureLogin), tostring(PureArrayName), HostIP
| where count_ >= 10
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/ed32b115-5001-43a7-a2bb-f53026db4d97')]",
"kind": "NRT",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/ed32b115-5001-43a7-a2bb-f53026db4d97')]",
"properties": {
"alertDetailsOverride": {
"alertDynamicProperties": []
},
"alertRuleTemplateName": "ed32b115-5001-43a7-a2bb-f53026db4d97",
"customDetails": null,
"description": "Detect failed login attacks and delete user",
"displayName": "Pure Failed Login",
"enabled": true,
"entityMappings": [
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "HostIP",
"identifier": "Address"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "PureLogin",
"identifier": "Name"
}
]
},
{
"entityType": "Host",
"fieldMappings": [
{
"columnName": "PureArrayName",
"identifier": "HostName"
}
]
}
],
"eventGroupingSettings": {
"aggregationKind": "SingleAlert"
},
"incidentConfiguration": {
"createIncident": true,
"groupingConfiguration": {
"enabled": false,
"groupByAlertDetails": [],
"groupByCustomDetails": [],
"groupByEntities": [],
"lookbackDuration": "PT5H",
"matchingMethod": "AllEntities",
"reopenClosedIncident": false
}
},
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Pure Storage/Analytic Rules/PureFailedLogin.yaml",
"query": "Syslog\n| where SyslogMessage has \"purity.alert\" and SyslogMessage has \"invalid username or password\"\n| extend Message = SyslogMessage\n| extend ParsedLog = extract_all(@\"((?P<process>.*?)\\[(?P<processid>.*?)\\][\\s\\S]*?Array name:\\s*'(?P<arrayname>\\S+)'[\\s\\S]*?Controller:\\s*'?(?P<controller>[^']+)'?[\\s\\S]*Interface:\\s*'(?P<interface>\\S+)'.*?User:\\s'(?P<login>.*?)'\\sLocation: '(?P<location>[^']+)'\\sSublocation: '(?P<sublocation>[^']+)\\s*(?P<part2log>[\\s\\S]*))\", dynamic(['process', 'processid', 'arrayname', 'controller', 'interface','login', 'location', 'sublocation', 'part2log']), Message)\n| mv-expand ParsedLog\n| extend ResidueLog = tostring(ParsedLog[8])\n| extend Rlog = extract_all(@\"[\\s\\S]*Action:\\s'(?P<action>[^']+)'[\\s\\S]*Method:\\s'(?P<method>[^']+)'[\\s\\S]*Result:\\s(?P<result>[^']+)[\\s\\S]*Description:\\s'(?P<description>[^']*)'\", dynamic(['action', 'method', 'result', 'description']), ResidueLog)\n| mv-expand Rlog\n| extend PureLogType = ParsedLog[0], PureProcessID = ParsedLog[1], PureArrayName = ParsedLog[2], PureController = ParsedLog[3], PureInterface = ParsedLog[4], PureLogin = ParsedLog [5], PureLocation = ParsedLog [6], PureSublocation = ParsedLog [7], PureAction = Rlog [0], PureMethod = Rlog [1], PureResult = Rlog [2], PureDescription = Rlog [3]\n| project-away ResidueLog, Rlog, ParsedLog\n| summarize count() by tostring(PureLogin), tostring(PureArrayName), HostIP\n| where count_ >= 10",
"severity": "High",
"subTechniques": [],
"suppressionDuration": "PT5H",
"suppressionEnabled": false,
"tactics": [
"CredentialAccess"
],
"techniques": [
"T1212"
],
"templateVersion": "1.0.0"
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}