
CVE-2021-21239 のエクスプロイト: pysaml2/Redash における SAML署名検証バイパス。埋め込まれた公開鍵を使用してSAML応答を偽造し、JITプロビジョニングを介してユーザーになりすまし、権限を昇格させる。
Security Assertion Markup Language (SAML) は、フェデレーション ID システムにおいて、認証および認可データを当事者間で交換するためのオープン標準です。これにより、ドメインを越えたシングルサインオン(SSO)が可能になります。主要な構成要素は次のとおりです。
典型的な SAML フローでは、SP がユーザーを IdP にリダイレクトして認証を行います。IdP はユーザーに関するアサーション(例:メール、名前)を含む署名済みの SAML 応答を返します。SP は署名を検証し、ユーザーをプロビジョニングまたはログインさせます。
CVE-2021-21239 は、Redash <=10.1.0 が SAML SSO に使用する pysaml2 ライブラリ(バージョン <6.5.0)における署名検証バイパスの脆弱性です。大まかに言うと、攻撃者が任意の埋め込み公開鍵を用いた SAML 応答を偽造でき、Just-In-Time(JIT)プロビジョニングを介してユーザーになりすまし、権限昇格を可能にします。
この脆弱性は、pysaml2 が xmlsec1 を呼び出して SAML 署名を検証する方法に起因します。Xmlsec1 はデフォルトで、設定された IdP 証明書よりも SAML 応答の <ds:KeyInfo> に埋め込まれた公開鍵を優先します。攻撃者は自己生成の RSA 鍵ペアを用いて SAML 応答を作成し、公開鍵を <ds:RSAKeyValue> に埋め込み、秘密鍵でアサーションに署名することができます。pysaml2 が信頼された IdP 証明書のみを使用するように xmlsec1 を制限しないため、偽造された署名が有効とみなされ、攻撃者は任意のユーザー(例:管理者)としてログインし、最高権限を取得できます。
コードレベルでは、脆弱性は pysaml2 の sigver.py(check_signature 関数)に存在します。xmlsec1 コマンドリストに --enabled-key-data raw-x509-cert オプションが欠如しており、xmlsec1 が信頼されていない埋め込み鍵を使用できるようになっています。
com_list = [
self.xmlsec, '--verify', '--enabled-reference-uris', 'empty,same-doc',
'--pubkey-cert-pem', cert_file_name,
'--id-attr:%s' % id_attr, node_name,
'--node-id', nodeid, '--output', output_file_name, xml_file_name
]
これにより、攻撃者が <saml:NameID> 内のメールを変更して任意のユーザーになりすます攻撃が可能になり、JIT プロビジョニングを利用します。
エクスプロイトをテストするために、Docker Compose を使用してローカルの Redash インスタンス(v10.1.0 以前)を立ち上げます。セットアップには、Google の IdP を用いた SAML SSO の設定が含まれます。
docker-compose up を実行します。REDASH_SAML_LOGIN_ENABLED=true、REDASH_SAML_METADATA_URL=...(Google IdP から))。このセットアップにより、Python スクリプトまたは Burp Suite を介して偽造された SAML 応答を送信し、権限昇格を検証できます。
脆弱性は、pysaml2 の xmlsec1 呼び出しが埋め込み鍵を検証に使用することを許可し、信頼された IdP 証明書をバイパスすることに起因します。攻撃者は RSA 鍵ペアを生成し、<ds:RSAKeyValue> に公開鍵を含む SAML 応答を作成し、属性(例:メールを管理者のものに)を変更し、アサーションに署名します。Xmlsec1 は埋め込み鍵を使用して検証し、有効とみなします。
修正は pysaml2 v6.5.0 で実装されました(初回コミット 2021年1月17日、src/saml2/sigver.py)。xmlsec1 コマンドリストが更新され、--enabled-key-data raw-x509-cert が追加され、検証が設定された IdP 証明書に制限されました。
com_list = [
self.xmlsec, '--verify', '--enabled-reference-uris', 'empty,same-doc',
'--pubkey-cert-pem', cert_file_name,
'--enabled-key-data', 'raw-x509-cert',
'--id-attr:%s' % id_attr, node_name,
'--node-id', nodeid, '--output', output_file_name, xml_file_name
]
これにより、信頼チェーンの検証が強制され、埋め込み鍵の使用が防止されます。Redash は後のバージョン(例:v11+)で pysaml2 をアップグレードすることで修正しました。脆弱性のあるバージョンは --insecure を使用していませんでした。バグは制限オプションの欠如でした。
エクスプロイトコードは cve-2021-21239.py に実装されています。この Python スクリプトは、Redash <=10.1.0 における CVE-2021-21239 を悪用するための SAML 応答の偽造を自動化し、JIT プロビジョニングによるユーザーなりすましと権限昇格を可能にします。このエクスプロイトは Google Workspace SAML IdP を対象としていますが、攻撃は他の IdP(keycloak)でもテストされています。スクリプトは以下の手順を実行します。
email="[email protected]")を持ちます。idpid を取得し、ターゲットの設定との互換性を確保します。SAMLResponseTempalte.xml)を使用します。動的な UTC タイムスタンプが 5 分の有効期間で生成され、Redash の検証を通過します。xmlsec ライブラリを使用して <saml:Assertion> 要素に RSA-SHA256 で署名し、脆弱性を悪用するために公開鍵を <ds:RSAKeyValue> に埋め込みます。/saml/callback?org_slug=default)に送信します。CVE-2021-21239 をエクスプロイトするには、Redash が JIT プロビジョニングで受け入れる偽造 SAML 応答を作成する必要がありました。主な困難とその回避方法は次のとおりです。
<ds:RSAKeyValue> に埋め込み、秘密鍵で署名することでバイパスしました。xmlsec1 バイナリは動作しましたが、Python の xmlsec ライブラリでは空白/正規化の問題によるダイジェスト不一致が発生しました。署名前に XML を一行にシリアライズ(etree.tostring(..., pretty_print=False))することで回避しました。NotOnOrAfter は拒否されたため、5 分の有効期間を持つ動的な UTC タイムスタンプを使用して回避しました。SAMLResponse を二重エンコードし、パースエラーが発生。生のフォームデータを送信することで回避しました。これらの課題は、脆弱性を効果的にエクスプロイトするために、正確な XML 操作と環境設定が必要であることを示しています。提供されたエクスプロイトコードはこれを実証し、SAML 応答を偽造してユーザーになりすまし、アクセスを獲得します。