From 096b88e3afb88b7051e40a15d9aa7111b1376a63 Mon Sep 17 00:00:00 2001 From: Marc Guasch Date: Thu, 14 May 2020 15:02:37 +0200 Subject: [PATCH] Improve ECS field mappings in Sysmon module. (#18381) - related.hash, related.ip, and related.user are now populated. - hashes are now also populated to the corresponding process.hash, process.pe.imphash, file.hash or file.pe.imphash - file.name, file.directory, and file.extension are now populated. - rule.name is populated for all events when present. Closes #18364 --- CHANGELOG.next.asciidoc | 4 + .../module/sysmon/config/winlogbeat-sysmon.js | 131 +++++++++++-- .../test/testdata/sysmon-11-filedelete.evtx | Bin 69632 -> 69632 bytes .../sysmon-11-filedelete.evtx.golden.json | 182 +++++++++++++++++- .../testdata/sysmon-9.01.evtx.golden.json | 151 +++++++++++++++ 5 files changed, 456 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 50bf403c838..f6956be45e0 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -46,6 +46,10 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d *Winlogbeat* - Add support to Sysmon file delete events (event ID 23). {issue}18094[18094] +- Improve ECS field mappings in Sysmon module. `related.hash`, `related.ip`, and `related.user` are now populated. {issue}18364[18364] +- Improve ECS field mappings in Sysmon module. Hashes are now also populated to the corresponding `process.hash`, `process.pe.imphash`, `file.hash`, or `file.pe.imphash`. {issue}18364[18364] +- Improve ECS field mappings in Sysmon module. `file.name`, `file.directory`, and `file.extension` are now populated. {issue}18364[18364] +- Improve ECS field mappings in Sysmon module. `rule.name` is populated for all events when present. {issue}18364[18364] *Functionbeat* diff --git a/x-pack/winlogbeat/module/sysmon/config/winlogbeat-sysmon.js b/x-pack/winlogbeat/module/sysmon/config/winlogbeat-sysmon.js index 8eea4b8a558..f7dac99a4e8 100644 --- a/x-pack/winlogbeat/module/sysmon/config/winlogbeat-sysmon.js +++ b/x-pack/winlogbeat/module/sysmon/config/winlogbeat-sysmon.js @@ -332,10 +332,21 @@ var sysmon = (function () { evt.Delete("user"); evt.Put("user.domain", userParts[0]); evt.Put("user.name", userParts[1]); + evt.AppendTo("related.user", userParts[1]); evt.Delete("winlog.event_data.User"); } }; + var setRuleName = function (evt) { + var ruleName = evt.Get("winlog.event_data.RuleName"); + if (!ruleName || ruleName === "-") { + return; + } + + evt.Put("rule.name", ruleName); + evt.Delete("winlog.event_data.RuleName"); + }; + var addNetworkDirection = function (evt) { switch (evt.Get("winlog.event_data.Initiated")) { case "true": @@ -361,7 +372,39 @@ var sysmon = (function () { evt.Delete("winlog.event_data.DestinationIsIpv6"); }; - var addHashes = function (evt, hashField) { + var setRelatedIP = function (evt) { + var sourceIP = evt.Get("source.ip"); + if (sourceIP) { + evt.AppendTo("related.ip", sourceIP); + } + + var destIP = evt.Get("destination.ip"); + if (destIP) { + evt.AppendTo("related.ip", destIP); + } + }; + + var getHashPath = function (namespace, hashKey) { + if (hashKey === "imphash") { + return namespace + ".pe.imphash"; + } + + return namespace + ".hash." + hashKey; + }; + + var emptyHashRegex = /^0*$/; + + var hashIsEmpty = function (value) { + if (!value) { + return true; + } + + return emptyHashRegex.test(value); + } + + // Adds hashes from the given hashField in the event to the 'hash' key + // in the specified namespace. It also adds all the hashes to 'related.hash'. + var addHashes = function (evt, namespace, hashField) { var hashes = evt.Get(hashField); evt.Delete(hashField); hashes.split(",").forEach(function (hash) { @@ -372,16 +415,31 @@ var sysmon = (function () { var key = parts[0].toLowerCase(); var value = parts[1].toLowerCase(); + + if (hashIsEmpty(value)) { + return; + } + + var path = getHashPath(namespace, key); + + evt.Put(path, value); + evt.AppendTo("related.hash", value); + + // TODO: remove in 8.0, see (https://github.com/elastic/beats/issues/18364). evt.Put("hash." + key, value); }); }; - var splitHashes = function (evt) { - addHashes(evt, "winlog.event_data.Hashes"); + var splitFileHashes = function (evt) { + addHashes(evt, "file", "winlog.event_data.Hashes"); }; - var splitHash = function (evt) { - addHashes(evt, "winlog.event_data.Hash"); + var splitFileHash = function (evt) { + addHashes(evt, "file", "winlog.event_data.Hash"); + }; + + var splitProcessHashes = function (evt) { + addHashes(evt, "process", "winlog.event_data.Hashes"); }; var removeEmptyEventData = function (evt) { @@ -477,6 +535,28 @@ var sysmon = (function () { evt.Put("file.code_signature.valid", signatureStatus === "Valid"); }; + var setAdditionalFileFieldsFromPath = function (evt) { + var filePath = evt.Get("file.path"); + if (!filePath) { + return; + } + + evt.Put("file.name", path.basename(filePath)); + evt.Put("file.directory", path.dirname(filePath)); + + // path returns extensions with a preceding ., e.g.: .tmp, .png + // according to ecs the expected format is without it, so we need to remove it. + var ext = path.extname(filePath); + if (!ext) { + return; + } + + if (ext.charAt(0) === ".") { + ext = ext.substr(1); + } + evt.Put("file.extension", ext); + }; + // https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-hives var commonRegistryHives = { HKEY_CLASSES_ROOT: "HKCR", @@ -606,10 +686,11 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setProcessNameUsingExe) .Add(splitProcessArgs) .Add(addUser) - .Add(splitHashes) + .Add(splitProcessHashes) .Add(setParentProcessNameUsingExe) .Add(splitParentProcessArgs) .Add(removeEmptyEventData) @@ -652,6 +733,8 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) + .Add(setAdditionalFileFieldsFromPath) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -727,6 +810,8 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) + .Add(setRelatedIP) .Add(setProcessNameUsingExe) .Add(addUser) .Add(addNetworkDirection) @@ -792,6 +877,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -833,8 +919,10 @@ var sysmon = (function () { ], fail_on_error: false, }) + .Add(setRuleName) + .Add(setAdditionalFileFieldsFromPath) .Add(setAdditionalSignatureFields) - .Add(splitHashes) + .Add(splitFileHashes) .Add(removeEmptyEventData) .Build(); @@ -888,9 +976,11 @@ var sysmon = (function () { ], fail_on_error: false, }) + .Add(setRuleName) + .Add(setAdditionalFileFieldsFromPath) .Add(setAdditionalSignatureFields) .Add(setProcessNameUsingExe) - .Add(splitHashes) + .Add(splitFileHashes) .Add(removeEmptyEventData) .Build(); @@ -921,6 +1011,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -956,6 +1047,8 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) + .Add(setAdditionalFileFieldsFromPath) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -998,6 +1091,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -1039,6 +1133,8 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) + .Add(setAdditionalFileFieldsFromPath) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -1070,6 +1166,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setRegistryFields) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) @@ -1102,6 +1199,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setRegistryFields) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) @@ -1134,6 +1232,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setRegistryFields) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) @@ -1176,8 +1275,10 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) + .Add(setAdditionalFileFieldsFromPath) .Add(setProcessNameUsingExe) - .Add(splitHash) + .Add(splitFileHash) .Add(removeEmptyEventData) .Build(); @@ -1235,6 +1336,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -1276,6 +1378,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) .Build(); @@ -1294,6 +1397,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(addUser) .Add(removeEmptyEventData) .Build(); @@ -1316,6 +1420,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(addUser) .Add(setProcessNameUsingExe) .Add(removeEmptyEventData) @@ -1335,6 +1440,7 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(addUser) .Add(removeEmptyEventData) .Build(); @@ -1389,6 +1495,7 @@ var sysmon = (function () { field: "dns.question.name", target_field: "dns.question.registered_domain", }) + .Add(setRuleName) .Add(translateDnsQueryStatus) .Add(splitDnsQueryResults) .Add(setProcessNameUsingExe) @@ -1425,7 +1532,7 @@ var sysmon = (function () { }, { from: "winlog.event_data.TargetFilename", - to: "file.name", + to: "file.path", }, { from: "winlog.event_data.Image", @@ -1446,9 +1553,11 @@ var sysmon = (function () { ignore_missing: true, fail_on_error: false, }) + .Add(setRuleName) .Add(addUser) - .Add(splitHashes) + .Add(splitProcessHashes) .Add(setProcessNameUsingExe) + .Add(setAdditionalFileFieldsFromPath) .Add(removeEmptyEventData) .Build(); diff --git a/x-pack/winlogbeat/module/sysmon/test/testdata/sysmon-11-filedelete.evtx b/x-pack/winlogbeat/module/sysmon/test/testdata/sysmon-11-filedelete.evtx index 4258ea01dd7caab6fc52b32362eccf8777dc8098..d3a5da13484828b3249a7ac033995e4966a1d7b4 100644 GIT binary patch literal 69632 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