CVE-2009-2705: Null-byte + overlong UTF XSS flaws in CA SiteMinder

In 2009 Jeff Williams and I discovered 2 critical flaws in SiteMinder. We decided to experiment with responsible^M^M coordinated disclosure with the company who manages SiteMinder, Computer Associates (CA). The process was painfully slow and we endured the same disrespectful treatment that many researchers got at that time (and still sometimes get today.) The history and details of the vulnerability were not captured anywhere, and they're not in any of the CVE tracking sites, so I thought they should be captured here.

Here is some of that story from that time:

For months they kept asking for details about the product version and configuration – details that we told them we didn’t know and couldn’t provide without being a major annoyance to our customers. We repeated ourselves and kept pressing for them to fix it.

We repeatedly asked for status. The fixes should have been relatively easy and we got very little information until now. The timelines in the responsible disclosure guidelines by Wysopal & Christey were obliterated by CA. We just got an email after months saying they just tested their latest build (something we suggested they do on day one) and that the attacks appear not to work anymore.

This response, after thinking a bit, seems like an insult to my intelligence. The attacks haven’t not worked on any SiteMinder-protected application we’ve tested since last year. All of a sudden they decide it’s important and test their latest build and it no longer works? Apply some critical thinking skills and ask yourself what is more likely:

They randomly fixed both of these vulnerabilities before we reported it. Keep in mind the following facts:

  • We are seeing them work in the wild 24/7
  • There are no advisories regarding these vulnerabilities on their advisory blog
  • It took 6 months for them to “get around” to testing our 2 newly reported critical vulnerabilities

or…

They took our information, spent the last 6 months fixing the vulnerabilities quietly, and now have plausible deniability

So much for "responsible" disclosure.

The motivation for researchers to find flaws is credit. Credit is the currency we deal in. As gaz pointed out on Twitter, “bug hunting is fun”, but at the same time bug hunters are also providing an extremely valuable service and should be compensated in some way for the bugs they find. Credit to the researchers in a patch or advisory is the only currency that vendors have been willing to pay, especially for layer 7 bugs. You think ZDI’s paying me for my XSS?

Let's talk about the bugs.

What is SiteMinder?

SiteMinder, for the uninitiated, was a security gateway that used to sit in front of 80-90% of corporate America’s J2EE/Java EE/Jakarta applications. It was used to provide authentication, URL authorization and XSS protection on GET requests.

Although it was used to protect Java applications, SiteMinder itself was written in an unmanaged language.

Flaw #1: Complete XSS-defense Bypass Through Null-Byte Injection

Normally, passing almost any special characters in a GET request to SiteMinder will cause an error to occur. It’s practically impossible to XSS a SiteMinder application through a GET because of this. The user data must land inside a JavaScript context, unquoted attribute, or some other unusual scenario for exploitation to be possible.

Passing data in via a POST is the low-tech way to do this, but it’s not ideal for reflected XSS.

Jeff was testing this mechanism and he tried prepending his payload with %00. SiteMinder didn’t see the attack because it recognized %00 as the end-of-string character. Here’s some text from our disclosure to them:

The following URL, which attempts to exploit a non-existent XSS vulnerability in the a page will be caught by Siteminder’s XSS protection:

http://victim/app/function?foo=bar<script>alert(document.cookie)</script>

However, prepending the parameter value with a null byte directly will cause the parameter value to go unnoticed by the protection mechanism, as can be seen in the following URL:

http://victim/app/function?foo=bar%00<script>alert(document.cookie)</script>

This indicates that the code for parsing parameters is done in an unmanaged language like C or C++ and interprets the null-byte as the end of string character. Unfortunately, Java considers the null byte just another part of the string, so what comes after it is used in the vulnerable page and the reflected XSS will be fired.

Flaw #2: Complete XSS-defense Bypass Through Canonically Decomposable (aka “overlong”) Unicode

This one we anticipated would be harder to fix since it would require some architectural re-thinking. By passing an "overlong" version of a SiteMinder-blacklisted character (like %e0%80%bc for ‘<’) you could get the attack to pass SiteMinder’s check, which obviously worked at the byte or ASCII-character level. However, when the J2EE application server got a hold of the multi-byte character sequence it canonicalized the data into Unicode (Java uses UTF-16 under the hood). Here is some text from our disclosure to them:

There are a multitude of issues when interpreting UTF-8 in a gateway security mechanism. Invalid UTF-8 of all forms, including overlong UTF-8, using best-fit mappings and performing normalization can all cause problems. The following URL will be caught by SiteMinder because it contains a ‘<’.

http://victim/app/function?foo=bar<

However, passing the following URL will not trip the protection mechanism:

http://victim/app/function?foo=bar%e0%80%bc

The seemingly random assortment of bytes (0xe080bc) is reduced to the ‘<’ character when its consumed into a Java String object because the JavaVM understands and reduces this inappropriately long representation of a UTF-8 character. Strictly looking for the 0x3C byte to detect ‘<’ characters will always fail because of this, so the SiteMinder protection needs to be Unicode aware. These issues are presented well in the Unicode technical report #36, specifically in section 3. I believe the JVM has gotten more strict about this behavior recently, so I'm not sure if it works any longer.

Summary

That’s our story. At the end of the day, we didn’t get credit from CA, but our bugs supposedly got fixed, so we’ll call it a push. We ended up later getting credit with CVE-2009-2705, probably because a scanner company needed a CVE to which they could map their vulnerability findings to when they searched for this issue.