attacking-saml について
許可を得た SAML セキュリティ評価向けのスキルです。SSO メッセージとサービスプロバイダーの挙動を調べるテスターを対象に、アサーション検証の弱点、リプレイ、XML 解析の問題、関連する ID 偽造経路を扱います。
主な機能
- 01SAML メッセージのデコードと検査
- 02XML 署名ラッピングのテスト
- 03未署名アサーション処理の確認
- 04アサーションとリプレイ検証の評価
- 05SAML パーサーの XXE 検査
- 06証明書の信頼動作のテスト
活用シーン
- 01SAML ACS エンドポイントの評価
- 02署名検証とアサーション選択ロジックのテスト
- 03サービス間のアサーション再利用の確認
- 04XML 解析と証明書信頼の評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trilwu/ secskills --skill attacking-samlインストール後、Claude Code で/attacking-samlを入力して読み込まれたか確認します。
詳細
SAML への攻撃
SAML のセキュリティは XML 署名の検証にかかっていますが、XML 署名を正しく検証するのは非常に困難です。アサーションには署名されていますが、署名対象の要素、XML パーサーが読み取る内容、アプリケーションが最終的に信頼する内容は、まったく異なる場合があります。この隔たりが XML Signature Wrapping であり、暗号技術の印象以上に SAML で問題が頻発する理由です。
許可を得ているシステムに対してのみ実施してください。
使用する場合
- リクエストまたはリダイレクトに
SAMLRequestまたはSAMLResponseパラメーターが含まれている - Base64(リダイレクトバインディングの場合は DEFLATE も適用)をデコードすると、
<saml:Assertion>、<samlp:Response>、または<saml:Subject>を含む XML になる - 対象が
/saml/acs、/sso、/saml2/acs、または/Shibboleth.ssoのアサーションコンシューマーサービスエンドポイントを公開している - IdP 起点のログインで、事前の
AuthnRequestなしにアサーションが SP へ直接 POST される - フェデレーションで Okta、ADFS、PingFederate、Azure/Entra、Shibboleth、SimpleSAMLphp、または Keycloak が使われている
- 低権限のフェデレーションアカウントを管理しており、別の ID またはロールへのアクセスを目指している
使用しない場合
- SSO フローが OAuth 2.0 または OpenID Connect である(
code、id_token、access_token、/authorize、/.well-known/openid-configuration)—attacking-oauth-oidcを使用してください - トークンが署名済み XML ではなく JWT である(ドット区切りの
eyJ...)—attacking-jwtを使用してください - 対象範囲に SAML アーティファクトがない一般的な Web テスト —
testing-web-applicationsを使用してください - 侵害済みの AD FS サーバーまたはクラウドテナントを対象とする Golden SAMLで、すでにトークン署名鍵を保有している場合 — これは
attacking-entra-idで扱うテナント乗っ取りです - 署名プリミティブ自体の評価(SHA-1 と SHA-256 の比較、RSA 鍵長、正規化アルゴリズムの選択)—
reviewing-cryptographyを使用してください
デコードと検査
すべてはメッセージを読み取ることから始まります。ワイヤ形式はバインディングによって異なります。
# HTTP-Redirect binding: base64 then raw DEFLATE (no zlib header)
echo 'fVLLbtsw...' | base64 -d | python3 -c \
"import sys,zlib; sys.stdout.write(zlib.decompress(sys.stdin.buffer.read(),-15).decode())"
# HTTP-POST binding: plain base64, no deflate
echo 'PHNhbWxwOl...' | base64 -d | xmllint --format -
リダイレクトバインディングでは、ヘッダーなしの raw DEFLATE を使い、ウィンドウビットは -15 です。POST バインディングではデフレートは行いません。誤った方法を選ぶと意味不明なデータになります。両方試してください。
SAML Raider(Burp 拡張機能)は作業環境として最適です。ACS への POST をインターセプトし、XML を整形して表示し、IdP 証明書をインポートし、以下の署名ラッピング攻撃をワンクリックで実行できます。手作業を始める前にインストールしてください。
samltool.com(OneLogin の SAMLtool)はメッセージのデコードと再エンコードに使え、構造の理解に役立ちます。ただし、オフラインの参考用途に限ってください。稼働中の本番アサーションをサードパーティの Web サイトに貼り付けてはいけません。代わりに、上記のコマンドでデコードしてください。
まず次のフィールドを確認してください。これらが以降のすべての攻撃の基盤となります。
<ds:Signature>— どこに配置され、<ds:Reference URI="#...">が何を指しているか。これが攻撃の要です。<saml:Subject><saml:NameID>— アサートされている ID<saml:AttributeStatement>— ロール、グループ、メールアドレス、エンタイトルメント<saml:Conditions>—NotBefore、NotOnOrAfter、AudienceRestriction<saml:SubjectConfirmationData>—Recipient、NotOnOrAfter、InResponseTo- レスポンスエンベロープ上の
DestinationとIssuer
XML Signature Wrapping(XSW)
SAML の中核的な攻撃です。署名は暗号学的に有効ですが、署名チェッカーが引き続き受け入れる場所へ署名済み要素を移動させる一方で、アプリケーションのロジックには、攻撃者が制御する別の未署名アサーションを読み取らせます。検証側と利用側で、どの要素が信頼できるのかについて認識が食い違います。
代表的な 8 種類の亜種(Somorovsky ら)は、元の署名済みアサーションを移動する場所と、偽造したアサーションを挿入する場所によって異なります。
- XSW1 / XSW2 —
<Response>全体をラップします。署名は元のレスポンスを参照しつつ、偽造したレスポンスが処理されます。XSW2 では、署名の配置位置がエンベロープ形式ではありません。 - XSW3 / XSW4 — アサーションレベルの攻撃です。XSW3 では偽造したアサーションを署名済みアサーションの兄弟要素にし、XSW4 では署名済みアサーションを偽造したアサーションの内側にネストします。同一または重複する ID を使います。
- XSW5 / XSW6 — コピーしたアサーションで署名を囲み、参照が引き続き解決されるよう
ID属性を操作します。 - XSW7 / XSW8 — スキーマ検証が緩いラッパーに隠します。XSW7 では偽造したアサーションを
<Extensions>要素に配置し、XSW8 では元の署名済みアサーションを<Object>の中に埋め込み、検証は通るものの利用されないようにします。
# Attack in SAML Raider:
# 1. Intercept the ACS POST, select the signed assertion
# 2. Edit NameID / attributes in the assertion the app will read
# 3. Click XSW1..XSW8 in turn — each rebuilds the document layout
# 4. Forward; watch for a successful login as the forged identity
8 種類すべてを試してください。どれが機能するかは SP の XML ライブラリと、信頼するアサーションの選択方法に完全に依存します。予測する方法はないため、SP が安全だと結論づける前にすべての亜種を試してください。正当に取得したことのない NameID でログインに成功すれば、それが発見事項です。
未署名のアサーションと署名の削除
ラップ攻撃を試す前に、最も単純な不具合をテストしてください。SP は署名を検証しているでしょうか?
- 署名を削除する。
<ds:Signature>を完全に削除して転送します。署名が存在する場合にのみ検証する SP もあります。 - 署名を空にする。
SignatureValueまたはDigestValueを空にします。 - 誤った対象に署名する。 SP が一方しか確認しない場合、アサーションには署名せずレスポンスに署名する、またはその逆を試します。
- アルゴリズムをダウングレードする。 SP が想定されたアルゴリズムを固定していない場合、SHA-1 の
SignatureMethodや、さらにはmd5/何もしない方式を試します。
# xmlsec1 can tell you what a document's signature actually covers
xmlsec1 --verify --pubkey-cert-pem idp.crt --id-attr:ID Assertion response.xml
SP が署名を削除したアサーションや未署名のアサーションを受け入れる場合、暗号処理なしで ID を偽造できます。これは SAML で最も深刻な結果です。
アサーションの改ざん
アサーションを受け入れさせることができたら(署名の削除、未署名、または機能する XSW 亜種を介して)、アサーションの内容を書き換えます。
- NameID — 対象ユーザー(
admin@corp、別テナントのユーザーなど)に差し替えます。 - 属性 —
Role/Group/memberOfをadminに変更し、IdP が発行していないエンタイトルメント属性を追加し、SP でアカウント連携を発生させるためにemailを変更します。 - AudienceRestriction — SP が
<Audience>を確認しない場合、同じフェデレーション内の別の SP 向けに発行されたアサーションをここで再利用できます。 - NotOnOrAfter / NotBefore — 有効期間が広い、または確認されない場合、取得したアサーションを本来の有効期限が過ぎた後も再利用できます。
- InResponseTo — SP 起点フローでは、SP がレスポンスを自身の
AuthnRequestID に紐づけているかを確認します。紐づけていなければ、注入または再利用されたレスポンスが受け入れられます。
それぞれを個別にテストしてください。署名を検証していても、AudienceRestriction やリプレイ防止期間を無視する SP は、依然として完全に悪用可能です。
NameID へのコメント挿入
複数の SAML ライブラリで発生した正規化の不具合です(2018 年の Duo/python-saml/OneLogin 系の CVE)。XML のテキストノード処理と署名の正規化処理で、XML コメントがテキストノードを分割する方法が異なります。
<saml:NameID>[email protected]</saml:NameID>
署名は正規化された値(コメントを削除したり、ノードを連結したりする場合があります)に対して計算されますが、アプリケーションによるテキスト抽出ではコメントより前のノードだけが読み取られ、admin になります。そのため、[email protected](攻撃者が正当に所有するアカウント)宛てに有効な署名が付いたアサーションで、admin として認証されます。NameID や、アカウントのマッピングに使われる email/username 属性など、ID に関わるフィールドの中にコメントを挿入して試してください。
SAML パーサーを介した XXE
SP は、攻撃者が用意した XML をパーサーに渡します。外部エンティティが無効化されていない場合、ACS エンドポイントは XXE の攻撃対象になります。
<?xml version="1.0"?>
<!DOCTYPE samlp:Response [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response ...>...&xxe;...</samlp:Response>
帯域外 DTD(http://attacker/evil.dtd)を使って、ブラインドファイル読み取りや SP の内部ネットワークへの SSRF を実行します。パラメーターエンティティ、OOB によるデータ窃取、エラーベースの情報漏えいを含む手法全体については、exploiting-xxe を参照してください。SAML 固有のポイントは、アサーションがインジェクションポイントであり、ACS が認証なしでアクセスできることです。
証明書の偽造と自己署名証明書による再署名
SP が IdP の証明書をピン留めせず、代わりに <ds:KeyInfo> に埋め込まれた証明書をそのまま信頼したり、広範な CA バンドルに含まれる任意の証明書を受け入れたりする場合、実際の署名を削除し、自分の鍵で再署名して、その証明書をメッセージに含めることができます。
# Generate a key/cert and re-sign a tampered assertion
openssl req -x509 -newkey rsa:2048 -keyout evil.key -out evil.crt -days 30 -nodes -subj "/CN=idp"
xmlsec1 --sign --privkey-pem evil.key,evil.crt \
--id-attr:ID Assertion tampered.xml > forged.xml
SAML Raider を使えば、この操作を自動化できます。「Send Certificate」で証明書をインポートまたは生成し、編集したメッセージにその場で再署名します。偽造した自己署名アサーションが受け入れられた場合、SP はピン留めされた IdP 証明書ではなく、メッセージ自身に埋め込まれた鍵を信頼しているため、認証を完全に回避できます。
Recipient/Destination の混同と IdP 起点のリプレイ
- Recipient/Destination が検証されない。 SP が
SubjectConfirmationData内のRecipientやレスポンスのDestinationを無視する場合、ある SP で取得したアサーションを、同じ IdP を共有する別の SP で再利用できます。 - IdP 起点のリプレイ。 IdP 起点の SSO には紐付け対象となる
AuthnRequestがないため、InResponseToがなく、リプレイ防止の状態管理も行われないことがよくあります。有効な IdP 起点の POST を取得して再送すると、有効期間内であればそのまま再ログインできる可能性があります。ログ、リファラー、履歴に漏えいしたアサーションは、使用可能な認証情報になります。 - テナント間でのトークン再利用。 マルチテナントの SaaS では、テナント A 向けに発行されたアサーションが、テナント B の ACS でも受け入れられるか確認してください。
Golden SAML
これは侵入の糸口ではなく、最終段階です。IdP の秘密のトークン署名鍵(AD FS サーバーの証明書ストア、Azure/Entra のフェデレーション信頼、またはエクスポートされた IdP キーストアから窃取したもの)をすでに入手していれば、任意のユーザー、任意のロールに対する、完全に署名されたアサーションを無期限に偽造できます。認証情報も MFA も IdP とのやり取りも不要で、パスワードリセット後も有効です。
# With the stolen signing key, mint an assertion for any identity
xmlsec1 --sign --privkey-pem tokensigning.key,tokensigning.crt \
--id-attr:ID Assertion golden.xml > any-user.xml
鍵の入手はホストやテナントの侵害に関する作業であり、SAML メッセージに関する作業ではありません。この経路(AD FS のトークン署名証明書、DKM 鍵、またはクラウドフェデレーションシークレットの抽出)については、attacking-entra-id を参照してください。ここに戻るのは、偽造するアサーションを組み立てるときだけです。
退けるべき合理化
- 「アサーションには署名があるので、改ざんできません。」 署名ラッピングでは、アプリが別の要素を読み取る一方で、署名は有効なままです。署名されていることは、その署名対象が信頼されていることを意味しません。
- 「XSW1 が機能しなかったので、SP は安全です。」 8 種類のバリアントがあるのには理由があります。何らかの結論を出す前に、XSW1~XSW8 をすべて実行してください。
- 「署名は検証しています。確認しました。」 ある署名を検証することと、実際に使用するアサーションを検証することは同じではありません。また、署名がある場合にしか検証しない可能性があります。署名を削除してテストしてください。
- 「Audience/Recipient は単なるメタデータです。」 SP が
AudienceRestriction、Recipient、Destinationを強制しない場合、アサーションは SP やテナントをまたいでリプレイされます。 - 「コメントの件は見た目だけの問題です。」
[email protected]はadminとして認証されます。正規化の不一致は、アカウントの完全な乗っ取りにつながります。 - 「信頼できる IdP からの XML なので、XXE は問題になりません。」 ACS は信頼する前にバイト列を解析し、そのバイト列はあなたのブラウザーから送られます。つまり、信頼できないデータです。
- 「Golden SAML には秘密鍵が必要なので、対象外です。」 アサーションの偽造はここで扱う範囲です。鍵の漏えいを記録し、鍵の抽出は
attacking-entra-idに引き継いでください。影響を軽視しないでください。
ATT&CK の対象範囲
secskills-core/ttp-index.json から生成されます。このファイルを編集してから、
python3 scripts/sync_attack.py --write を実行してください。レポートで引用する前に、
現在の ATT&CK リリースに照らして ID を再確認してください。
認証情報アクセス(TA0006)
- T1606.002 SAML トークン —
attacking-entra-idも参照してください
これらに関する検出コンテンツ:engineering-detections。プロアクティブな検索:hunting-threats。侵害後の対応:responding-to-incidents。
参考資料
attacking-oauth-oidc— SSO フローが OAuth 2.0 / OpenID Connect の場合attacking-jwt— トークンが XML ではなく署名付き JWT の場合exploiting-xxe— ACS パーサーがシンクとなる場合の XXE 手法全般attacking-entra-id— AD FS サーバーまたはテナントの侵害を介した Golden SAMLtesting-web-applications— 関連する Web 手法reporting-security-findings— 署名回避およびリプレイの重大度- SAML Raider(Burp 拡張機能)、Burp Suite、xmlsec1、SAMLtool(samltool.com)