RecordedFuture Threat Hunting Hash All Actors
| Id | 6db6a8e6-2959-440b-ba57-a505875fcb37 | 
| Rulename | RecordedFuture Threat Hunting Hash All Actors | 
| Description | Recorded Future Threat Hunting hash correlation for all actors. | 
| Severity | Medium | 
| Tactics | InitialAccess Execution Persistence | 
| Techniques | T1189 T1059 T1554 | 
| Required data connectors | ThreatIntelligenceUploadIndicatorsAPI | 
| Kind | Scheduled | 
| Query frequency | 15m | 
| Query period | 1d | 
| Trigger threshold | 0 | 
| Trigger operator | gt | 
| Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Recorded Future/Analytic Rules/ThreatHunting/RecordedFutureThreatHuntingHashAllActors.yaml | 
| Version | 1.1.0 | 
| Arm template | 6db6a8e6-2959-440b-ba57-a505875fcb37.json | 
let ioc_lookBack = 1d;
// The source table (imFileEvent) is a ASIM parser table, but can be replaced by any infrastructure table containing Hash data.
// The following workbook: Recorded Future - Hash Correlation will help researching available data and selecting tables and columns
imFileEvent
| where isnotempty(Hash)
| extend lowerHash=tolower(Hash)
| join kind=inner (
ThreatIntelIndicators
// Only look for IOCs
| where ObservableKey contains'file:hashes'
| where isnotempty(ObservableValue)
// Only look at Recorded Future Threat Hunt Indicators.
| where Data.description startswith "Recorded Future - Threat Hunt"
// Only work with the latest indicators
| where TimeGenerated >= ago(ioc_lookBack)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id
| where IsActive == true and ValidUntil > now()
| extend lowerHash=tolower(ObservableValue)
) on lowerHash
// select column from the source table to match with Recorded Future ThreatIntelIndicator $left.Hash
| mv-expand RecordedFuturePortalLink=parse_json(tostring(parse_json(Tags)))['recordedfutureportallink']
// Hash and HashType is defaulted to data from Recorded Future, it can be changed to data from the infrastructure table.
| project Hash=ObservableValue, HashType=extract("file:hashes.('[^']*')", 1, ObservableKey), Description=Data.description, Type, TimeGenerated, RecordedFuturePortalLink
kind: Scheduled
customDetails:
  ActorInformation: RecordedFuturePortalLink
alertDetailsOverride:
  alertDisplayNameFormat: '{{Description}}'
  alertDescriptionFormat: '**{{Description}}**\n\nCorrelation found on {{Hash}} from the {{Type}} table.\n'
  alertDynamicProperties:
  - value: RecordedFuturePortalLink
    alertProperty: AlertLink
entityMappings:
- entityType: FileHash
  fieldMappings:
  - columnName: Hash
    identifier: Value
  - columnName: HashType
    identifier: Algorithm
description: |
    'Recorded Future Threat Hunting hash correlation for all actors.'
severity: Medium
queryFrequency: 15m
incidentConfiguration:
  groupingConfiguration:
    reopenClosedIncident: false
    matchingMethod: AllEntities
    lookbackDuration: 1h
    enabled: true
  createIncident: true
triggerThreshold: 0
relevantTechniques:
- T1189
- T1059
- T1554
eventGroupingSettings:
  aggregationKind: AlertPerResult
