
Struts2とPowerShellを使用してCVE-2017-5638 OGNL Injection脆弱性を再現する。
このリポジトリは、SC3010 コンピュータセキュリティコースプロジェクトの一部です。
CVE-2017-5638 を再現します。これは Apache Struts 2(バージョン 2.3.5~2.3.31 および 2.5~2.5.10)における重大なリモートコード実行(RCE)脆弱性であり、2017年の Equifax データ漏洩で悪用され、約1億4700万人分の個人記録が流出したことで有名です。
この脆弱性は、単一の設計上の欠陥に起因します:Apache Struts が multipart/form-data アップロードリクエストの解析に失敗したとき、サニタイズせずに生の Content-Type ヘッダーを文字列に埋め込み、その文字列が OGNL 式評価器に渡されることでエラーメッセージを構築します。攻撃者が Content-Type ヘッダー内に OGNL 式を仕込むと、それが Tomcat プロセスユーザーとしてサーバーサイドで実行されます。
このリポジトリには以下が含まれます:
SC3010-Computer-Security/
├── simulation/
│ ├── backend/ # 脆弱な Apache Struts2 2.3.28 サーバー(Java/Maven)
│ └── attack-script/ # CVE-2017-5638 向けエクスプロイトスクリプト
│ └── exploit_cve_2017_5638.ps1 # PowerShell(クロスプラットフォーム)
├── struts-src-code/ # Apache Struts2 参照ソース + 法的通知
│ ├── licenses/ # LICENSE、NOTICE、およびコンポーネントライセンス
│ └── src/
│ ├── struts2-core/ # リクエストパイプラインクラス + 脆弱な JakartaMultiPartRequest
│ ├── xwork2/ # ActionContext.java、OgnlUtil.java
│ └── ognl/ # OgnlContext.java
├── diagrams/ # 状態機械図 + シーケンス図、注釈付き OGNL ペイロード
└── _notes/ # 背景情報
以下の図は、Struts2 リクエストパイプラインの各分岐ポイントを示しています。赤い経路が攻撃者が強制する経路です。灰色の → ... の分岐は、エクスプロイト中には適用されない安全な経路です。
flowchart TD
Start([攻撃者が HTTP POST /upload.action を送信<br/>Content-Type: %{OGNL_PAYLOAD}.multipart/form-data])
Start --> PIPE
PIPE["<b>Struts2 フィルター → ラップ → パースパイプライン</b><br/>doFilter() → PrepareOperations.wrapRequest()<br/>→ Dispatcher.wrapRequest() → new MultiPartRequestWrapper()"]
PIPE --> D_CT{"Content-Type に<br/>"multipart/form-data" が含まれているか?"}
D_CT -- "いいえ → 通常のリクエスト ..." --> OUT_NORM([非アップロードパス ...])
D_CT -- "はい(攻撃者がペイロードに<br/>.multipart/form-data を追加)" --> PARSE
PARSE[/"<b>JakartaMultiPartRequest.parse()</b><br/>→ Commons FileUpload.parseRequest()"/]
PARSE --> D_VALID{"FileUpload が Content-Type を<br/>解析できるか?"}
D_VALID -- "はい → 通常のファイルアップロード ..." --> OUT_OK([ファイルが抽出され、アクションが実行される ...])
D_VALID -- "いいえ — 不正な Content-Type<br/>InvalidContentTypeException をスロー<br/>(メッセージ = 生の Content-Type 文字列)" --> CATCH
CATCH["parse() のキャッチブロック<br/>buildErrorMessage(e, {}) を呼び出す"]
CATCH --> FIND
FIND[/"<b>buildErrorMessage()</b><br/>→ LocalizedTextUtil.findText(class, errorKey, locale, e.getMessage(), args)"/]
FIND --> D_KEY{"リソースバンドルにキー<br/>struts.messages.upload.error.* が存在するか?"}
D_KEY -- "はい → 安全なローカライズメッセージ ..." --> OUT_SAFE([エラーが安全に表示される ...])
D_KEY -- "いいえ — デフォルトとして<br/>e.getMessage() にフォールバック<br/>(攻撃者の生の Content-Type)" --> TRANSLATE
TRANSLATE["TextParseUtil.translateVariables()<br/>文字列をスキャンして %{...} 式を探す"]
TRANSLATE --> D_OGNL{"文字列に<br/>%{...} OGNL 式が含まれているか?"}
D_OGNL -- "いいえ → プレーンなエラー文字列 ..." --> OUT_PLAIN([安全なエラーメッセージ ...])
D_OGNL -- "はい — 攻撃者のコンテンツ内の<br/>OGNL を評価" --> SANDBOX
SANDBOX[/"<b>OGNL サンドボックス回避</b><br/>#ognlUtil.getExcludedClasses().clear()<br/>#ognlUtil.getExcludedPackageNames().clear()"/]
SANDBOX --> ACCESS
ACCESS[/"<b>無制限のリフレクション</b><br/>#context.setMemberAccess(DEFAULT_MEMBER_ACCESS)"/]
ACCESS --> RCE
RCE[/"<b>RCE</b><br/>Runtime.getRuntime().exec(cmd)"/]
RCE --> Done([コマンドが Tomcat プロセスユーザーとして実行される])
style Start fill:#d32f2f,color:#fff
style Done fill:#d32f2f,color:#fff
style OUT_NORM fill:#9e9e9e,color:#fff
style OUT_OK fill:#9e9e9e,color:#fff
style OUT_SAFE fill:#9e9e9e,color:#fff
style OUT_PLAIN fill:#9e9e9e,color:#fff
style SANDBOX fill:#b71c1c,color:#fff
style ACCESS fill:#b71c1c,color:#fff
style RCE fill:#b71c1c,color:#fff
style CATCH fill:#e65100,color:#fff
style TRANSLATE fill:#e65100,color:#fff分岐の説明付きの完全な状態機械については、diagrams/cve-2017-5638-state-machine.md を参照してください。
シーケンス図と注釈付き OGNL ペイロードの内訳については、diagrams/cve-2017-5638-attack-chain.md を参照してください。
このリポジトリは、学術的なセキュリティ研究目的で Apache Struts 2.3.28 ソースコードの一部を再現しています。
Apache Struts は Copyright © 2000–2016 The Apache Software Foundation です。
Apache License, Version 2.0 の下でライセンスされています。
ライセンスのコピーはstruts-src-code/licenses/LICENSE.txtにあります。
Apache License で要求される完全な帰属表示はstruts-src-code/licenses/NOTICE.txtにあります。
Apache Struts 2 は追加のサードパーティコンポーネントをバンドルしており、それぞれが独自のライセンスに従います:
| コンポーネント | ライセンスファイル |
|---|---|
| OGNL (Object-Graph Navigation Library) | struts-src-code/licenses/OGNL-LICENSE.txt |
| XWork | struts-src-code/licenses/XWORK-LICENSE.txt |
| FreeMarker | struts-src-code/licenses/FREEMARKER-LICENSE.txt |