Skip to content

[Bug] Inconsistent population of related_integrations field for ESQL rules #5246

@shashank-elastic

Description

@shashank-elastic

Describe the Bug

When Testing Release Fleet workflow fix PR - #5245. I found that ESQL rules across various integrations have inconsistent ( some integrations are listed and some are not) value population for related_integrations field

Windows Integration is Populated in ESQL rule
python -m detection_rules view-rule /Users/shashankks/elastic_workspace/detection-rules/rules/windows/defense_evasion_posh_obfuscation_concat_dynamic.toml          
Loaded config file: /Users/shashankks/elastic_workspace/detection-rules/.detection-rules-cfg.json

█▀▀▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄   ▄      █▀▀▄ ▄  ▄ ▄   ▄▄▄ ▄▄▄
█  █ █▄▄  █  █▄▄ █    █   █  █ █ █▀▄ █      █▄▄▀ █  █ █   █▄▄ █▄▄
█▄▄▀ █▄▄  █  █▄▄ █▄▄  █  ▄█▄ █▄█ █ ▀▄█      █ ▀▄ █▄▄█ █▄▄ █▄▄ ▄▄█

/Users/shashankks/elastic_workspace/detection-rules/detection_rules/index_mappings.py:345: ElasticsearchWarning: No limit defined, adding default limit of [1000]
  response = elastic_client.esql.query(query=query)
{
  "author": [
    "Elastic"
  ],
  "description": "Identifies PowerShell scripts that use concatenated strings within dynamic command invocation (&() or .()) as a form of obfuscation. These methods are designed to evade static analysis and bypass security protections such as the Antimalware Scan Interface (AMSI).",
  "from": "now-9m",
  "language": "esql",
  "license": "Elastic License v2",
  "name": "Potential PowerShell Obfuscation via Concatenated Dynamic Command Invocation",
  "note": " ## Triage and analysis\n\n> **Disclaimer**:\n> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.\n\n### Investigating Potential PowerShell Obfuscation via Concatenated Dynamic Command Invocation\n\nPowerShell is a powerful scripting language used for task automation and configuration management in Windows environments. Adversaries exploit its capabilities by obfuscating commands to evade detection, often using concatenated strings in dynamic invocations. This detection rule identifies such obfuscation by analyzing script patterns, specifically looking for concatenated strings within dynamic command invocations, which are indicative of attempts to bypass security measures like AMSI. By counting these patterns, the rule effectively flags suspicious scripts, aiding in the identification of potential threats.\n\n### Possible investigation steps\n\n- Review the `powershell.file.script_block_text` field to understand the content and purpose of the script, focusing on the concatenated strings and dynamic command invocations.\n- Check the `host.name` and `user.id` fields to identify the machine and user account associated with the execution of the suspicious script, which can help determine if the activity is expected or anomalous.\n- Analyze the `file.path` field to locate the script's source or storage location, which may provide additional context or indicate if the script is part of a known application or process.\n- Investigate the `powershell.file.script_block_id` and `powershell.sequence` fields to trace the execution sequence and correlate it with other related PowerShell activities, which might reveal a broader pattern of behavior.\n- Assess the `agent.id` field to determine the specific endpoint agent involved, which can assist in further endpoint-specific investigations or actions.\n\n### False positive analysis\n\n- Scripts with legitimate concatenated strings for dynamic command execution may trigger the rule. Review the script context to determine if the concatenation serves a valid administrative purpose.\n- Automated scripts from trusted sources that use concatenation for modularity or readability might be flagged. Consider adding these scripts to an allowlist if they are verified as safe.\n- Development or testing environments where PowerShell scripts are frequently modified and tested could generate false positives. Implement exceptions for known development hosts or user accounts.\n- Security tools or monitoring solutions that use PowerShell for legitimate operations may inadvertently match the pattern. Identify these tools and exclude their operations from the rule.\n- Regularly review and update the exclusion list to ensure it reflects the current environment and does not inadvertently allow malicious activity.\n\n### Response and remediation\n\n- Isolate the affected host immediately to prevent further execution of potentially malicious scripts and limit lateral movement within the network.\n- Terminate any suspicious PowerShell processes identified by the alert to halt the execution of obfuscated commands.\n- Conduct a thorough review of the script block text and associated script block ID to understand the intent and potential impact of the obfuscated commands.\n- Remove any unauthorized or malicious scripts from the affected system and ensure that all legitimate scripts are verified and signed.\n- Restore the affected system from a known good backup if any malicious activity is confirmed, ensuring that all data integrity checks are performed.\n- Escalate the incident to the security operations team for further analysis and to determine if additional systems have been compromised.\n- Update endpoint protection and monitoring tools to enhance detection capabilities for similar obfuscation techniques, leveraging insights from the MITRE ATT&CK framework.\n",
  "query": "from logs-windows.powershell_operational* metadata _id, _version, _index\n| where event.code == \"4104\" and powershell.file.script_block_text like \"*+*\"\n\n// replace the patterns we are looking for with the \ud83d\udd25 emoji to enable counting them\n// The emoji is used because it's unlikely to appear in scripts and has a consistent character length of 1\n| eval Esql.script_block_tmp = replace(\n    powershell.file.script_block_text,\n    \"\"\"[.&]\\(\\s*(['\"][A-Za-z0-9.-]+['\"]\\s*\\+\\s*)+['\"][A-Za-z0-9.-]+['\"]\\s*\\)\"\"\",\n    \"\ud83d\udd25\"\n)\n\n// count how many patterns were detected by calculating the number of \ud83d\udd25 characters inserted\n| eval Esql.script_block_pattern_count = length(Esql.script_block_tmp) - length(replace(Esql.script_block_tmp, \"\ud83d\udd25\", \"\"))\n\n// keep the fields relevant to the query, although this is not needed as the alert is populated using _id\n| keep\n    Esql.script_block_pattern_count,\n    Esql.script_block_tmp,\n    powershell.file.script_block_text,\n    powershell.file.script_block_id,\n    file.path,\n    powershell.sequence,\n    powershell.total,\n    _id,\n    _index,\n    host.name,\n    agent.id,\n    user.id\n\n// Filter for scripts that match the pattern at least once\n| where Esql.script_block_pattern_count >= 1\n",
  "related_integrations": [
    {
      "package": "windows",
      "version": "^3.0.0"
    }
  ],
  "required_fields": [
    {
      "ecs": false,
      "name": "Esql.script_block_pattern_count",
      "type": "integer"
    },
    {
      "ecs": false,
      "name": "Esql.script_block_tmp",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "_id",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "_index",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "agent.id",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "file.path",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "host.name",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "powershell.file.script_block_id",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "powershell.file.script_block_text",
      "type": "text"
    },
    {
      "ecs": false,
      "name": "powershell.sequence",
      "type": "long"
    },
    {
      "ecs": false,
      "name": "powershell.total",
      "type": "long"
    },
    {
      "ecs": true,
      "name": "user.id",
      "type": "keyword"
    }
  ],
  "risk_score": 21,
  "rule_id": "083383af-b9a4-42b7-a463-29c40efe7797",
  "setup": "## Setup\n\nThe 'PowerShell Script Block Logging' logging policy must be enabled.\nSteps to implement the logging policy with Advanced Audit Configuration:\n\n```\nComputer Configuration >\nAdministrative Templates >\nWindows PowerShell >\nTurn on PowerShell Script Block Logging (Enable)\n```\n\nSteps to implement the logging policy via registry:\n\n```\nreg add \"hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging\" /v EnableScriptBlockLogging /t REG_DWORD /d 1\n```\n",
  "severity": "low",
  "tags": [
    "Domain: Endpoint",
    "OS: Windows",
    "Use Case: Threat Detection",
    "Tactic: Defense Evasion",
    "Data Source: PowerShell Logs",
    "Resources: Investigation Guide"
  ],
  "threat": [
    {
      "framework": "MITRE ATT&CK",
      "tactic": {
        "id": "TA0005",
        "name": "Defense Evasion",
        "reference": "https://attack.mitre.org/tactics/TA0005/"
      },
      "technique": [
        {
          "id": "T1027",
          "name": "Obfuscated Files or Information",
          "reference": "https://attack.mitre.org/techniques/T1027/"
        },
        {
          "id": "T1140",
          "name": "Deobfuscate/Decode Files or Information",
          "reference": "https://attack.mitre.org/techniques/T1140/"
        }
      ]
    },
    {
      "framework": "MITRE ATT&CK",
      "tactic": {
        "id": "TA0002",
        "name": "Execution",
        "reference": "https://attack.mitre.org/tactics/TA0002/"
      },
      "technique": [
        {
          "id": "T1059",
          "name": "Command and Scripting Interpreter",
          "reference": "https://attack.mitre.org/techniques/T1059/",
          "subtechnique": [
            {
              "id": "T1059.001",
              "name": "PowerShell",
              "reference": "https://attack.mitre.org/techniques/T1059/001/"
            }
          ]
        }
      ]
    }
  ],
  "timestamp_override": "event.ingested",
  "type": "esql",
  "version": 4
}
Azure ESQL rule has no related_integrations field
python -m detection_rules view-rule /Users/shashankks/elastic_workspace/detection-rules/rules/integrations/azure/persistence_entra_id_oidc_discovery_url_change.toml
Loaded config file: /Users/shashankks/elastic_workspace/detection-rules/.detection-rules-cfg.json

