Sunday, December 29, 2019

Reviving Old CVEs - Reflected XSS in CA SiteMinder / SSO

Recently, I've been on a number of engagements where I've run into Computer Associate's (CA) SiteMinder product.  So, what is SiteMinder?  SiteMinder is an enterprise infrastructure product that enables centralized web access management system that enables user authentication and single sign-on, policy-based authorization, identity federation, and auditing of access to Web applications and portals.  SiteMinder pages usually have an extension of "fcc" but I've seen them wrapped in a number of different environments with various extensions.  A typical login.fcc page usually leverages a custom template but the default one looks like this:


When I first ran into the product, I Googled around and discovered two old vulnerabilities, CVE-2005-2204 and CVE-2007-5923.  Both of these were reflected cross-site-scripting (XSS) vulnerabilities so I figured it was worth exploring how these were fixed and if I could uncover a workaround or a vector they didn't see.  While researching how they fixed it, I discovered they implemented some configuration parameters for bad cross-site scripting characters (BadCSSChars) and bad URL characters (BadUrlChars).  A list of agent configuration parameters revealed what the default values were for these parameters and offered a brief description of all of them.  Here are the two relevant ones:

Parameter NameDefaultUsage
BadCSSChars<,',>A comma-separated list of characters to block due to use in XSS attacks.
BadUrlChars//,./,/.,/*, *.,~,\,-%1f,%7fA comma-separated list of character sequences to block from use in URL requests to prevent exploitation by malicious web clients.

Right away, the BadCSSChars parameter seemed lacking, with obvious omissions of backslash and double quotes.  I did see backslash in the default list of BadUrlChars so I started digging further into the documentation for how this filter was applied.  The documentation stated that the Web Agent will refuse URL requests that contain any of the characters or strings of characters that you include in this list. However, that checking is done on the URL before the "?" character.  That meant the backslash was in play for GET parameters.

With all of this in mind, it was time to start poking around various pages to see what parameters I could control that were reflected somewhere in the page. preferably somewhere in JavaScript, since I could use both double quotes and backslashes without issue.  The page mentioned in CVE-2007-5923 seemed like a good place to start.  Sure enough, just a few minutes of poking around revealed the "USERNAME" GET parameter is reflected in a JavaScript block.

https://www.example.com/siteminderagent/forms/smpwservices.fcc?USERNAME=[XSS PAYLOAD]&SMAUTHREASON=7

Both the USERNAME and SMAUTHREASON parameters are reflected in a JavaScript block and both are important for different reasons.  SMAUTHREASON dictates control flow within the JavaScript block.  This is important to get our code to execute, especially if there is a WAF in front of the application blocking double quotes and our ability to escape a string assignment and control flow ourselves.  Leveraging just a valid SMAUTHREASON and backslashes it's possible control the flow of execution and get XSS.  For example, the source code of the example URL above will contain JavaScript similar to this:
...[SNIP]...
//Auth Reason 7 - Account disabled
else if (7 == 7)
{
document.write("<TR>");
document.write("<TD NOWRAP WIDTH='100%' BGCOLOR='' height='26'>");
document.write("<font face='Arial, Helvetica'><B>[XSS PAYLOAD]</B> you cannot access your account at this time.</font>");
document.write(" </TD>");
document.write("</TR>");
} //Auth Reason - 7
...[SNIP]...
When this JavaScript executes in the victim's browser, it writes the following to the document object model (DOM):
<TR>
<TD NOWRAP='' WIDTH='100%' BGCOLOR='' height='26'>
<font face='Arial, Helvetica'><b>[XSS PAYLOAD]</b> you cannot access your account at this time.</font>
</TD>
</TR>
This is pretty basic to exploit.  Even with a slightly limited character space, we can leverage backslash and numbers to encode our payload and have use the functionality of the page to write it to the DOM.

For example:

https://www.example.com/siteminderagent/forms/smpwservices.fcc?USERNAME=\u003cimg\u0020src\u003dx\u0020onerror\u003d\u0022confirm(document.domain)\u0022\u003e&SMAUTHREASON=7

Would result in the following being written to the DOM:
<TR>
<TD NOWRAP='' WIDTH='100%' BGCOLOR='' height='26'>
<font face='Arial, Helvetica'><b><img src=x onerror="confirm(document.domain)"></b> you cannot access your account at this time.</font>
</TD>
</TR>
Simple XSS for the win!  Worst of all, it bypasses all browser XSS protections.

I found some different WAFs required some different encoding, sometimes "\u" or different key words, like "alert" or "script" would trigger them, but many could be bypassed with all the characters available to us, as long as backslash was accepted.  One of my favorite methods is using octal encoding instead of unicode since it's just a backslash followed by a number.

I found these endpoints were vulnerable consistently:
  • smpwservices.fcc
  • smaceauth.fcc

While many others were randomly vulnerable based on changes the individual developers made to various templates.

