Recently I have come across a situation where I need to install Sysmon on a Linux virtual machine in Azure subscription and analyze those logs in Log analytics workspace. This post is a quick guide to help installing Sysmon and analyzing logs using Kusto query language.
Prerequisites to install Sysmon for Linux
- Ensure the Linux virtual machine is on boarded to Log analytics workspace.
- Collect Syslog events with Azure Monitor Agent. Install using this
Installing Sysmon on Linux
For complete installation process on various .nix operating systems, follow Sysmon installation instructions here
Ubuntu 20.04 & 22.04
- Register Microsoft key and feed
- wget -q https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
- sudo dpkg -i packages-microsoft-prod.deb
- Install SysmonForLinux
- sudo apt-get update
- sudo apt-get install sysmonforlinux
The Kusto query to parse the Sysmon logs on a Linux can be found here.
let Eventlogs = materialize (Syslog
| where SyslogMessage has "Linux-Sysmon"
| extend Data =parse_xml(SyslogMessage)
| extend System = Data.Event.System, EventDetail=Data.Event.EventData.Data
| extend Provider = tostring(System.Provider.["@Name"]), EventID = toint(System.EventID)
| extend Operation = case(
EventID == 1,
"ProcessCreate. Log all newly created processes",
EventID == 3,
"NetworkConnect Detected. Log all network connections",
EventID == 5,
"ProcessTerminate. Log all processes terminated",
EventID == 9,
"RawAccessRead. Log all raw access read",
EventID == 10,
"ProcessAccess. Log all open process operations",
EventID == 11,
"FileCreate. Log every file creation",
EventID == 23,
"FileDelete. Log all files being deleted",
""
)
| project-away Data, System);
let Linux_SYSMON_CREATE_PROCESS_1=() {
let ProcessCreate = Eventlogs
| where EventID == 1
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
ProcessGuid = EventDetail.[2].["#text"],
ProcessId = EventDetail.[3].["#text"],
Image = EventDetail.[4].["#text"],
FileVersion = EventDetail.[5].["#text"],
Description = EventDetail.[6].["#text"],
Product = EventDetail.[7].["#text"],
Company = EventDetail.[8].["#text"],
OriginalFileName = EventDetail.[9].["#text"],
CommandLine = EventDetail.[10].["#text"],
CurrentDirectory = EventDetail.[11].["#text"],
User = EventDetail.[12].["#text"],
LogonGuid = EventDetail.[13].["#text"],
LogonId = EventDetail.[14].["#text"],
TerminalSessionId = EventDetail.[15].["#text"],
IntegrityLevel = EventDetail.[16].["#text"],
Hashes = EventDetail.[17].["#text"],
ParentProcessGuid = EventDetail.[18].["#text"],
ParentProcessId = EventDetail.[19].["#text"],
ParentImage = EventDetail.[20].["#text"],
ParentCommandLine = EventDetail.[21].["#text"],
ParentUser=EventDetail.[22].["#text"]
| extend Hashes = extract_all(@"(?P<key>\w+)=(?P<value>[a-zA-Z0-9]+)", dynamic(["key", "value"]), tostring(Hashes))
| mv-apply Hashes on (
summarize ParsedHashes = make_bag(pack(tostring(Hashes[0]), tostring(Hashes[1])))
)
| project-away EventDetail, SyslogMessage;
ProcessCreate;
};
let Linux_SYSMON_NETWORK_CONNECT_3=() {
let processEvents = Eventlogs
| where EventID == 3
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
ProcessGuid = EventDetail.[2].["#text"],
ProcessId = EventDetail.[3].["#text"],
Image = EventDetail.[4].["#text"],
User = EventDetail.[5].["#text"],
Protocol = EventDetail.[6].["#text"],
Initiated = EventDetail.[7].["#text"],
SourceIsIpv6 = EventDetail.[8].["#text"],
SourceIp = EventDetail.[9].["#text"],
SourceHostname = EventDetail.[10].["#text"],
SourcePort = EventDetail.[11].["#text"],
SourcePortName = EventDetail.[12].["#text"],
DestinationIsIpv6 = EventDetail.[13].["#text"],
DestinationIp = EventDetail.[14].["#text"],
DestinationHostname = EventDetail.[15].["#text"],
DestinationPort = EventDetail.[16].["#text"],
DestinationPortName = EventDetail.[17].["#text"]
| project-away EventDetail, SyslogMessage;
processEvents;
};
let Linux_SYSMON_PROCESS_TERMINATE_5=() {
let processEvents = Eventlogs
| where EventID == 5
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
ProcessGuid = EventDetail.[2].["#text"],
ProcessId = EventDetail.[3].["#text"],
Image = EventDetail.[4].["#text"]
| project-away EventDetail, SyslogMessage;
processEvents;
};
let Linux_SYSMON_RAWACCESS_READ_9=() {
let processEvents = Eventlogs
| where EventID == 9
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
ProcessGuid = EventDetail.[2].["#text"],
ProcessId = EventDetail.[3].["#text"],
Image = EventDetail.[4].["#text"],
Device = EventDetail.[5].["#text"]
| project-away EventDetail, SyslogMessage;
processEvents;
};
let linunx_SYSMON_ACCESS_PROCESS_10=() {
let processEvents = Eventlogs
| where EventID == 10
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
SourceProcessGUID = EventDetail.[2].["#text"],
SourceProcessId = EventDetail.[3].["#text"],
SourceThreadId = EventDetail.[4].["#text"],
SourceImage = EventDetail.[5].["#text"],
TargetProcessGUID = EventDetail.[6].["#text"],
TargetProcessId = EventDetail.[7].["#text"],
TargetImage = EventDetail.[8].["#text"],
GrantedAccess = EventDetail.[9].["#text"],
CallTrace = EventDetail.[10].["#text"]
| project-away EventDetail, SyslogMessage;
processEvents;
};
let linux_SYSMON_FILE_CREATE_11=() {
let processEvents = Eventlogs
| where EventID == 11
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
ProcessGuid = EventDetail.[2].["#text"],
ProcessId = EventDetail.[3].["#text"],
Image = EventDetail.[4].["#text"],
TargetFilename = EventDetail.[5].["#text"],
CreationUtcTime = EventDetail.[6].["#text"]
| project-away EventDetail, SyslogMessage;
processEvents;
};
let Linux_SYSMON_FILE_DELETE_23=() {
let processEvents = Eventlogs
| where EventID == 23
| extend
RuleName = EventDetail.[0].["#text"],
UtcTime = EventDetail.[1].["#text"],
ProcessGuid = EventDetail.[2].["#text"],
ProcessId = EventDetail.[3].["#text"],
User = EventDetail.[4].["#text"],
Image = EventDetail.[5].["#text"],
TargetFilename = EventDetail.[6].["#text"],
Hashes = EventDetail.[7].["#text"],
IsExecutable = EventDetail.[8].["#text"],
Archived = EventDetail.[9].["#text"]
| extend Hashes = extract_all(@"(?P<key>\w+)=(?P<value>[a-zA-Z0-9]+)", dynamic(["key", "value"]), tostring(Hashes))
| mv-apply Hashes on (
summarize ParsedHashes = make_bag(pack(tostring(Hashes[0]), tostring(Hashes[1])))
)
| project-away EventDetail, SyslogMessage;
processEvents;
};
(union isfuzzy=true
Linux_SYSMON_CREATE_PROCESS_1,
Linux_SYSMON_NETWORK_CONNECT_3,
Linux_SYSMON_PROCESS_TERMINATE_5,
Linux_SYSMON_RAWACCESS_READ_9,
linunx_SYSMON_ACCESS_PROCESS_10,
linux_SYSMON_FILE_CREATE_11,
Linux_SYSMON_FILE_DELETE_23)
| extend
Details = column_ifexists("Details", ""),
RuleName = column_ifexists("RuleName", ""),
PreviousCreationUtcTime=column_ifexists("PreviousCreationUtcTime", ""),
Hashes = column_ifexists("Hashes", "")
| project
EventID,
UtcTime,
Description,
RuleName,
ProcessGuid,
ProcessId,
Image,
FileVersion,
Product,
Company,
OriginalFileName,
CommandLine,
CurrentDirectory,
User,
LogonGuid,
LogonId,
TerminalSessionId,
IntegrityLevel,
Hashes,
ParsedHashes,
ParentProcessGuid,
ParentProcessId,
ParentImage,
ParentCommandLine,
TargetFilename,
CreationUtcTime,
PreviousCreationUtcTime,
Protocol,
Initiated,
SourceIsIpv6,
SourceIp,
SourceHostname,
SourcePort,
SourcePortName,
DestinationIsIpv6,
DestinationIp,
DestinationHostname,
DestinationPort,
DestinationPortName,
SourceProcessId,
SourceImage,
TargetProcessId,
TargetImage,
Device,
SourceProcessGUID,
SourceThreadId,
TargetProcessGUID,
GrantedAccess,
CallTrace,
Details,
Operation,
Type,
IsExecutable,
Archived
References
- Collect Syslog events with Azure Monitor Agent - Azure Monitor | Microsoft Learn
- Sysinternals/SysmonForLinux (github.com)
- gist.githubusercontent.com/Cyb3rWard0g/bcf1514cc340197f0076bf1da8954077/raw/293db31bb81c48ff18a591574a6f2bf946282602/SysmonForLinux-CollectAll-Config.xml
- gist.githubusercontent.com/doreddy1/2d46a1e5644f047f7e8b4703c7c78a2d/raw/9ddb0988d78f629f441bdc2a9cc653c242619dce/SysmonForLinuxParser.kql
Comments
Post a Comment