█▀▀▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄   ▄      █▀▀▄ ▄  ▄ ▄   ▄▄▄ ▄▄▄
█  █ █▄▄  █  █▄▄ █    █   █  █ █ █▀▄ █      █▄▄▀ █  █ █   █▄▄ █▄▄
█▄▄▀ █▄▄  █  █▄▄ █▄▄  █  ▄█▄ █▄█ █ ▀▄█      █ ▀▄ █▄▄█ █▄▄ █▄▄ ▄▄█

/Users/shashankks/elastic_workspace/detection-rules/detection_rules/index_mappings.py:345: ElasticsearchWarning: No limit defined, adding default limit of [1000]
  response = elastic_client.esql.query(query=query)
{
  "author": [
    "Elastic"
  ],
  "description": "Detects a change to the OpenID Connect (OIDC) discovery URL in the Entra ID Authentication Methods Policy. This behavior may indicate an attempt to federate Entra ID with an attacker-controlled identity provider, enabling bypass of multi-factor authentication (MFA) and unauthorized access through bring-your-own IdP (BYOIDP) methods.",
  "from": "now-9m",
  "interval": "8m",
  "language": "esql",
  "license": "Elastic License v2",
  "name": "OIDC Discovery URL Changed in Entra ID",
  "note": "## Triage and analysis\n\n### Investigating OIDC Discovery URL Changed in Entra ID\n\nThis rule detects when the OIDC `discoveryUrl` is changed within the Entra ID Authentication Methods policy. Adversaries may leverage this to federate Entra ID with a rogue Identity Provider (IdP) under their control, allowing them to authenticate users with attacker-owned credentials and bypass MFA. This misconfiguration allows an attacker to impersonate valid users by issuing tokens via a third-party OIDC IdP while still passing validation in Entra ID. This technique has been publicly demonstrated and has critical implications for trust in federated identity.\n\n### Possible investigation steps\n- Review `azure.auditlogs.properties.initiated_by.user.userPrincipalName` and `ipAddress` to identify who made the change and from where.\n- Examine the `old_oidc_discovery` and `new_oidc_discovery` to confirm if the new `discoveryUrl` points to an unexpected or untrusted IdP.\n- Check that the discovery URLs have `.well-known/openid-configuration` endpoints, which are standard for OIDC providers.\n- Use `azure.auditlogs.properties.correlation_id` to pivot to related changes and activity from the same session.\n- Review any subsequent sign-in activity that may have originated from the new IdP.\n- Pivot to additional logs associated with the user or application that made the change to identify any further suspicious activity.\n\n### False positive analysis\n- Entra ID administrators may intentionally reconfigure OIDC trust relationships to support new business requirements.\n- Validate any changes with the identity or security operations team before taking action.\n\n### Response and remediation\n- If the change is unauthorized, immediately revert the discovery URL to the trusted IdP via the Entra ID portal.\n- Revoke tokens or sessions issued after the configuration change.\n- Investigate how the unauthorized change occurred (e.g., compromised account or over-privileged app).\n- Apply conditional access policies and change control procedures to protect IdP configuration changes.\n",
  "query": "from logs-azure.auditlogs-* metadata _id, _version, _index\n| where event.action == \"Authentication Methods Policy Update\"\n| eval Esql.azure_auditlogs_properties_target_resources_modified_properties_new_value_replace = replace(`azure.auditlogs.properties.target_resources.0.modified_properties.0.new_value`, \"\\\\\\\\\", \"\")\n| eval Esql.azure_auditlogs_properties_target_resources_modified_properties_old_value_replace = replace(`azure.auditlogs.properties.target_resources.0.modified_properties.0.old_value`, \"\\\\\\\\\", \"\")\n| dissect Esql.azure_auditlogs_properties_target_resources_modified_properties_new_value_replace \"%{}discoveryUrl\\\":\\\"%{Esql.azure_auditlogs_properties_auth_oidc_discovery_url_new}\\\"}%{}\"\n| dissect Esql.azure_auditlogs_properties_target_resources_modified_properties_old_value_replace \"%{}discoveryUrl\\\":\\\"%{Esql.azure_auditlogs_properties_auth_oidc_discovery_url_old}\\\"}%{}\"\n| where Esql.azure_auditlogs_properties_auth_oidc_discovery_url_new is not null and Esql.azure_auditlogs_properties_auth_oidc_discovery_url_old is not null\n| where Esql.azure_auditlogs_properties_auth_oidc_discovery_url_new != Esql.azure_auditlogs_properties_auth_oidc_discovery_url_old\n| keep\n    @timestamp,\n    event.action,\n    event.outcome,\n    azure.tenant_id,\n    azure.correlation_id,\n    azure.auditlogs.properties.activity_datetime,\n    azure.auditlogs.properties.operation_type,\n    azure.auditlogs.properties.initiated_by.user.userPrincipalName,\n    azure.auditlogs.properties.initiated_by.user.displayName,\n    azure.auditlogs.properties.initiated_by.user.ipAddress,\n    source.geo.city_name,\n    source.geo.region_name,\n    source.geo.country_name,\n    Esql.azure_auditlogs_properties_auth_oidc_discovery_url_new,\n    Esql.azure_auditlogs_properties_auth_oidc_discovery_url_old\n",
  "references": [
    "https://dirkjanm.io/persisting-with-federated-credentials-entra-apps-managed-identities/"
  ],
  "required_fields": [
    {
      "ecs": true,
      "name": "@timestamp",
      "type": "date"
    },
    {
      "ecs": false,
      "name": "Esql.azure_auditlogs_properties_auth_oidc_discovery_url_new",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "Esql.azure_auditlogs_properties_auth_oidc_discovery_url_old",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "azure.auditlogs.properties.activity_datetime",
      "type": "date"
    },
    {
      "ecs": false,
      "name": "azure.auditlogs.properties.initiated_by.user.displayName",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "azure.auditlogs.properties.initiated_by.user.ipAddress",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "azure.auditlogs.properties.initiated_by.user.userPrincipalName",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "azure.auditlogs.properties.operation_type",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "azure.correlation_id",
      "type": "keyword"
    },
    {
      "ecs": false,
      "name": "azure.tenant_id",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "event.action",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "event.outcome",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "source.geo.city_name",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "source.geo.country_name",
      "type": "keyword"
    },
    {
      "ecs": true,
      "name": "source.geo.region_name",
      "type": "keyword"
    }
  ],
  "risk_score": 73,
  "rule_id": "498e4094-60e7-11f0-8847-f661ea17fbcd",
  "severity": "high",
  "tags": [
    "Domain: Cloud",
    "Domain: Identity",
    "Data Source: Azure",
    "Data Source: Microsoft Entra ID",
    "Data Source: Microsoft Entra ID Audit Logs",
    "Use Case: Identity and Access Audit",
    "Tactic: Persistence",
    "Resources: Investigation Guide"
  ],
  "threat": [
    {
      "framework": "MITRE ATT&CK",
      "tactic": {
        "id": "TA0003",
        "name": "Persistence",
        "reference": "https://attack.mitre.org/tactics/TA0003/"
      },
      "technique": [
        {
          "id": "T1556",
          "name": "Modify Authentication Process",
          "reference": "https://attack.mitre.org/techniques/T1556/",
          "subtechnique": [
            {
              "id": "T1556.009",
              "name": "Conditional Access Policies",
              "reference": "https://attack.mitre.org/techniques/T1556/009/"
            }
          ]
        }
      ]
    }
  ],
  "timestamp_override": "event.ingested",
  "type": "esql",
  "version": 5
}
AWS bedrock ESQL rules have no related_integrations field
 python -m detection_rules view-rule rules/integrations/aws_bedrock/aws_bedrock_multiple_sensitive_information_policy_blocks_detected.toml                           
