Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2021-21239 PoC — Idpy Pysaml2 数据伪造问题漏洞

Source
Associated Vulnerability
Title:Idpy Pysaml2 数据伪造问题漏洞 (CVE-2021-21239)
Description:Idpy Pysaml2是Idpy社区的一个基于Python的SAML服务器实现。 Idpy PySAML2 before 6.5.0 存在数据伪造问题漏洞,该漏洞源于加密签名验证错误。
Readme
# Technical Report on CVE-2021-21239: Redash SAML Authentication Vulnerability

## Introduction to SAML
Security Assertion Markup Language (SAML) is an open standard for exchanging authentication and authorization data between parties in a federated identity system. It enables single sign-on (SSO) across domains. The key components are:

- **Identity Provider (IdP)**: The service that authenticates the user and issues a SAML assertion (e.g., Google's SAML IdP). It signs the assertion with its private key to ensure integrity and authenticity.
- **Service Provider (SP)**: The application that relies on the IdP for authentication (e.g., Redash). The SP verifies the signature using the IdP's public key or certificate to trust the assertion.

In a typical SAML flow, the SP redirects the user to the IdP for authentication. The IdP returns a signed SAML response containing assertions about the user (e.g., email, name). The SP validates the signature and provisions or logs in the user.

## Vulnerability Explanation
CVE-2021-21239 is a signature validation bypass vulnerability in the pysaml2 library (versions <6.5.0), used by Redash <=10.1.0 for SAML SSO. At a high level, it allows an attacker to forge a SAML response with an arbitrary embedded public key, enabling user impersonation and privilege escalation via just-in-time (JIT) provisioning.

The vulnerability stems from how pysaml2 invokes `xmlsec1` to verify SAML signatures. `Xmlsec1`, by default, prefers embedded public keys in the SAML response's `<ds:KeyInfo>` over the configured IdP certificate. An attacker can craft a SAML response with a self-generated RSA key pair, embed the public key in `<ds:RSAKeyValue>`, and sign the assertion with the private key. Since pysaml2 does not restrict `xmlsec1` to use only the trusted IdP certificate, the forged signature is deemed valid, allowing the attacker to log in as any user (e.g., admin) and gain highest privileges.

At the code level, the vulnerability exists in pysaml2's `sigver.py` (check_signature function). The `xmlsec1` command list lacks the `--enabled-key-data raw-x509-cert` option, allowing `xmlsec1` to use untrusted embedded keys:

```python
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
]
```
This permits attacks where the attacker modifies the email in `<saml:NameID>` to impersonate any user, leveraging JIT provisioning.

## Setup for Testing the Exploit
To test the exploit, a local Redash instance (v10.1.0 or earlier) is spun up using Docker Compose. The setup involves configuring SAML SSO with Google's IdP:

- Install Redash via Docker Compose: Clone the Redash repository, checkout the vulnerable tag (e.g., v10.1.0), and run docker-compose up.
- Configure SAML in Redash's environment variables (e.g., REDASH_SAML_LOGIN_ENABLED=true, REDASH_SAML_METADATA_URL=... from Google's IdP).
- Use Google's SAML IdP for testing: Set up a Google Workspace SAML app with the Redash callback URL.
- Expose the local Redash instance to Google's IdP using Ngrok.

This setup allows testing the forged SAML response sent via a Python script or Burp Suite, verifying privilege escalation.

