Enhanced Windows Monitoring with Sysmon, Graylog and Winlogbeat

Samer Younes
6 min readMar 1, 2021

--

Overview

This article covers configuring Graylog’s Winlogbeat sidecar to process Sysmon events from the Windows event log and parse it into relevant fields that allow more detailed and actionable information to be extracted and viewed in a Graylog dashboard. It is meant to update the original article published on Graylog’s Blog but which contains an outdated pipeline script and some configuration options for newer Graylog deployments beyond version 3.2. The original article can be read by following this link.

Pre-requisties include a working Graylog deployment with a running Beats input endpoint, as well as a functioning Windows deployment to install and run Sysmon on.

Rationale for Sysmon

Monitoring Microsoft Windows deployments using the venerable Event Viewer can be tedious especially when having to deal with multiple deployments.

The stock events as well as the group policy and auditing events that can be enabled in Windows can also be helpful at the expense of log volume and frequency. Though thorough and comprehensive, some key aspects of the Windows subsystem still remain unchecked; enter Sysmon by Sysinternals.

Originally developed by Mark Russinovich as part of a set of Windows utilities, Sysmon is now an integral tool in the Microsoft arsenal with the latest iterations being co-developed with Thomas Garnier. Version 13 was released with a number new features that include among others a process image tampering event that reports when the mapped image of a process doesn’t match the on-disk image file, or the image file is locked for exclusive access. These indicators are triggered by process hollowing and process herpaderping.

Sysmon is meant to complement the Windows logging subsystem not replace it, though it does add a level of visibility that can be invaluable when diagnosing malware or other system instabilities.

The Sysmon driver though is as good as the configuration file used to run it. It is essential that it be customized to the environment and system(s) being monitored to provide essential event logs into the system’s performance and behavior. An excellent and comprehensive starter config can be found in SwiftOnSecurity’s Git repo pre-configured for general-use case and with excellent in file comments that document the various modules, functions and effects.

Once the configuration file ready and Sysmon downloaded on the target system, installing and running using the desired file is as straightforward as running the following command from an elevated command prompt:

sysmon.exe -accepteula -i sysmonconfig-export.xml

This installs Sysmon as a service, that auto starts upon system reboot.

If any changes are made to the config file while Sysmon is running, the configuration can be updated on the fly through an elevated command prompt:

sysmon.exe -c sysmonconfig-export.xml

To uninstall Sysmon simply issue the following command from an elevated command prompt:

sysmon.exe -u

Winlogbeat Sidecar

As mentioned in the overview section, a working Graylog deployment with a functioning Beats input is needed in order to ingest the events generated by Sysmon on the target machine.

Starting with Graylog v3, the sidecar subsystem went through a complete overhaul; sidecar agents can now be managed directly from the Graylog server and push configurations to Windows clients from a centralized location offering ease of management and deployment.

The following assumes that the Windows machine already has a deployed sidecar being managed through Graylog. If not please have a look at Graylog’s documentation on how to go about that here.

The latest Graylog deployment (4.0.5 as of this writing) was used to run the configurations and transformations outlined in this article.

Below is a sample Winlogbeat configuration that can be deployed to the remote agent to collect Sysmon events from the Event Log:

# Needed for Graylog
fields_under_root: true
fields.collector_node_id: ${sidecar.nodeName}
fields.gl2_source_collector: ${sidecar.nodeId}
output.logstash:
hosts: ["[[Graylog Server IP Address]]:5044"]
path:
data: C:\Program Files\Graylog\sidecar\cache\winlogbeat\data
logs: C:\Program Files\Graylog\sidecar\logs
tags:
- windows
winlogbeat:
event_logs:
- name: Application
- name: System
- name: Security
- name: Microsoft-Windows-Sysmon/Operational

The above configuration uses the default event node name created by Sysmon “Microsoft-Windows-Sysmon/Operational”.

Graylog Pipelines — Where the magic happens

Now that Sysmon logs are being ingested into Graylog its time to do some pre-processing on the data being ingested in order to create actionable fields mapped to Sysmon in order to search, manipulate and display Sysmon specific data.