Loaded config file: /Users/shashankks/elastic_workspace/detection-rules/.detection-rules-cfg.json

█▀▀▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄   ▄      █▀▀▄ ▄  ▄ ▄   ▄▄▄ ▄▄▄
█  █ █▄▄  █  █▄▄ █    █   █  █ █ █▀▄ █      █▄▄▀ █  █ █   █▄▄ █▄▄
█▄▄▀ █▄▄  █  █▄▄ █▄▄  █  ▄█▄ █▄█ █ ▀▄█      █ ▀▄ █▄▄█ █▄▄ █▄▄ ▄▄█

/Users/shashankks/elastic_workspace/detection-rules/detection_rules/index_mappings.py:345: ElasticsearchWarning: No limit defined, adding default limit of [1000]
  response = elastic_client.esql.query(query=query)
{
  "author": [
    "Elastic"
  ],
  "description": "Detects repeated compliance violation 'BLOCKED' actions coupled with specific policy name such as 'sensitive_information_policy', indicating persistent misuse or attempts to probe the model's denied topics.",
  "false_positives": [
    "New model deployments.",
    "Testing updates to compliance policies."
  ],
  "from": "now-60m",
  "interval": "10m",
  "language": "esql",
  "license": "Elastic License v2",
  "name": "Unusual High Denied Sensitive Information Policy Blocks Detected",
  "note": "## Triage and analysis\n\n### Investigating Unusual High Denied Sensitive Information Policy Blocks Detected\n\nAmazon Bedrock Guardrail is a set of features within Amazon Bedrock designed to help businesses apply robust safety and privacy controls to their generative AI applications.\n\nIt enables users to set guidelines and filters that manage content quality, relevancy, and adherence to responsible AI practices.\n\nThrough Guardrail, organizations can define \"sensitive information filters\" to prevent the model from generating content on specific, undesired subjects,\nand they can establish thresholds for harmful content categories.\n\n#### Possible investigation steps\n\n- Identify the user account that queried sensitive information and whether it should perform this kind of action.\n- Investigate other alerts associated with the user account during the past 48 hours.\n- Consider the time of day. If the user is a human (not a program or script), did the activity take place during a normal time of day?\n- Examine the account's prompts and responses in the last 24 hours.\n- If you suspect the account has been compromised, scope potentially compromised assets by tracking Amazon Bedrock model access, prompts generated, and responses to the prompts by the account in the last 24 hours.\n\n### False positive analysis\n\n- Verify the user account that queried denied topics, is not testing any new model deployments or updated compliance policies in Amazon Bedrock guardrails.\n\n### Response and remediation\n\n- Initiate the incident response process based on the outcome of the triage.\n- Disable or limit the account during the investigation and response.\n- Identify the possible impact of the incident and prioritize accordingly; the following actions can help you gain context:\n    - Identify the account role in the cloud environment.\n    - Identify if the attacker is moving laterally and compromising other Amazon Bedrock Services.\n    - Identify any regulatory or legal ramifications related to this activity.\n- Review the permissions assigned to the implicated user group or role behind these requests to ensure they are authorized and expected to access bedrock and ensure that the least privilege principle is being followed.\n- Determine the initial vector abused by the attacker and take action to prevent reinfection via the same vector.\n- Using the incident response data, update logging and audit policies to improve the mean time to detect (MTTD) and the mean time to respond (MTTR).\n",
  "query": "from logs-aws_bedrock.invocation-*\n\n// Expand multi-valued policy name field\n| mv_expand gen_ai.policy.name\n\n// Filter for blocked actions related to sensitive info policy\n| where\n  gen_ai.policy.action == \"BLOCKED\"\n  and gen_ai.compliance.violation_detected == \"true\"\n  and gen_ai.policy.name == \"sensitive_information_policy\"\n\n// keep only relevant fields\n| keep user.id\n\n// count how many times each user triggered a sensitive info block\n| stats\n    Esql.ml_policy_blocked_sensitive_info_count = count()\n  by user.id\n\n// Filter for users with more than 5 violations\n| where Esql.ml_policy_blocked_sensitive_info_count > 5\n\n// sort highest to lowest\n| sort Esql.ml_policy_blocked_sensitive_info_count desc\n",
  "references": [
    "https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-components.html",
    "https://atlas.mitre.org/techniques/AML.T0051",
    "https://atlas.mitre.org/techniques/AML.T0054",
    "https://www.elastic.co/security-labs/elastic-advances-llm-security"
  ],
  "required_fields": [
    {
      "ecs": false,
      "name": "Esql.ml_policy_blocked_sensitive_info_count",
      "type": "long"
    },
    {
      "ecs": true,
      "name": "user.id",
      "type": "keyword"
    }
  ],
  "risk_score": 47,
  "rule_id": "0e1af929-42ed-4262-a846-55a7c54e7c84",
  "setup": "## Setup\n\nThis rule requires that guardrails are configured in AWS Bedrock. For more information, see the AWS Bedrock documentation:\n\nhttps://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-create.html\n",
  "severity": "medium",
  "tags": [
    "Domain: LLM",
    "Data Source: AWS Bedrock",
    "Data Source: AWS S3",
    "Use Case: Policy Violation",
    "Mitre Atlas: T0051",
    "Mitre Atlas: T0054",
    "Resources: Investigation Guide"
  ],
  "timestamp_override": "event.ingested",
  "type": "esql",
  "version": 4
}

To Reproduce

  • Enable export DR_REMOTE_ESQL_VALIDATION="true"
  • Use view-rule on sample spread ESQL rules
  • See the above inconsistent behaviour
  • For now we know it shows up for windows, aws and does not show up for aws_bedrock and azure

Expected Behavior

  • Related integrations for all ESQL rules should be rightly populated

Screenshots

NA

Desktop - OS

None

Desktop - Version

No response

Additional Context

Identified via testing #5245

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions