Not too long ago, I was tasked with performing an Application Security Assessment while on-site at a client location. I had worked with this client before, and was eager to see how they had matured their applications over the past couple years. Originally, I had performed an assessment on an older version of the application and I was curious to see the direction they went with the new version of the application.

As I began my normal testing routine, I quickly realized this particular application was built on top of the Google Web Toolkit (GWT) and most of the responses were JSON formatted. Seeing this, I knew this would be a tough nut to crack as both GWT and JSON were built with security in mind.

At the start of this assessment, I decided to start with a quick walkthrough of the application. While my intercepting proxy tool spidered each click, I set up and configured a web vulnerability scanner and let it run against the application. Aside from the typical SSL/TLS configuration issues, the automated scanner didn’t find much in the way of exploitable vulnerabilities that would result in access to the host or a user’s session. This is where the real application penetration testing began.

I knew I would need to go through each page of the application, and would need to try altering specific areas in each request to see how the application responded. About the third day into the application assessment, my teammate and I discovered an input field that, when altered, resulted in JavaScript execution on a search results page. What’s more is that the page that displayed my entered JavaScript had an auto refresh timer meaning the script would run as often as the refresh kicked in on the page. This is good, but the initial attack displayed a pop-up box with a user’s session token, which would alert the end user that something was potentially wrong with the page. Right away, I realized I needed to take this attack a step further to see if I could covertly execute JavaScript on the response page.

Let’s step back a minute though and discuss some of the issues with the Google Web Toolkit (GWT) framework. GWT is built in a way that overcomes typical Web application attacks. GWT uses Remote Procedure Calls (RPC) for asynchronous web related tasks and makes it easier for developers to reuse application code for common tasks. You can think of GWT as a way to debug Ajax with Java. GWT was built with security in mind and helps defend against several forms of web application attacks. One weakness of GWT though is against DOM based Cross-Site Scripting (XSS). So while injecting SCRIPT* tags may not lead to successful XSS, injecting a STYLE** tag with the ‘onload’ attribute may. I mentioned though that the responses received from the application server were JSON. I did this intentionally. JSON has several methods for thwarting maliciously injected JavaScript. One such method is the .stringify() method which essentially takes anything input into the method and turns it into a string. So, for example, take the following potentially malicious JavaScript:

When used in the stringify() method as an input parameter, the entire input would be returned to a browser as a string, meaning the SCRIPT* tags and JavaScript wouldn’t render but would be displayed as a string data type. Using JSON in this way is extremely effective in thwarting injection attacks. As far as our application is concerned, I needed to see if the stringify() method was being used as a way to sanitize malicious input in order to prevent it from rendering. Based on some basic manual testing, I could tell the input discovered on day three was not being converted by the application’s back end using the JSON stringify() method against values entered. This is the only reason the XSS attack would work.

Let’s break this down a bit and explain what’s happening in more detail.

The input field in question was used as a way for the end user to enter a reference ID associated with their search terms for a particular topic. This value was then stored with the results on the results page for quick reference. The application was responsible for batch processing multiple search queries at once, and this input made it easy to track one particular search batch among the many running simultaneously within the application.

Here’s a breakdown of how I discovered the vulnerability:

  1. I set my intercepting proxy to catch all request/response sequences between my browser and the application.
  2. I entered the word ALERT (just like that, in all caps) so I could track where in the request/response sequences that particular input came into play.
  3. From testing, I knew the application had client-side validation mechanisms in play, so I would have to manipulate the raw request before manually sending it through to the application.
  4. Testing revealed the third request had my entered word “ALERT”.
  5. I removed the word ALERT and entered my JavaScript.
  6. I forwarded the remaining requests/responses and waited for the results page.
  7. When an alert box popped up revealing the user session token, I knew the attack worked.
  8. I repeated steps 1-6, but this time altered the JavaScript to be more covert to the end user.
  9. I used:

When executed, the user’s browser would continually try to load a fictitious image by making an HTTP request to the attacker’s web server (at 123.123.123.123) – in this case my attacking machine. At the end of the request would be the user’s session token value (which will replace the ‘document.cookie’ in the script above once the script executes). This session token value could then be used to access the application as the user without needing the user’s authentication credentials. The cool thing about this attack is that the refresh on the page would execute this script every so often, meaning whoever visited the page would wind up sending the attacker their session token. The attacker would gain multiple authenticated session tokens and be able to use the application as any of those users.

A major aspect to highlight in this blog is the fact it took dedicated, manual testing to uncover this vulnerability that was missed by automated tools. GWT and JSON applications can be a nightmare to assess when configured properly and implemented well. There is immense value in dedicated, manual-testing sessions when performing an application penetration assessment.

While automated testing lets a tester check a lot of things in a rapid manner, it simply will not test everything. Manual testing, and being good at manual testing, is what separates “penetration testers” from “good penetration testers”.