I reported this issue to Broadcom on July 12th, 2019.  Receipt was acknowledged but requests for updates have provided very little information.  Since there are a large number of vulnerable sites out there and many issue cookies to the parent domain (it's SSO, after all) I feel like it's important to make this known.  My recommendation for resolving this issue is to edit your "BadCSSChars" configuration parameter to block all of the following: ",\,',<,>,+

Friday, May 24, 2019

XSS Filter Evasion - No !#$()*;<>| or New Line? No Problem!


Before reading, try the challenge I created!

XSS Filter Evasion Challenge 1
Difficulty: Moderate

Recently, while working on some private bug bounty programs, I ran into similar cross-site scripting (XSS) filters.  These filters triggered on !#$()*;<>| and new line characters.  When triggered, these filters would replace the entire user input string with an empty string.  To illustrate this, and one example where I achieved XSS, I threw together a little challenge I will be walking through in this post.

This is a rather simple example and a bit contrived to illustrate the filter evasion but, similar to the challenge, I had to derive the input parameter from a pretty obvious place in the HTML source code.  In the challenge, if you view the source code, it will reveal an input parameter:

<!-- Sample Usage https://www.pwntheinter.net/XSSFilterEvasion/evasion1.php?redirect=https://www.pwntheinter.net/index.php -->

Using "redirect=test" reveals where our user input string is reflected:



Just like the real world finding, it was a very obvious DOM-based open redirect.  The only real "check" was that the redirect parameter begin with "https://www.pwntheinter.net" which could be easily circumvented using the "@" character.  The browser will treat everything before the "@" as "Basic" HTTP authentication and redirect to anything after the "@".  An example of exploiting this to redirect to https://www.cnn.com:

https://www.pwntheinter.net/XSSFilterEvasion/evasion1.php?redirect=https://www.pwntheinter.net@www.cnn.com

Based on where I saw my input reflected in the HTML source code, I thought I could trivially achieve XSS that bypassed browser protections, such as Chrome's XSS Auditor.  I started with the tried and true simple payload of ";alert(1);// for the quick win and found my entire input string was replaced with an empty string.


At this point, it's pretty obvious we are up against some sort of server-side XSS protections.  One easy way to see what characters trigger the protections and erase the input string is to use Burp Intruder with a payload list of all printable characters.  For fun, and some coding practice, you could write a quick script in python to achieve the same results.  Below is a link to one such script.  This is a simple example without threading or the use of a regex which would make it faster and more robust.

https://gist.github.com/reigningshells/191d1a7b3af2433bd552eb94120986b9

Running the script against the target reveals the bad characters that cannot be used in our payload:


Now we need to figure out how we are going to end the variable assignment and run our own JavaScript code.  We can use a double quote to end the string but new lines and semicolon are filtered out.  What can we do?



Well, we're in luck because our payload is reflected within a function.  We can end the string with a double quote, end the function with a closing bracket, and start a block statement with an opening bracket: "}{

This would also benefit us if we were injecting into a JavaScript function that wasn't being called because our newly created block statement would run automatically.  Seems like we are in good shape, but how do we call a function without parentheses?


This admittedly had me stumped for a little while.  I did some googling and nothing I found was working.  Then it hit me!  What if I encoded the parentheses?  How would I call a function using encoded parentheses?   Maybe, document.location?  My next thought was to try something like this:

"}{document.location="javascript:alert\50document.domain)\51

Where the parentheses are octal encoded.  But when I did...FILTERED!


The XSS sanitization wasn't just looking for bad characters, but common function names used in XSS POCs.  You can do something similar to what we did to look for bad characters with common JavaScript function names.  The ones I found that were filtered were alert, confirm, eval, prompt and the word script.  This led me to believe these XSS defenses may have been implemented after a fellow hunter reported it and was mistakenly closed despite a bypass to this solution.  Since we already encoded the parentheses we can just do the same for random characters in the bad strings to get by the filter.  Final payload:

"}{document.location="j\141v\141scri\160t:\141lert\50document.domain\51

https://www.pwntheinter.net/XSSFilterEvasion/evasion1.php?redirect=%22}{document.location=%22j\141v\141scri\160t:\141lert\50document.domain\51


And this bypasses Chrome's XSS Auditor!


That's all for this entry.  Nothing earth shattering but I hadn't seen this method for bypassing XSS filters before and thought it was worth sharing.  Feel free to comment with any alternative solutions.

Sunday, September 2, 2018

Hacking The RPi Cam Web Interface



In my spare time, I like to poke around on different open and closed source projects and look for vulnerabilities.  Recently, I turned my attention to a rather popular and cool little Raspberry Pi (RPi) project. The RPi Cam Web Interface is a web interface for the Raspberry Pi Camera module.  It can be used for a wide variety of applications including surveillance, DVR recording and time lapse photography.  A few hours of exploration led to some serious vulnerabilities I'd like to share in this post.  The creator of the project was very receptive to the findings and did a great job communicating and fixing the vulnerabilities.  If you're using the RPi Cam Web Interface, it is highly recommended that you upgrade to the latest version which, at the time of this writing, is 6.4.30.