## Technical Explanation and Fix
The vulnerability arises because pysaml2's xmlsec1 invocation allows embedded keys to be used for verification, bypassing the trusted IdP certificate. An attacker generates an RSA key pair, crafts a SAML response with the public key in `<ds:RSAKeyValue>`, modifies attributes (e.g., email to admin's), and signs the assertion. `Xmlsec1` verifies using the embedded key, deeming it valid.
The fix was implemented in pysaml2 v6.5.0 ([initial commit](https://github.com/IdentityPython/pysaml2/commit/751dbf50a51131b13d55989395f9b115045f9737) on Jan 17, 2021) in `src/saml2/sigver.py`. The `xmlsec1` command list was updated to include `--enabled-key-data raw-x509-cert`, restricting verification to the configured IdP certificate:

```python
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
]
```

This enforces trust chain validation, preventing embedded key usage. Redash fixed this by upgrading pysaml2 in later versions (e.g., v11+). Vulnerable versions did not use `--insecure`; the bug was the missing restriction option.

## Exploit code
The exploit code is implemented in the `cve-2021-21239.py`. This Python script automates the process of forging a SAML response to exploit CVE-2021-21239 in Redash <=10.1.0, enabling user impersonation and privilege escalation via JIT provisioning. The exploit targets Google Workspace SAML IdP but the attack has been tested with other IdPs (`keycloak`). The script performs the following steps:

1. **Parses Command-Line Arguments**: Accepts inputs for the SAML template file, Redash URL, IdP ID, assertion ID, email, first name, and last name, with defaults for testing (e.g., `email="bill@microsoft.com"`).
2. **Resolves IdP ID**: Fetches the `idpid` from Redash’s SAML login endpoint if not provided, ensuring compatibility with the target’s configuration.
3. **Fills XML Template**: Uses a template (`SAMLResponseTempalte.xml`) with placeholders for email, names, timestamps, and assertion ID. Dynamic UTC timestamps are generated with a 5-minute validity window to pass Redash’s validation.
4. **Generates RSA Key Pair**: Creates a 2048-bit RSA private key for signing the SAML assertion.
5. **Signs the XML**: Uses the `xmlsec` Python library to sign the `<saml:Assertion>` element with RSA-SHA256, embedding the public key in `<ds:RSAKeyValue>` to exploit the vulnerability.
6. **Verifies the Signature**: Validates the signature, ensuring the forged SAML response is structurally valid.
7. **Sends the SAMLResponse**: Base64-encodes and URL-encodes the signed XML, sending it to Redash’s SAML callback endpoint (`/saml/callback?org_slug=default`).
8. **Extracts Session Cookie**: Retrieves the session cookie from the response, allowing the attacker to impersonate the target user.
9. **Lists Users**: Fetches the Redash user list with the user's group memberships. This allows to identify and target admin users.

## Difficulties in Exploiting and Bypassing Them
Exploiting CVE-2021-21239 required crafting a forged SAML response that Redash accepts via JIT provisioning. Key difficulties and bypasses:

- Signature Validation Bypass: Pysaml2 allowed embedded keys, bypassed by generating an RSA key pair and embedding the public key in `<ds:RSAKeyValue>`, signing with the private key.
- XML Signing Challenges: Initial attempts with `xmlsec1` binary worked, but Python `xmlsec` library caused digest mismatches due to whitespace/canonicalization issues. Bypassed by serializing XML to a single line (`etree.tostring(..., pretty_print=False)`) before signing.
- Timestamp Validation: Far-future `NotOnOrAfter` caused rejection; bypassed by using dynamic UTC timestamps with 5-minute validity.
- HTTP Header Mismatch: Requests library double-encoded `SAMLResponse`, causing parsing failures; bypassed by sending raw form data.
- Redash Setup: Local Redash required Ngrok for Google's IdP; bypassed by tunneling with Ngrok and configuring SAML accordingly.

These challenges highlight the need for precise XML manipulation and environment setup to exploit the vulnerability effectively. The provided exploit code successfully demonstrates this, forging a SAML response to impersonate users and gain access.
File Snapshot

[4.0K] /data/pocs/61c8f249f74416b026c33ff343b58d4f98680e43 ├── [ 15K] cve-2021-21239.py ├── [1.1K] LICENSE ├── [7.6K] README.md ├── [ 65] requirements.txt └── [2.8K] SAMLResponseTempalte.xml 0 directories, 5 files
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
    3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.