[EDR Workflows] Add runscript from Microsoft Defender for Endpoint support to Response Console#222377
Conversation
|
/ci |
|
/ci |
|
/ci |
|
/ci |
|
/ci |
|
/ci |
|
/ci |
| ); | ||
|
|
||
| additionalData = { | ||
| output: { |
There was a problem hiding this comment.
Note for reviewers:
- this code is here as a temporary solution to help me verify if the value coming in is valid
- it will be refactored in a following PR that will address showing this value as a downloadable link in the response console
- possibly it won't be returned as
stdoutbut differently - more similar to how we do it ins1
@raqueltabuyo any opinion? I think you've played with Script picker recently, should we change the behavior to what @ashokaditya is suggesting? |
ashokaditya
left a comment
There was a problem hiding this comment.
Thanks for the changes with the schemas. the conditional schema needs a small update besides clean up of redundant schemas and type exports. Let me know if you need help with any of it.
I tested out the flow again with windows and ubuntu and everything works as expected. I'm still not seeing an OS icon for my VMs for some reason even after several hours. Not sure if there is a issue with the alert data that is being ingested via connectors.
| }); | ||
|
|
||
| describe('Common validation', () => { | ||
| it('should reject when no endpoint_ids are provided', () => { |
There was a problem hiding this comment.
Consider using it.each for tests that should cover both MDE and Crowdstrike.
| // export type RunScriptActionRequestBody = Omit<BaseRunScriptActionRequest, 'parameters'> & { | ||
| // parameters: | ||
| // | MSDefenderRunScriptActionRequestBody['parameters'] | ||
| // | CrowdStrikeRunScriptActionRequestBody['parameters']; | ||
| // }; |
There was a problem hiding this comment.
Should remove this before merging.
| return 'At least one of Raw, HostPath, or CloudFile must be provided'; | ||
| parameters: schema.oneOf([ | ||
| // CrowdStrike schema | ||
| schema.conditional( |
There was a problem hiding this comment.
The conditional schema should work like a nested ternary operator
boolean condition 1
? do something
: boolean 2
? do else
: never true `. So RunScriptActionRequestSchema should be something like this, where the next conditional check is nested within the outer one
export const RunScriptActionRequestSchema = {
body: schema.object({
...restBaseSchema,
parameters: schema.oneOf([
// CrowdStrike schema
schema.conditional(
schema.siblingRef('agent_type'),
'crowdstrike',
CrowdStrikeRunScriptActionRequestParamsSchema,
schema.conditional(
schema.siblingRef('agent_type'),
'microsoft_defender_endpoint',
// Microsoft Defender Endpoint schema
MSDefenderEndpointRunScriptActionRequestParamsSchema,
schema.never()
)
),
]),
}),
};| export type MSDefenderRunScriptActionRequestBody = TypeOf< | ||
| typeof MSDefenderEndpointRunScriptActionRequestSchema.body | ||
| >; | ||
| export type CrowdStrikeRunScriptActionRequestBody = TypeOf< | ||
| typeof CrowdStrikeRunScriptActionRequestSchema.body | ||
| >; |
There was a problem hiding this comment.
I think for both MS defend and Crowdstrike you just need parameter schemas. I don't see the base schema body being used anywhere. So essentially neither CrowdStrikeRunScriptActionRequestBody or MSDefenderRunScriptActionRequestBody can be removed.
You should instead export the type for MSDefenderEndpointRunScriptActionRequestParamsSchema and replace with MSDefenderRunScriptActionRequestBody['parameters'] where ever used. Same for CrowdStrikeRunScriptActionRequestBody['parameters']
| }, | ||
| }); | ||
| }).toThrow( | ||
| '[parameters.1.scriptName]: expected value of type [string] but got [undefined]' |
There was a problem hiding this comment.
That error looks odd. I think it is because the parameters conditional check is not nested correctly.
| parameters: {}, | ||
| }); | ||
| }).toThrow( | ||
| '[parameters.1.scriptName]: expected value of type [string] but got [undefined]' |
There was a problem hiding this comment.
Same here. schema.conditonal should be nested. See my earlier comment.
| scriptName: NonEmptyString, | ||
| args: schema.maybe(NonEmptyString), |
There was a problem hiding this comment.
You can't use the NonEmptyString schema for MDE here cause the error thrown by it is specific to CS parameter schema.
| it('should accept optional comment field', () => { | ||
| expect(() => { | ||
| RunScriptActionRequestSchema.body.validate({ | ||
| endpoint_ids: ['endpoint_id'], | ||
| agent_type: 'crowdstrike', | ||
| parameters: { | ||
| raw: 'Get-Process', | ||
| }, | ||
| comment: 'Running process enumeration', | ||
| }); | ||
| }).not.toThrow(); | ||
| }); | ||
|
|
||
| it('should accept optional case_ids field', () => { | ||
| expect(() => { | ||
| RunScriptActionRequestSchema.body.validate({ | ||
| endpoint_ids: ['endpoint_id'], | ||
| agent_type: 'crowdstrike', | ||
| parameters: { | ||
| raw: 'Get-Process', | ||
| }, | ||
| case_ids: ['case-id-1', 'case-id-2'], | ||
| }); | ||
| }).not.toThrow(); | ||
| }); | ||
|
|
||
| it('should accept optional alert_ids field', () => { |
There was a problem hiding this comment.
These three tests look agent specific cause of the parameters.raw or parameters.scriptName values. You can make a copy of each within the agent type specific scopes above.
There was a problem hiding this comment.
Moved them to CS 👍
|
Thanks @ashokaditya, again good comments — I applied all of them, let me know what you think 👍 |
ashokaditya
left a comment
There was a problem hiding this comment.
Thanks for all the changes! I'm approving so this can be merged after another review. Do remember to remove the redundant tests as I mentioned.
I still think that the script picker UX needs improvement and would frustrate users with its current behaviour.
| } | ||
| }, | ||
| }); | ||
| const getNonEmptyString = (fieldName: string) => |
|
|
||
| // Microsoft Defender Endpoint schemas | ||
| const MSDefenderEndpointRunScriptActionRequestParamsSchema = schema.object({ | ||
| export const MSDefenderEndpointRunScriptActionRequestParamsSchema = schema.object({ |
There was a problem hiding this comment.
No need to rename this yet. Or rename it later when we might use a params schema for newer MDE actions.
There was a problem hiding this comment.
Hmm, it was not renamed, just the export added, right?
| endpoint_ids: ['endpoint_id'], | ||
| agent_type: 'crowdstrike' as const, | ||
| }; | ||
| describe('Common fields validation', () => { |
There was a problem hiding this comment.
You can actually remove the entire common fields validation as it is already tested above for the base schema. Let's keep CS, MDE schema specific test in here.
pmuellr
left a comment
There was a problem hiding this comment.
ResponseOps changes LGTM
💛 Build succeeded, but was flaky
Failed CI StepsMetrics [docs]Async chunks
Page load bundle
History
cc @tomsonpl |
|
Starting backport for target branches: 8.19 https://github.com/elastic/kibana/actions/runs/15729292273 |
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
…pport to Response Console (elastic#222377) (cherry picked from commit 18f606e) # Conflicts: # x-pack/solutions/security/plugins/security_solution/common/endpoint/types/microsoft_defender_endpoint.ts # x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts # x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/mocks.ts # x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/microsoft/defender/endpoint/mocks.ts # x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/microsoft/defender/endpoint/ms_defender_endpoint_actions_client.test.ts # x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/microsoft/defender/endpoint/ms_defender_endpoint_actions_client.ts
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |


Overview
This PR adds support for custom script execution functionality in the Microsoft Defender Endpoint (MDE) response actions client, including the ability to run scripts and retrieve custom script libraries.
Previous PRs
New Features
1. Run Script Action Support
runscript()scriptNameand optionalargsparametersRUN_SCRIPTsub-action to communicate with Microsoft Defender API2. Custom Scripts Library Management
getCustomScripts()GET_LIBRARY_FILESsub-actionCustomScriptsResponseformat3. Script Result Download Support
getFileInfo()andgetFileDownload()runscriptoutputsAWAITING_UPLOAD,READY)Technical Changes
Core Implementation (
ms_defender_endpoint_actions_client.ts)runscript()method with proper parameter validation and error handlinggetCustomScripts()method with response transformationprocessPendingActions()to handle script execution resultsProcessing MDE completion (
microsoft_defender_endpoint.ts)runscriptactions (unlikeisolate/releasewhich don't fetch results)File Download Support (
microsoft_defender_endpoint.ts)runscriptexecution results directly from Microsoft Defender EndpointgetFileInfo()– retrieves metadata and checks file availability status from response documentsgetFileDownload()– streams JSON output directly from Defender’s API using readable streamsAWAITING_UPLOAD,READYrunscript-output-{machineActionId}.jsonFeature Flag
microsoftDefenderEndpointRunScriptEnabledUI
Downloaded file example:
runscript-output-3887e24e-4185-493d-a139-1cf4fa6a106c.json
How to test
x-pack/solutions/security/plugins/security_solution/scripts/endpoint/run_microsoft_defender_host.jsto setup MDE env and generate alertrunscriptcommand through Response ConsoleCloses: https://github.com/elastic/security-team/issues/12318
Closes: https://github.com/elastic/security-team/issues/12350
Closes: https://github.com/elastic/security-team/issues/12319
Closes: https://github.com/elastic/security-team/issues/12320
Closes: https://github.com/elastic/security-team/issues/12417