diff --git a/src/pentesting-web/saml-attacks/README.md b/src/pentesting-web/saml-attacks/README.md index 5115d93a878..d2cec51da44 100644 --- a/src/pentesting-web/saml-attacks/README.md +++ b/src/pentesting-web/saml-attacks/README.md @@ -371,8 +371,95 @@ CSRF delivery pattern: Why it works: the server decodes `RelayState` and incorporates it into the response in a way that permits newline injection, letting the attacker influence headers and body. Forcing `Content-Type: text/html` causes the browser to render the attacker-controlled HTML from the response body. +## Unterminated / unquoted SAML attribute overread (IdP parser bugs) + +Some SAML IdP implementations use **custom XML parsers** for `AuthnRequest` attributes and try to recover from malformed XML instead of rejecting it. A recurring bug class is that **quoted** attribute values stop correctly, but the **error-recovery path for unquoted values** only stops on a literal space, `>` or `NUL`. That lets attackers make the parser **over-consume later XML** and, in the worst case, **read past the request buffer**. + +This is especially interesting when the parsed fields are later **reflected** into: + +- cookies +- logs +- redirect parameters +- debugging/error responses + +### Quick detection idea + +Send a base64-encoded `SAMLRequest` to the IdP endpoint and replace the separator after an unquoted attribute with a newline or tab. Then put another attribute or tag immediately after it. + +```xml + +test + +``` + +If the target behaves as if `AssertionConsumerServiceURL` were `11 ID=22` instead of only `11`, the parser is **not treating XML whitespace consistently** in its recovery path. + +### Escalating from parser confusion to overread + +Useful heuristics when fuzzing SAML IdP parsers: + +- Keep the **high-level SAML requirements** valid somewhere in the document (for example `AuthnRequest`, closing tag, valid `Issuer`). +- Corrupt the **low-level parser state** with an **unterminated opening tag** or an **unterminated attribute**. +- Move required elements into **weird but still accepted locations** to satisfy semantic checks while the attribute scanner keeps reading. +- Try payloads where the final attribute is left unterminated at the end of the request: + +```xml +test + +Version="2.0" +ID="11" +AssertionConsumerServiceURL= +``` + +If the parser later serializes that field into a cookie or redirect, decode the reflected value and check whether it contains bytes that were **not present in your request**. + +### Reflected sink hunting + +For NetScaler SAML IdP parsing, the useful sink was the `NSC_TASS` cookie returned after a `POST` to `/saml/login` (typically inside a `302` response). Generalize this idea to any SAML appliance or middleware that stores parsed request fields server-side and then reflects them client-side. + +A practical workflow is: + +1. Send a base64-encoded `SAMLRequest` to the IdP endpoint. +2. Capture the response without following redirects. +3. Extract and base64-decode the reflected cookie / parameter. +4. Inspect the parsed field (`ACSURL`, `ID`, etc.) for data that was never in your original request. + +```bash +python3 - <<'PY' +import base64 +print(base64.b64decode('NSC_TASS_VALUE_HERE')) +PY +``` + +If the leaked field contains: + +- fragments of later XML tags +- stale heap/stack marker bytes +- partial pointers +- binary data that changes with request length + +then you likely have a **real memory disclosure primitive**, not just malformed-XML confusion. + +### Request-length shaping + +These bugs often stop leaking at `NUL`, `>` or other control characters, so the leak may be short. Still, **varying the request length** can change which adjacent bytes are reached and turn a tiny overread into a useful **infoleak primitive** for pointer recovery / ASLR bypass preparation. In practice, small changes such as adding padding spaces inside the malformed `AuthnRequest` can move the leaked bytes to a more useful heap position. + +### DoS variant + +Also try **incomplete attributes** such as: + +```xml +