Take Your XSS and POST It

Parameter injection is one of the most common classes of web application vulnerabilities exploited in the wild.  This class of vulnerability implies that attackers inject known malicious strings into Hypertext Transfer Protocol (HTTP) request parameters in an attempt to cause unexpected application behavior.  This class of vulnerability encompasses a large variety of attack methods including, but not limited to, cross-site scripting (XSS), SQL injection (SQLi), local file includes, and path traversal.

On a daily basis I perform security assessments against web applications, and one of the most commonly occurring injection vulnerabilities I see is reflected XSS.  XSS is the result of a condition in which the vulnerable web application echoes unsanitized user input in the server response.  Essentially, this provides an attacker with a vector to manipulate the appearance and contents of the server response, or in other words render unintended HTML or execute attacker defined JavaScript within the context of the victims browser.  The impact of a successful XSS attack can vary from case to case but is typically exploited to hijack end user session identifiers, capture keystrokes, redirect browser traffic, and in some cases (with the assistance of the Metasploit Framework) compromise the system of the target victim.

Reflected and Persistent Cross-Site Scripting

There are two variants of XSS, reflected and persistent.  The two types of XSS differ only in the way the exploit is delivered to the victim.  The initial attack vector for reflected and persistent XSS relies on a vulnerable web application echoing unsanitized end user input in the server response.  However, in the case of persistent XSS the injected value is not lost when the page is refreshed, but rather persisted in a back end database where it can be delivered to victims continuously.  As an example, assume that the comment section of your local newspaper’s web page was vulnerable to persistent XSS, and exploited by a malicious adversary.  Each user that visits the page containing the poisoned comment would fall victim to the XSS attack.  Reflected XSS on the other hand relies on a phishing component for successful exploitation.  Essentially, the attacker identifies a vulnerable URL query (GET) parameter, crafts a malicious URL, and sends this URL to the intended victims.

In the case of reflected XSS, given that a URL must be sent to the target victim as part of a phishing campaign, web developers often overlook the risk of vulnerable POST parameters, or parameters present in the body of an HTTP requests (rather than in the URL as a GET parameter).  There is simply no way to cut and paste a clickable link that contains POST parameters into an email.  As a result, one would assume that the real world exploitation of POST parameter based reflected XSS is essentially impossible.  How can you send a POST request in an email?  You just can’t.   This is all sound logic, but it is not entirely correct.

HTML vulnerability

Web browsers have varying levels of trust as far as cross-domain requests go.  Nearly all of the most frequently visited web pages today load asynchronously, meaning that the contents of a page can change over time without the entire page reloading.  This behavior is facilitated through JavaScript XMLHttpRequest objects.  Modern browsers have protections in place that prevent XMLHttpRequest objects from making requests to domains other than that of the hosted web page.  This security control provides an effective defense against attackers making requests to remote servers as part of an XSS exploit.  HTML elements however are not subject to this security control.  The source of an HTML image element can be hosted on an AWS cloud server, while the body of the main site is hosted within a company’s domain.   The same is true of the “action” attribute of an HTML form.   An HTML form can be hosted on any server, and the form action allows the browser to send that request to any other server.  The flexible behavior of browsers regarding where the contents of an HTML form can be directed presents an opportunity for an attacker to exploit POST based reflected XSS.

How is POST based XSS performed?

Assume that an attacker has identified POST based XSS on a web site, and would like to stage a phishing campaign to exploit victims.  All an attacker has to do is create a dummy HTML page that contains a form that mirrors the parameters of the target web application, and ensure the form submit method is set to “POST”.  Once created, the value of the vulnerable parameter on the attackers dummy HTML form can be set to the reflected XSS payload. Finally, JavaScript needs to be inserted into the dummy page to ensure that the malicious form is submitted to the vulnerable web application as soon as the page is loaded.  Once created, the attacker can host the malicious page on any server of their choosing.  In terms of real world exploitation, in place of a URL that contains XSS payloads injected into URL query parameters, an attacker simply sends a link to the malicious “dummy” HTML form.  When the victim clicks the link, their browser directs them to the attackers dummy page, at which point they are immediately redirected to the vulnerable web application where the poisoned parameter is submitted to the server, and the POST based XSS exploit is launched.

In other words, the risk of reflected XSS is equivalent regardless of how a vulnerable web application receives user-supplied input.  Web developers should therefor treat all remediation efforts with the same level of urgency, regardless of whether a parameter is submitted via GET or POST requests.