diff --git a/packages/crowdstrike/changelog.yml b/packages/crowdstrike/changelog.yml index 00364fbad60..85267b69fce 100644 --- a/packages/crowdstrike/changelog.yml +++ b/packages/crowdstrike/changelog.yml @@ -1,4 +1,9 @@ # newer versions go on top +- version: "4.5.0" + changes: + - description: Map CommandHistory events to ECS process fields. + type: enhancement + link: https://github.com/elastic/integrations/pull/20285 - version: "4.4.0" changes: - description: >- diff --git a/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr-command-history.log b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr-command-history.log new file mode 100644 index 00000000000..d1694c09be3 --- /dev/null +++ b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr-command-history.log @@ -0,0 +1,2 @@ +{"event_simpleName":"CommandHistory","CommandHistory":"sc stop CSFalconService¶Stop-Service -Name CSFalconService -Force","FirstCommand":"0","CommandCountMax":"2","CommandCount":"2","CommandSequence":"1","LastDisplayed":"0","LastAdded":"0","TargetProcessId":"7292754410393","AuthenticationId":"2048391741","ConfigStateHash":"886310903","EffectiveTransmissionClass":"3","Entitlements":"15","EventOrigin":"1","LogonType":"10","UserName":"jdoe","aip":"81.2.69.144","aid":"b5c2f3e1d4a789102345678abcdef01","timestamp":"1752051389000","cid":"a1b2c3d4e5f67890abcdef1234567890","id":"a1b2c3d4e5f67890abcdef1234567890a1b2","event_platform":"Win","name":"CommandHistoryV5","ConfigBuild":"1007.3.0021003.10"} +{"event_simpleName":"CommandHistory","CommandHistory":"sc stop CSFalconService","FirstCommand":"0","CommandCountMax":"1","CommandCount":"1","CommandSequence":"1","LastDisplayed":"0","LastAdded":"0","TargetProcessId":"7292754410394","AuthenticationId":"2048391742","ConfigStateHash":"886310903","EffectiveTransmissionClass":"3","Entitlements":"15","EventOrigin":"1","LogonType":"2","UserName":"jdoe","aip":"81.2.69.144","aid":"b5c2f3e1d4a789102345678abcdef01","timestamp":"1752051390000","cid":"a1b2c3d4e5f67890abcdef1234567890","id":"b2c3d4e5f67890abcdef1234567890b2c3","event_platform":"Win","name":"CommandHistoryV5","ConfigBuild":"1007.3.0021003.10"} diff --git a/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr-command-history.log-expected.json b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr-command-history.log-expected.json new file mode 100644 index 00000000000..7ad50e61702 --- /dev/null +++ b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr-command-history.log-expected.json @@ -0,0 +1,195 @@ +{ + "expected": [ + { + "@timestamp": "2025-07-09T08:56:29.000Z", + "crowdstrike": { + "AuthenticationId": "2048391741", + "CommandCount": 2, + "CommandCountMax": 2, + "CommandHistory": [ + "sc stop CSFalconService", + "Stop-Service -Name CSFalconService -Force" + ], + "CommandSequence": "1", + "ConfigStateHash": "886310903", + "EffectiveTransmissionClass": "3", + "Entitlements": "15", + "EventOrigin": "1", + "FirstCommand": "0", + "LastAdded": "0", + "LastDisplayed": "0", + "LogonType": "10", + "cid": "a1b2c3d4e5f67890abcdef1234567890", + "event_simpleName": "CommandHistory", + "id": "a1b2c3d4e5f67890abcdef1234567890a1b2", + "name": "CommandHistoryV5" + }, + "device": { + "id": "b5c2f3e1d4a789102345678abcdef01" + }, + "event": { + "action": "CommandHistory", + "category": [ + "process" + ], + "created": "2025-07-09T08:56:29.000Z", + "id": "a1b2c3d4e5f67890abcdef1234567890a1b2|b5c2f3e1d4a789102345678abcdef01|a1b2c3d4e5f67890abcdef1234567890", + "kind": "event", + "original": "{\"event_simpleName\":\"CommandHistory\",\"CommandHistory\":\"sc stop CSFalconService¶Stop-Service -Name CSFalconService -Force\",\"FirstCommand\":\"0\",\"CommandCountMax\":\"2\",\"CommandCount\":\"2\",\"CommandSequence\":\"1\",\"LastDisplayed\":\"0\",\"LastAdded\":\"0\",\"TargetProcessId\":\"7292754410393\",\"AuthenticationId\":\"2048391741\",\"ConfigStateHash\":\"886310903\",\"EffectiveTransmissionClass\":\"3\",\"Entitlements\":\"15\",\"EventOrigin\":\"1\",\"LogonType\":\"10\",\"UserName\":\"jdoe\",\"aip\":\"81.2.69.144\",\"aid\":\"b5c2f3e1d4a789102345678abcdef01\",\"timestamp\":\"1752051389000\",\"cid\":\"a1b2c3d4e5f67890abcdef1234567890\",\"id\":\"a1b2c3d4e5f67890abcdef1234567890a1b2\",\"event_platform\":\"Win\",\"name\":\"CommandHistoryV5\",\"ConfigBuild\":\"1007.3.0021003.10\"}", + "outcome": "success", + "type": [ + "end", + "info" + ] + }, + "host": { + "id": "b5c2f3e1d4a789102345678abcdef01", + "os": { + "type": "windows" + } + }, + "observer": { + "address": [ + "81.2.69.144" + ], + "geo": { + "city_name": "London", + "continent_name": "Europe", + "country_iso_code": "GB", + "country_name": "United Kingdom", + "location": { + "lat": 51.5142, + "lon": -0.0931 + }, + "region_iso_code": "GB-ENG", + "region_name": "England" + }, + "ip": [ + "81.2.69.144" + ], + "serial_number": "b5c2f3e1d4a789102345678abcdef01", + "version": "1007.3.0021003.10" + }, + "process": { + "command_line": "sc stop CSFalconService¶Stop-Service -Name CSFalconService -Force", + "entity_id": "7292754410393", + "interactive": true, + "user": { + "name": "jdoe" + } + }, + "related": { + "hash": [ + "886310903" + ], + "ip": [ + "81.2.69.144" + ], + "user": [ + "jdoe" + ] + }, + "tags": [ + "preserve_original_event" + ], + "user": { + "name": "jdoe" + } + }, + { + "@timestamp": "2025-07-09T08:56:30.000Z", + "crowdstrike": { + "AuthenticationId": "2048391742", + "CommandCount": 1, + "CommandCountMax": 1, + "CommandHistory": [ + "sc stop CSFalconService" + ], + "CommandSequence": "1", + "ConfigStateHash": "886310903", + "EffectiveTransmissionClass": "3", + "Entitlements": "15", + "EventOrigin": "1", + "FirstCommand": "0", + "LastAdded": "0", + "LastDisplayed": "0", + "LogonType": "2", + "cid": "a1b2c3d4e5f67890abcdef1234567890", + "event_simpleName": "CommandHistory", + "id": "b2c3d4e5f67890abcdef1234567890b2c3", + "name": "CommandHistoryV5" + }, + "device": { + "id": "b5c2f3e1d4a789102345678abcdef01" + }, + "event": { + "action": "CommandHistory", + "category": [ + "process" + ], + "created": "2025-07-09T08:56:30.000Z", + "id": "b2c3d4e5f67890abcdef1234567890b2c3|b5c2f3e1d4a789102345678abcdef01|a1b2c3d4e5f67890abcdef1234567890", + "kind": "event", + "original": "{\"event_simpleName\":\"CommandHistory\",\"CommandHistory\":\"sc stop CSFalconService\",\"FirstCommand\":\"0\",\"CommandCountMax\":\"1\",\"CommandCount\":\"1\",\"CommandSequence\":\"1\",\"LastDisplayed\":\"0\",\"LastAdded\":\"0\",\"TargetProcessId\":\"7292754410394\",\"AuthenticationId\":\"2048391742\",\"ConfigStateHash\":\"886310903\",\"EffectiveTransmissionClass\":\"3\",\"Entitlements\":\"15\",\"EventOrigin\":\"1\",\"LogonType\":\"2\",\"UserName\":\"jdoe\",\"aip\":\"81.2.69.144\",\"aid\":\"b5c2f3e1d4a789102345678abcdef01\",\"timestamp\":\"1752051390000\",\"cid\":\"a1b2c3d4e5f67890abcdef1234567890\",\"id\":\"b2c3d4e5f67890abcdef1234567890b2c3\",\"event_platform\":\"Win\",\"name\":\"CommandHistoryV5\",\"ConfigBuild\":\"1007.3.0021003.10\"}", + "outcome": "success", + "type": [ + "end", + "info" + ] + }, + "host": { + "id": "b5c2f3e1d4a789102345678abcdef01", + "os": { + "type": "windows" + } + }, + "observer": { + "address": [ + "81.2.69.144" + ], + "geo": { + "city_name": "London", + "continent_name": "Europe", + "country_iso_code": "GB", + "country_name": "United Kingdom", + "location": { + "lat": 51.5142, + "lon": -0.0931 + }, + "region_iso_code": "GB-ENG", + "region_name": "England" + }, + "ip": [ + "81.2.69.144" + ], + "serial_number": "b5c2f3e1d4a789102345678abcdef01", + "version": "1007.3.0021003.10" + }, + "process": { + "command_line": "sc stop CSFalconService", + "entity_id": "7292754410394", + "interactive": true, + "user": { + "name": "jdoe" + } + }, + "related": { + "hash": [ + "886310903" + ], + "ip": [ + "81.2.69.144" + ], + "user": [ + "jdoe" + ] + }, + "tags": [ + "preserve_original_event" + ], + "user": { + "name": "jdoe" + } + } + ] +} diff --git a/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr.log-expected.json b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr.log-expected.json index aa10617169d..f064334c1de 100644 --- a/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr.log-expected.json +++ b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-fdr.log-expected.json @@ -8066,6 +8066,7 @@ }, "process": { "entity_id": "816054990879", + "interactive": false, "thread": { "id": 52913017705957 } @@ -8553,6 +8554,7 @@ }, "process": { "entity_id": "7073822473144", + "interactive": false, "pid": 744, "thread": { "id": 48689911139327 @@ -9365,6 +9367,7 @@ }, "process": { "entity_id": "30254389526587", + "interactive": false, "thread": { "id": 275230771323179 } diff --git a/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-windows.log-expected.json b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-windows.log-expected.json index e7fed4667d8..a15b9d6b2f6 100644 --- a/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-windows.log-expected.json +++ b/packages/crowdstrike/data_stream/fdr/_dev/test/pipeline/test-windows.log-expected.json @@ -388,7 +388,9 @@ "ApplicationName": "7371f07", "CommandCount": 3, "CommandCountMax": 983, - "CommandHistory": "41c56f9bd5471921f1ad5eb1eaa88bd7d4dcce1feb86682fa", + "CommandHistory": [ + "41c56f9bd5471921f1ad5eb1eaa88bd7d4dcce1feb86682fa" + ], "ConfigStateHash": "7040662006", "EffectiveTransmissionClass": "3", "Entitlements": "96", @@ -448,6 +450,7 @@ "version": "2c8b.4.bab7095.e6" }, "process": { + "command_line": "41c56f9bd5471921f1ad5eb1eaa88bd7d4dcce1feb86682fa", "entity_id": "3502200260267" }, "related": { @@ -6223,6 +6226,7 @@ "command_line": "82\\340d600\\4a6a0a4b\\4cdbc.exe", "entity_id": "25700434000", "executable": "\\6ba0bd\\257d4e13\\d598026\\dc9ec376\\4cdbc.exe", + "interactive": false, "name": "4cdbc.exe" }, "related": { @@ -8749,6 +8753,7 @@ }, "process": { "entity_id": "6990300009751", + "interactive": false, "thread": { "id": 95004910750900 } @@ -8955,6 +8960,7 @@ }, "process": { "entity_id": "3014546000418", + "interactive": false, "pid": 173, "thread": { "id": 610009300097503 @@ -9144,6 +9150,7 @@ }, "process": { "entity_id": "1776052010570", + "interactive": false, "thread": { "id": 500010382010308 } @@ -11942,6 +11949,7 @@ "command_line": "System", "entity_id": "21475403566", "executable": "System", + "interactive": true, "name": "System" }, "related": { diff --git a/packages/crowdstrike/data_stream/fdr/elasticsearch/ingest_pipeline/default.yml b/packages/crowdstrike/data_stream/fdr/elasticsearch/ingest_pipeline/default.yml index d9c3f02b6cb..9925932d287 100644 --- a/packages/crowdstrike/data_stream/fdr/elasticsearch/ingest_pipeline/default.yml +++ b/packages/crowdstrike/data_stream/fdr/elasticsearch/ingest_pipeline/default.yml @@ -1007,6 +1007,42 @@ processors: ctx.process.args = commandLineToArgv(ctx.process.command_line); ctx.process.args_count = ctx.process.args.length; + - script: + description: >- + Map the CommandHistory field to process.command_line and split into an + array at crowdstrike.CommandHistory. CrowdStrike uses U+00B6 PILCROW + SIGN (¶) as the delimiter between individual commands in the history + string; this character has no formal documentation from CrowdStrike but + is consistently observed in FDR CommandHistory events. + tag: script_command_history_to_process_command_line_8c3e1f92 + if: |- + ctx.crowdstrike?.event_simpleName == 'CommandHistory' && + ctx.crowdstrike?.CommandHistory instanceof String && + ctx.crowdstrike.CommandHistory != '' + source: |- + def history = ctx.crowdstrike.CommandHistory; + ctx.process = ctx.process ?: [:]; + ctx.process.command_line = history; + def parts = history.splitOnToken('¶'); + def commands = new ArrayList(); + for (def cmd : parts) { + def trimmed = cmd.trim(); + if (!trimmed.isEmpty()) { + commands.add(trimmed); + } + } + ctx.crowdstrike.CommandHistory = commands; + on_failure: + - append: + field: error.message + value: "Failed to parse CommandHistory: {{{_ingest.on_failure_message}}}" + - set: + tag: set_process_user_name_command_history_4e2a8f1c + description: Map crowdstrike.UserName to process.user.name for CommandHistory events. + if: ctx.crowdstrike?.event_simpleName == 'CommandHistory' && ctx.crowdstrike?.UserName instanceof String && ctx.crowdstrike.UserName != '' + field: process.user.name + copy_from: crowdstrike.UserName + ignore_empty_value: true - rename: tag: rename_crowdstrike_ImageFileName_to_process_executable_1e9d3140 if: ctx._temp?.isLibrary != true && ctx._temp?.isDriver != true @@ -3150,6 +3186,31 @@ processors: } } + - script: + tag: script_process_interactive_logon_type_9b3d6c7a + description: >- + Set process.interactive from crowdstrike.LogonType whenever a process + object is present in the event. Placed after all other process + processors so that any processor that creates a process object + (TargetProcessId, ContextProcessId, etc.) has already run. Logon types + 2 (Interactive), 10 (RemoteInteractive), 11 (CachedInteractive), and 12 + (CachedRemoteInteractive) indicate an interactive shell session; all + other types are non-interactive. + if: >- + ctx.crowdstrike?.LogonType instanceof String && + ctx.crowdstrike.LogonType != '' && + ctx.process != null + source: |- + // Logon type reference: 2=Interactive, 3=Network, 4=Batch, 5=Service, + // 7=Unlock, 8=NetworkCleartext, 9=NewCredentials, 10=RemoteInteractive, + // 11=CachedInteractive, 12=CachedRemoteInteractive, 13=CachedUnlock + def logonType = ctx.crowdstrike.LogonType; + ctx.process.interactive = (logonType == '2' || logonType == '10' || logonType == '11' || logonType == '12'); + on_failure: + - append: + field: error.message + value: "Failed to set process.interactive from LogonType: {{{_ingest.on_failure_message}}}" + # Cleanup. - remove: tag: remove_crowdstrike_event_platform_f15993d1 diff --git a/packages/crowdstrike/data_stream/fdr/fields/ecs.yml b/packages/crowdstrike/data_stream/fdr/fields/ecs.yml index ff128413738..f624ecf137c 100644 --- a/packages/crowdstrike/data_stream/fdr/fields/ecs.yml +++ b/packages/crowdstrike/data_stream/fdr/fields/ecs.yml @@ -163,6 +163,8 @@ name: process.hash.md5 - external: ecs name: process.hash.sha256 +- external: ecs + name: process.interactive - external: ecs name: process.parent.entity_id - external: ecs @@ -179,6 +181,8 @@ name: process.title - external: ecs name: process.uptime +- external: ecs + name: process.user.name - external: ecs name: related.hash - external: ecs diff --git a/packages/crowdstrike/data_stream/fdr/fields/fields.yml b/packages/crowdstrike/data_stream/fdr/fields/fields.yml index 11218e21ca4..8aac6ffca0a 100644 --- a/packages/crowdstrike/data_stream/fdr/fields/fields.yml +++ b/packages/crowdstrike/data_stream/fdr/fields/fields.yml @@ -229,6 +229,8 @@ multi_fields: - name: text type: match_only_text + - name: CommandSequence + type: match_only_text - name: CompletionEventId type: keyword - name: CompositeId diff --git a/packages/crowdstrike/docs/README.md b/packages/crowdstrike/docs/README.md index b5cbd13df6d..a06fa54869c 100644 --- a/packages/crowdstrike/docs/README.md +++ b/packages/crowdstrike/docs/README.md @@ -1965,6 +1965,7 @@ An example event for `fdr` looks as following: | crowdstrike.CommandCountMax | | match_only_text | | crowdstrike.CommandHistory | | keyword | | crowdstrike.CommandHistory.text | Multi-field of `crowdstrike.CommandHistory`. | match_only_text | +| crowdstrike.CommandSequence | | match_only_text | | crowdstrike.CompanyName | | keyword | | crowdstrike.CompletionEventId | | keyword | | crowdstrike.CompositeId | Global unique identifier that identifies a unique alert. | keyword | @@ -3162,6 +3163,7 @@ An example event for `fdr` looks as following: | process.group.id | | keyword | | process.hash.md5 | MD5 hash. | keyword | | process.hash.sha256 | SHA256 hash. | keyword | +| process.interactive | Whether the process is connected to an interactive shell. Process interactivity is inferred from the processes file descriptors. If the character device for the controlling tty is the same as stdin and stderr for the process, the process is considered interactive. Note: A non-interactive process can belong to an interactive session and is simply one that does not have open file descriptors reading the controlling TTY on FD 0 (stdin) or writing to the controlling TTY on FD 2 (stderr). A backgrounded process is still considered interactive if stdin and stderr are connected to the controlling TTY. | boolean | | process.name | Process name. Sometimes called program name or similar. | keyword | | process.name.caseless | Multi-field of `process.name`. | keyword | | process.name.text | Multi-field of `process.name`. | match_only_text | @@ -3175,6 +3177,8 @@ An example event for `fdr` looks as following: | process.title | Process title. The proctitle, some times the same as process name. Can also be different: for example a browser setting its title to the web page currently opened. | keyword | | process.title.text | Multi-field of `process.title`. | match_only_text | | process.uptime | Seconds the process has been up. | long | +| process.user.name | Short name or login of the user. | keyword | +| process.user.name.text | Multi-field of `process.user.name`. | match_only_text | | related.hash | All the hashes seen on your event. Populating this field, then using it to search for hashes can help in situations where you're unsure what the hash algorithm is (and therefore which key name to search). | keyword | | related.hosts | All hostnames or other host identifiers seen on your event. Example identifiers include FQDNs, domain names, workstation names, or aliases. | keyword | | related.ip | All of the IPs seen on your event. | ip | diff --git a/packages/crowdstrike/manifest.yml b/packages/crowdstrike/manifest.yml index 91d994e852e..a1c176e7835 100644 --- a/packages/crowdstrike/manifest.yml +++ b/packages/crowdstrike/manifest.yml @@ -1,6 +1,6 @@ name: crowdstrike title: CrowdStrike -version: "4.4.0" +version: "4.5.0" description: Collect logs from Crowdstrike with Elastic Agent. type: integration format_version: "3.4.0"