Custom Agents - Recorded exploit intent before command-capable MCP call
Custom Exploit Intent Mcp Command Chain
Query
let Evidence=materialize(CustomAgentInlineContent(1h));
let Intent=Evidence
| where UserText matches regex @'(?i)(remote code execution|reverse[_ -]?shell|metasploit|run_shell_command|vulnerabilities/exec|(execute|run).{0,40}(command|shell|powershell|terminal))'
| summarize arg_min(EventTime, UserText, SpanId) by _ResourceId, OperationId, AgentKey
| project _ResourceId, OperationId, AgentKey, IntentTime=EventTime, IntentPrompt=UserText, IntentSpanId=SpanId;
CustomAgentSpans(1h)
| where Classification !in ('Excluded managed platform', 'Unattributed GenAI') and HasLineage
| where IsTool and ExplicitMcp and CommandCapable
| join kind=inner Intent on _ResourceId, OperationId, AgentKey
| where EventTime between (IntentTime .. IntentTime + 10m)
| summarize EventCount=count(), SuccessfulCalls=countif(Success == true),
FailedCalls=countif(Success == false), arg_min(EventTime, *)
by _ResourceId, OperationId, AgentKey
| extend Signal='Recorded user intent before observed tool span; 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 designed to detect potential security threats by analyzing data from custom agents in an application. Here's a simplified breakdown of what it does:
-
Purpose: The query aims to identify instances where a user attempts to exploit or execute commands, followed by a command-capable action within the same resource, agent, and trace, within a ten-minute window. This helps in detecting suspicious activities that might indicate an attempted security breach.
-
Data Sources: It uses data from Application Insights, specifically focusing on application requests and dependencies.
-
Process:
- Evidence Collection: It first collects evidence of user actions that match certain patterns indicative of exploit attempts (e.g., phrases related to remote code execution or shell commands).
- Intent Identification: It identifies these intents and records the time and details of these actions.
- Command Detection: It then looks for command-capable actions that occur shortly after these intents, within the same context (resource, agent, trace).
- Correlation: The query correlates these two events to see if they form a suspicious sequence.
-
Output: The query generates a report detailing:
- The number of events detected.
- Successful and failed command attempts.
- A signal indicating the detection of user intent before a tool's action.
- Various metadata about the detected events, including previews of the prompts and outputs.
-
Alerting: If any such sequences are detected, the system can create an alert. These alerts are grouped by specific entities to avoid duplication and ensure clarity.
-
Configuration: The query is scheduled to run every hour and looks back over the past 14 days of data. It is currently set to not be enabled by default.
-
Severity and Tags: The severity of the detected events is marked as "High," and the query is tagged for easy identification and categorization.
Overall, this query is part of a security monitoring setup that helps in identifying potential threats by correlating user actions with subsequent command-capable actions in a cloud environment.