Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
szwarckonrad committed Dec 31, 2024
1 parent 7865d09 commit a692316
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ export type AssistantFeatureKey = keyof AssistantFeatures;
export const defaultAssistantFeatures = Object.freeze({
assistantModelEvaluation: false,
attackDiscoveryAlertFiltering: false,
defendInsights: false,
defendInsights: true,
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export const DefendInsightEvent = z.object({
* The value of the event
*/
value: z.string(),
/**
* The signature of the event
*/
signature: z.string().optional(),
});

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ components:
value:
description: The value of the event
type: string
signature:
description: The signature of the event
type: string

DefendInsightType:
description: The insight type (ie. incompatible_antivirus)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ export const WorkflowInsightsResults = ({
{insight.message}
</EuiText>
<EuiText size={'xs'} color={'subdued'}>
{item.entries[0].type === 'match' && item.entries[0].value}
{item.entries[0].field === 'process.executable.caseless' &&
item.entries[0].value}
</EuiText>
</EuiText>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const SIZE = 200;
export function getFileEventsQuery({ endpointIds }: { endpointIds: string[] }): SearchRequest {
return {
allow_no_indices: true,
fields: ['_id', 'agent.id', 'process.executable'],
fields: ['_id', 'agent.id', 'process.executable', 'process.code_signature.signing_id'],
query: {
bool: {
must: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,21 @@ export const DEFEND_INSIGHTS_TOOL: AssistantTool = Object.freeze({
outputParser: outputFixingParser,
});

// console.log(JSON.stringify(prompt, null, 2));

const query = getDefendInsightsPrompt({
type: insightType,
events: anonymizedEvents,
});
// console.log(JSON.stringify(query, null, 2));

const result = await answerFormattingChain.call({
query: getDefendInsightsPrompt({
type: insightType,
events: anonymizedEvents,
}),
query,
timeout: langChainTimeout,
});

// console.log(JSON.stringify(result, null, 2));

const insights: DefendInsight[] = result.records;

await securityWorkflowInsightsService.createFromDefendInsights(insights, request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export function getIncompatibleVirusOutputParser() {
.object({
id: z.string().describe('The event ID'),
endpointId: z.string().describe('The endpoint ID'),
signature: z
.string()
.optional()
.describe('The process.code_signature.signing_id value of the event, if present'),
value: z.string().describe('The process.executable value of the event'),
})
.array()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

export function getIncompatibleAntivirusPrompt({ events }: { events: string[] }): string {
return `You are an Elastic Security user tasked with analyzing file events from Elastic Security to identify antivirus processes. Only focus on detecting antivirus processes. Ignore processes that belong to Elastic Agent or Elastic Defend, that are not antivirus processes, or are typical processes built into the operating system. Accuracy is of the utmost importance, try to minimize false positives. Group the processes by the antivirus program, keeping track of the agent.id and _id associated to each of the individual events as endpointId and eventId respectively. If there are no events, ignore the group field. Escape backslashes to respect JSON validation. New lines must always be escaped with double backslashes, i.e. \\\\n to ensure valid JSON. Only return JSON output, as described above. Do not add any additional text to describe your output.
return `You are an Elastic Security user tasked with analyzing file events from Elastic Security to identify antivirus processes. Only focus on detecting antivirus processes. Ignore processes that belong to Elastic Agent or Elastic Defend, that are not antivirus processes, or are typical processes built into the operating system. Accuracy is of the utmost importance, try to minimize false positives. Group the processes by the antivirus program, keeping track of the agent.id and _id associated to each of the individual events as endpointId and eventId respectively. If there are no events, ignore the group field. If the process.code_signature.signing_id field is present in an event, set its value in the signature field. If the process.code_signature.signing_id field is absent, ignore the signature field. Escape backslashes to respect JSON validation. New lines must always be escaped with double backslashes, i.e. \\\\n to ensure valid JSON. Only return JSON output, as described above. Do not add any additional text to describe your output.
Use context from the following process events to provide insights:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ export async function buildIncompatibleAntivirusWorkflowInsights(
const osEndpointIdsMap = await groupEndpointIdsByOS(endpointIds, endpointMetadataService);
return defendInsights.flatMap((defendInsight: DefendInsight) => {
const filePaths = Array.from(new Set((defendInsight.events ?? []).map((event) => event.value)));
const signatures = Array.from(
new Set((defendInsight.events ?? []).map((event) => event.signature))
).filter(Boolean) as string[];

return Object.keys(osEndpointIdsMap).flatMap((os) =>
filePaths.map((filePath) => ({
return Object.keys(osEndpointIdsMap).flatMap((os) => {
const common = {
'@timestamp': currentTime,
// TODO add i18n support
message: 'Incompatible antiviruses detected',
Expand All @@ -57,32 +60,66 @@ export async function buildIncompatibleAntivirusWorkflowInsights(
timestamp: currentTime,
},
value: defendInsight.group,
metadata: {
notes: {
llm_model: apiConfig.model ?? '',
},
},
remediation: {
exception_list_items: [
{
list_id: ENDPOINT_ARTIFACT_LISTS.trustedApps.id,
name: defendInsight.group,
description: 'Suggested by Security Workflow Insights',
entries: [
{
field: 'process.executable.caseless',
operator: 'included',
type: 'match',
value: filePath,
},
],
entries: [],
// TODO add per policy support
tags: ['policy:all'],
os_types: [os as SupportedHostOsType],
},
],
},
metadata: {
notes: {
llm_model: apiConfig.model ?? '',
};
if (signatures.length) {
return signatures.map((signature) => ({
...common,
remediation: {
...common.remediation,
exception_list_items: [
{
...common.remediation.exception_list_items[0],
entries: [
{
field: os === 'macos' ? 'process.code_signature' : 'process.Ext.code_signature',
operator: 'included',
type: 'match',
value: signature,
},
],
},
],
},
},
}))
);
}));
} else {
return filePaths.map((filePath) => ({
...common,
remediation: {
...common.remediation,
exception_list_items: [
{
...common.remediation.exception_list_items[0],
entries: [
{
field: 'process.executable.caseless',
operator: 'included',
type: 'match',
value: filePath,
},
],
},
],
},
}));
}
});
});
}

0 comments on commit a692316

Please sign in to comment.