To do this, a pipeline needs to be created and associated with the Stream to which the beats input in Graylog was configured to write to. For a full read-up on Graylog pipelines follow this link.

Our pipeline will be composed of two Stages:

  • Stage 0: Renames specific Winlogbeat fields to Sysmon in order to distinguish them.
rule "Stage 0 Sysmon Cleanup"  when   // Only run for Sysmon messages  
has_field("winlogbeat_source_name") && $message.winlogbeat_source_name == "Microsoft-Windows-Sysmon"
then // Rename some fields to clean up rename_field("winlogbeat_computer_name", "sysmon_computer_name"); rename_field("winlogbeat_event_data_Image", "sysmon_data_process"); rename_field("winlogbeat_event_data_UtcTime", "sysmon_data_utc_time"); rename_field("winlogbeat_event_id", "sysmon_event_id"); rename_field("winlogbeat_level", "sysmon_data_level"); rename_field("winlogbeat_task", "sysmon_task"); rename_field("winlogbeat_event_data_User", "sysmon_data_user"); rename_field("winlogbeat_event_data_TargetFilename", "sysmon_data_file_created"); rename_field("winlogbeat_event_data_CreationUtcTime", "sysmon_data_file_created_time"); rename_field("winlogbeat_event_data_PreviousCreationUtcTime", "sysmon_data_file_created_time_previous"); rename_field("winlogbeat_user_name", "sysmon_data_user_name"); rename_field("winlogbeat_thread_id", "sysmon_thread_id"); rename_field("winlogbeat_user_domain", "sysmon_user_domain"); rename_field("winlogbeat_user_identifier", "sysmon_user_identifier"); rename_field("winlogbeat_user_type", "sysmon_user_type"); rename_field("winlogbeat_event_data_DestinationHostname", "sysmon_dns_lookup"); rename_field("winlogbeat_event_data_DestinationIp", "sysmon_dns_lookup_ip"); rename_field("winlogbeat_event_data_DestinationPort", "sysmon_dest_port"); rename_field("winlogbeat_event_data_DestinationPortName", "sysmon_dest_port_name"); rename_field("winlogbeat_event_data_Initiated", "sysmon_con_initiated"); rename_field("winlogbeat_event_data_Protocol", "sysmon_con_proto"); rename_field("winlogbeat_event_data_SourceHostname", "sysmon_src_name"); rename_field("winlogbeat_event_data_SourceIp", "sysmon_src_ip"); rename_field("winlogbeat_event_data_SourcePort", "sysmon_src_port"); rename_field("winlogbeat_event_data_SourcePortName", "sysmon_src_port_name"); rename_field("winlogbeat_event_data_CommandLine", "sysmon_cmd_event"); rename_field("winlogbeat_event_data_CurrentDirectory", "sysmon_cmd_location"); rename_field("winlogbeat_event_data_Hashes", "sysmon_cmd_hash"); rename_field("winlogbeat_event_data_IntegrityLevel", "sysmon_cmd_integrity"); rename_field("winlogbeat_event_data_LogonId", "sysmon_cmd_logon_id"); rename_field("winlogbeat_event_data_ParentCommandLine", "sysmon_cmd_parent_cmd"); rename_field("winlogbeat_event_data_ParentImage", "sysmon_cmd_parent_file"); rename_field("winlogbeat_event_data_ParentProcessId", "sysmon_cmd_parent_pid"); rename_field("winlogbeat_event_data_TerminalSessionId", "sysmon_cmd_terminal_pid"); rename_field("winlogbeat_event_data_LogonGuid", "sysmon_cmd_logon_guid"); rename_field("winlogbeat_event_data_ParentProcessGuid", "sysmon_cmd_parent_guid"); // Remove clutter.
let fix = regex("^\\{(\\S+)\\}$", to_string($message.winlogbeat_event_data_ProcessGuid)); set_field("sysmon_data_process_guid", to_string(fix["0"])); remove_field("winlogbeat_event_data_ProcessGuid");
let fix = regex("^\\{(\\S+)\\}$", to_string($message.winlogbeat_provider_guid)); set_field("sysmon_data_provider_gui", to_string(fix["0"])); remove_field("winlogbeat_provider_guid"); // Remove unwanted fields
remove_field("name");
remove_field("tags");
remove_field("type");
// Remove winlogbeats fields we don't need remove_field("winlogbeat_event_data_ProcessId"); remove_field("winlogbeat_log_name"); remove_field("winlogbeat_opcode"); remove_field("winlogbeat_process_id"); remove_field("winlogbeat_record_number"); remove_field("winlogbeat_source_name"); remove_field("winlogbeat_tags"); remove_field("winlogbeat_type"); remove_field("winlogbeat_version"); remove_field("winlogbeat_event_data_SourceIsIpv6"); remove_field("winlogbeat_event_data_DestinationIsIpv6"); end
  • Stage 1: Performs IP lookups and threat intel lookup using Graylog’s built-in threat-intel-lookup data adapter.