Command injection via "convert" parameter in preview.php


When looking at PHP applications, one of the first things I grep for are functions accepting user input with the potential to execute an external program.  For reference, I listed these below:



In order to get to this function, the attacker must send a POST request to preview.php with the parameters convert and convertCmd:



Here, the data passed via convert is being manipulated and concatenated in two different ways.  I chose to focus on $tmp.  Here, $tmp is created by concatenating the BASE_DIR with the MEDIA_PATH and the result of the following two functions from config.php:


So, passing ".; id)#aaaaaaa" in convert would result in a $tmp of "/var/www/html/media/; id)#".  When $tmp is concatenated to $cmd, the final command passed to system is:

(/usr/bin/ffmpeg -f image2 -i /var/www/html/media/; id)#/i_%05d.jpg/var/www/html/media/mp4 ; rm -rf /var/www/html/media/; id)#;) >/dev/null 2>&1 &

Which results in our command being executed:



Similarly, the convertCmd parameter can be used to achieve command injection with one caveat, it overwrites whatever is in convertCmd.txt, breaking the conversion process in the future.



As a side note, the default installation of the RPi Cam Web Interface also grants sudo privileges to www-data on /bin/date which, as mentioned in my previous blog post, can aid in privilege escalation and expose sensitive information such as WiFi passwords:


A fix was put in place that first checks if the file is in the media directory and that it exists before trying to convert it and cleans up the getFileType and getFileIndex functions.


While testing this fix, I looked for a way to write a file to disk where I controlled the location and filename.  I found such a place in schedule.php.


Here, I could alter the Fifo_In and Fifo_Out parameters:


And still achieve command injection:


The developer disabled the ability to alter the Fifo_In and Fifo_Out locations and the vulnerability was closed.

Quick PoCs:
  • curl -d "convert=%2e%3b%20%69%64%29%23%61%61%61%61%61%61%61&convertCmd=doesntmatter" -X POST http://vulnerable_host/path/to/preview.php
  • curl -d "convert=doesntmatter&convertCmd=%69%64%29%20%26%26%20%28%65%63%68%6f%20" -X POST http://vulnerable_host/path/to/preview.php

Directory traversal via "download1" parameter in preview.php


The following section of code reveals that a filename passed in the download1 parameter will be retrieved and the contents returned to the attacker:


The dataFilename function requires us to do some additional padding to the filename:


But it's easy to pad a period and any 7 additional characters to achieve directory traversal and read any file www-data has the rights to read:


Quick PoC:
  • curl -d "download1=../../../../../../etc/passwd........" -X POST http://vulnerable_host/path/to/preview.php

Directory traversal via "action=zipSel" and "check_list[]" in preview.php


The last vulnerability I discovered was another directory traversal in preview.php.  This time, I'm taking advantage of the application's ability to zip a selected number of images/videos and allow you to download that archive.


Here a number of check_list[] parameters can be passed to preview.php, along with action=zipSel, to allow an attacker to read a large number of files all at once.  The getZip function handles all the heavy lifting.

Similar to the previous exploit, some extra padding is necessary because of the dataFilename.


Quick PoC:
  • curl -d "action=zipSel&check_list[]=../../../../etc/passwd.v......." -X POST --output - http://vulnerable_host/path/to/preview.php

Exploit


I decided to throw together a quick, fully functional, exploit for the command injection vulnerability.  It's just a simulated shell written in python that leverages the requests library to make the post requests to preview.php.

https://github.com/reigningshells/RPi_Cam_Web_Interface_Exploit


Monday, August 13, 2018

Sudo Date...Thanks For Read Access To Every Non-Binary File

Recently, I was testing an open source web application and stumbled on a command injection as the www-data user (hopefully another blog post soon, once the vulnerability has been patched).  To have a better idea of what I'm talking about, I created a demo web application with a similar vulnerability.


The payload in vulnparam is "id) && (echo" where id is the command output displayed to the screen and the echo part was to essentially eliminate the rest of the command that the web application intended to run but the actual command injection is outside the scope of this post.  Injecting id confirms I'm running as www-data.  While enumerating the system for privilege escalation I decided to run "sudo -l" to list the commands www-data was allowed to sudo and discovered something interesting.


Date seemed like something worth exploring.  The man pages instantly revealed something promising.


What happens if I set the file parameter to something that doesn't contain dates?  Well, nothing at first because the output goes to standard error, haha.  But, once I realized that and directed standard error to standard output with the following payload "sudo date -f /etc/shadow 2>&1) && (echo", I hit pay dirt!


Since this was a web application on an Internet of Things (IoT) device, reading /etc/wpa_supplicant/wpa_supplicant.conf for the cleartext WiFi password would be beneficial.  If you had root privileges on date on a more traditional engagement, you could use it for acquiring hashes or to read SSH private keys.

I thought this was an interesting step towards privilege escalation and worth sharing.  At the very least, it might be useful for a CTF...

Go forth and reign shells!

Copyright © 2015 Reigning Shells