tactics:
- InitialAccess
- Execution
- Persistence
name: RecordedFuture Threat Hunting Hash All Actors
id: 6db6a8e6-2959-440b-ba57-a505875fcb37
query: |
  let ioc_lookBack = 1d;
  // The source table (imFileEvent) is a ASIM parser table, but can be replaced by any infrastructure table containing Hash data.
  // The following workbook: Recorded Future - Hash Correlation will help researching available data and selecting tables and columns
  imFileEvent
  | where isnotempty(Hash)
  | extend lowerHash=tolower(Hash)
  | join kind=inner (
  ThreatIntelIndicators
  // Only look for IOCs
  | where ObservableKey contains'file:hashes'
  | where isnotempty(ObservableValue)
  // Only look at Recorded Future Threat Hunt Indicators.
  | where Data.description startswith "Recorded Future - Threat Hunt"
  // Only work with the latest indicators
  | where TimeGenerated >= ago(ioc_lookBack)
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id
  | where IsActive == true and ValidUntil > now()
  | extend lowerHash=tolower(ObservableValue)
  ) on lowerHash
  // select column from the source table to match with Recorded Future ThreatIntelIndicator $left.Hash
  | mv-expand RecordedFuturePortalLink=parse_json(tostring(parse_json(Tags)))['recordedfutureportallink']
  // Hash and HashType is defaulted to data from Recorded Future, it can be changed to data from the infrastructure table.
  | project Hash=ObservableValue, HashType=extract("file:hashes.('[^']*')", 1, ObservableKey), Description=Data.description, Type, TimeGenerated, RecordedFuturePortalLink  
requiredDataConnectors:
- dataTypes:
  - ThreatIntelIndicators
  connectorId: ThreatIntelligenceUploadIndicatorsAPI
version: 1.1.0
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Recorded Future/Analytic Rules/ThreatHunting/RecordedFutureThreatHuntingHashAllActors.yaml
queryPeriod: 1d
{
  "$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/6db6a8e6-2959-440b-ba57-a505875fcb37')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/6db6a8e6-2959-440b-ba57-a505875fcb37')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "**{{Description}}**\\n\\nCorrelation found on {{Hash}} from the {{Type}} table.\\n",
          "alertDisplayNameFormat": "{{Description}}",
          "alertDynamicProperties": [
            {
              "alertProperty": "AlertLink",
              "value": "RecordedFuturePortalLink"
            }
          ]
        },
        "alertRuleTemplateName": "6db6a8e6-2959-440b-ba57-a505875fcb37",
        "customDetails": {
          "ActorInformation": "RecordedFuturePortalLink"
        },
        "description": "'Recorded Future Threat Hunting hash correlation for all actors.'\n",
        "displayName": "RecordedFuture Threat Hunting Hash All Actors",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "FileHash",
            "fieldMappings": [
              {
                "columnName": "Hash",
                "identifier": "Value"
              },
              {
                "columnName": "HashType",
                "identifier": "Algorithm"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "lookbackDuration": "PT1H",
            "matchingMethod": "AllEntities",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Recorded Future/Analytic Rules/ThreatHunting/RecordedFutureThreatHuntingHashAllActors.yaml",
        "query": "let ioc_lookBack = 1d;\n// The source table (imFileEvent) is a ASIM parser table, but can be replaced by any infrastructure table containing Hash data.\n// The following workbook: Recorded Future - Hash Correlation will help researching available data and selecting tables and columns\nimFileEvent\n| where isnotempty(Hash)\n| extend lowerHash=tolower(Hash)\n| join kind=inner (\nThreatIntelIndicators\n// Only look for IOCs\n| where ObservableKey contains'file:hashes'\n| where isnotempty(ObservableValue)\n// Only look at Recorded Future Threat Hunt Indicators.\n| where Data.description startswith \"Recorded Future - Threat Hunt\"\n// Only work with the latest indicators\n| where TimeGenerated >= ago(ioc_lookBack)\n| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id\n| where IsActive == true and ValidUntil > now()\n| extend lowerHash=tolower(ObservableValue)\n) on lowerHash\n// select column from the source table to match with Recorded Future ThreatIntelIndicator $left.Hash\n| mv-expand RecordedFuturePortalLink=parse_json(tostring(parse_json(Tags)))['recordedfutureportallink']\n// Hash and HashType is defaulted to data from Recorded Future, it can be changed to data from the infrastructure table.\n| project Hash=ObservableValue, HashType=extract(\"file:hashes.('[^']*')\", 1, ObservableKey), Description=Data.description, Type, TimeGenerated, RecordedFuturePortalLink\n",
        "queryFrequency": "PT15M",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Execution",
          "InitialAccess",
          "Persistence"
        ],
        "techniques": [
          "T1059",
          "T1189",
          "T1554"
        ],
        "templateVersion": "1.1.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}