Custom Agents - Observed tool call to an internal or metadata target
Custom Internal Network Tool Target
Query
let Evidence=materialize(CustomAgentInlineContent(1h));
CustomAgentSpans(1h)
| where Classification !in ('Excluded managed platform', 'Unattributed GenAI') and HasLineage
| where IsTool and isnotempty(TargetHost)
| where ipv4_is_private(TargetHost) == true
or ipv4_is_in_range(TargetHost, '127.0.0.0/8') == true
or ipv4_is_in_range(TargetHost, '169.254.0.0/16') == true
or ipv6_is_in_range(TargetHost, '::1/128') == true
or ipv6_is_in_range(TargetHost, 'fc00::/7') == true
or ipv6_is_in_range(TargetHost, 'fe80::/10') == true
or TargetHost in ('localhost', 'metadata.google.internal')
or TargetHost endswith '.localhost' or TargetHost endswith '.local'
| extend Signal='Observed internal tool destination; SSRF and impact unproven'
| extend TimeGenerated=EventTime, ResourceId=_ResourceId, TraceId=OperationId,
EventCount=tolong(column_ifexists('EventCount', 1)),
SuccessfulCalls=tolong(column_ifexists('SuccessfulCalls', 0)),
FailedCalls=tolong(column_ifexists('FailedCalls', 0))
| project TimeGenerated, ResourceId, Agent, AgentId, AgentKey, AppRoleName,
TraceId, SpanId, Conversation, Model, Tool, TargetHost, ServerDisplay,
Signal, EventCount, SuccessfulCalls, FailedCalls,
TriggerSpanId=tostring(column_ifexists('TriggerSpanId', '')),
TriggerTime=todatetime(column_ifexists('TriggerTime', datetime(null))),
TriggerTool=tostring(column_ifexists('TriggerTool', '')),
TriggerToolResult=tostring(column_ifexists('TriggerToolResult', '')),
TriggerServerDisplay=tostring(column_ifexists('TriggerServerDisplay', '')),
TriggerTargetHost=tostring(column_ifexists('TriggerTargetHost', '')),
RiskyOutputKind=tostring(column_ifexists('RiskyOutputKind', '')),
RelatedToolResults=tolong(column_ifexists('RelatedToolResults', 0)),
MatchedIntentPrompt=tostring(column_ifexists('IntentPrompt', '')),
MatchedIntentSpanId=tostring(column_ifexists('IntentSpanId', ''))
| join kind=leftouter (Evidence
| project ResourceId=_ResourceId, TraceId=OperationId, SpanId, AgentKey, Prompt, Output, ToolArguments, ToolResult, InputMessages, OutputMessages,
EvidenceSource, PromptEvidenceOrigin, OutputEvidenceOrigin, PromptEvidenceSpanId, OutputEvidenceSpanId,
InputParseState, OutputParseState, ToolArgumentsState, ToolResultState)
on ResourceId, TraceId, SpanId, AgentKey
| extend Prompt=coalesce(MatchedIntentPrompt, Prompt),
PromptEvidenceOrigin=iff(isnotempty(MatchedIntentPrompt), 'Matched intent span: user role', PromptEvidenceOrigin),
PromptEvidenceSpanId=coalesce(MatchedIntentSpanId, PromptEvidenceSpanId)
| extend PreviewCharacters=toint(min_of(160, max_of(0, (1500 - string_size(tostring(bag_pack(
'AgentId', AgentId, 'AgentKey', AgentKey, 'TraceId', TraceId, 'SpanId', SpanId,
'Conversation', Conversation, 'ResourceId', ResourceId, 'Signal', Signal)))) / 12)))
| extend PromptPreview=substring(Prompt, 0, PreviewCharacters),
OutputPreview=substring(Output, 0, PreviewCharacters)
| extend EvidencePreviewStatus=case(PreviewCharacters == 0, 'Metadata exhausted preview budget; inspect full query results',
strlen(Prompt) > PreviewCharacters or strlen(Output) > PreviewCharacters, 'Inline evidence; previews shortened; full text in query results',
isempty(Prompt) and isempty(Output), 'No prompt/output captured or parsed; not a protection verdict',
'Inline evidence; full recorded text in query results')
| project TimeGenerated, ResourceId, Agent, AgentId, AgentKey, AppRoleName,
TraceId, SpanId, Conversation, Model, Tool, TargetHost, ServerDisplay,
Signal, EventCount, SuccessfulCalls, FailedCalls, Prompt, Output, ToolArguments, ToolResult, InputMessages, OutputMessages,
EvidenceSource, PromptEvidenceOrigin, OutputEvidenceOrigin, PromptEvidenceSpanId, OutputEvidenceSpanId,
InputParseState, OutputParseState, ToolArgumentsState, ToolResultState,
PromptPreview, OutputPreview, EvidencePreviewStatus, TriggerSpanId, TriggerTime, TriggerTool, TriggerToolResult,
TriggerServerDisplay, TriggerTargetHost, RiskyOutputKind, RelatedToolResults
| order by TimeGenerated descExplanation
This query is a scheduled alert rule designed to monitor and flag specific network activities related to internal or metadata targets. Here's a simplified breakdown:
-
Purpose: The query identifies and flags network requests made by custom agents to internal or metadata destinations. These destinations include private IP addresses, loopback addresses, and specific local names like 'localhost' or 'metadata.google.internal'.
-
Severity: The alert is classified as "Medium" severity, indicating a moderate level of concern.
-
Data Sources: It uses data from Application Insights, specifically the "AppRequests" and "AppDependencies" data types.
-
Frequency and Duration: The query runs every hour and looks back over the past 14 days.
-
Trigger Conditions: The alert triggers if there is any matching activity (i.e., more than 0 occurrences).
-
Query Logic:
- It first gathers evidence from custom agent data.
- It filters out certain classifications and checks if the target host is a tool and not empty.
- It then checks if the target host is within specific IP ranges or matches certain local names.
- If a match is found, it extends the data with additional information like signal, event count, and success/failure of calls.
- It projects and organizes the relevant data fields for further analysis.
- It joins with additional evidence data to enrich the results.
- It creates previews of prompts and outputs for quick inspection.
-
Output: The results are ordered by the time they were generated, and they include detailed information about the agent, target host, and any associated evidence.
-
Entity Mappings: The query maps certain fields to Azure resources and cloud applications for better integration with Azure Sentinel.
-
Custom Details and Grouping: It includes custom details for alerts and groups incidents based on specific criteria to manage and track them effectively.
-
Version and Tags: The query is versioned (1.2.0) and tagged for categorization and identification within the system.
Overall, this query helps in monitoring and identifying potentially suspicious internal network activities by custom agents, providing insights for further investigation.