rule "Stage 1 Sysmon Threatintel"  when   // To save CPU cycles, only run if there is something to look up  has_field("ip")  then    // look up the requested DNS captured by sysmon   
// this will be the most fired rule
let sysmon_dns_lookup_intel = threat_intel_lookup_domain(to_string($message.query_domain), "sysmon_dns_lookup");
set_fields(sysmon_dns_lookup_intel);
// look up the ip from the DNS answer
// if we do not monitor the dns, then this might be nice to have let sysmon_lookup_ip_answer_intel = threat_intel_lookup_ip(to_string($message.query_answer), "sysmon_dns_lookup_ip"); set_fields(sysmon_lookup_ip_answer_intel);
// look up the requesting IP
// this is useful if dealing with non internal IPs
// so you know if your IP is seen as a problem let sysmon_src_ip_answer_intel = threat_intel_lookup_ip(to_string($message.query_answer), "sysmon_src_ip");
set_fields(sysmon_src_ip_answer_intel);
// WHOIS lookup. This is disabled by default. Enable and carefully watch latency and performance.
// let sysmon_dns_lookup_ip_whois = whois_lookup_ip(to_string($message.query_answer), "sysmon_dns_lookup_ip");
// set_fields(sysmon_dns_lookup_ip_whois);
end
  • Stage 1': adds a threat_indicated field if the threat intel from Stage 1 returns true.
rule "Stage 1' Sysmon Threatintel Inflate"  when   
// run only if one of the fields is true to_bool($message.src_threat_indicated) || to_bool($message.dst_threat_indicated)
then
// This is to make Graylog searches easy
// -- Enables searches like threat_indicated:true set_field("threat_indicated", true);
end

Thanks to apitest2 from the Graylog community for updating the Graylog pipeline rules to work.

Graylog Dashboard

By this stage log ingestion and pipeline transformations should be up and running. Given the frequency and volume of logs that may be generated by Sysmon, having a summary of key indicators is essential to pave the way to more in-depth investigations when needed.

Graylog dashboards provide a convenient space to present and visualize large volume of information using charts and data tables. This convenience also allows for quick data drill-down based on selected criteria.

The dashboard is a representation of specific fields combinations that represent meaningful actionable information. As such this can vary from one deployment to another depending on requirements and key indicators. The dashboard presented herein is but a sample but provides a solid starter to further explore.

For details on how to go about creating a dashboard refer to the following Graylog documentation here.

Here is a sample widget that shows the count of tasks monitored by Sysmon over a time span of 1 hour.

You can build a set of widgets relevant to your use case by leveraging Graylog’s search capabilities to produce a full fledged dashboard based on the newly created fields like the sample below:

Graylog Sysmon Dashboard

Conclusion

In this article we gave a quick overview of how to leverage the power of Sysmon events, ingest and transform them in Graylog and visually present the information in a meaningful dashboard that summarizes key indicators that are being monitored.

As mentioned in the introduction this is a rewrite of an existing article in Graylog’s blog dating back to 2017 which is now out of date. So i hope this article will help those getting started with Sysmon and Graylog to leverage the informational insights this combination provides.

--

--

Samer Younes
Samer Younes

Written by Samer Younes

IT Projects & Information Security Manager, MS Comp. Science

No responses yet