Basically Cross-Site scripting is injecting the malicious code into the websites on the client-side. This vulnerability normally allows an attacker to masquerade as a victim user, to carry out any actions that the user is able to perform and access any of the user’s data.
The main focus of writing this article is whether XSS happens if the Content-type is set to JSON!!!!!
Before I go further, I want to define JSON: JavaScript Object Notation (JSON) is a simple, text-based data transfer format that is used to transmit data between a server and a client, an efficient transport mechanism in AJAX applications.
Before jumping into the topic the main areas involved are:
MIME Sniffing
MIME stands for “Multipurpose Internet Mail Extensions.” MIME was originally defined to support non-ASCII text and non-text binaries in email. However, the content types defined in the MIME standard are also used in the HTTP protocol to define the type of content in a request or response.
Browsers usually identify a resource’s MIME type by observing the Content-Type response header in an HTTP response.
“MIME sniffing” is adopted by browsers to determine the effective MIME type of a web resource by examining the content of the response instead of relying on the Content-Type header. MIME sniffing is performed only under specific conditions and algorithms for sniffing vary by browser.
X-Content-Type-Options
X-Content-Type-Options (XCTO) is a security-related HTTP response header used by servers to instruct browsers to not perform MIME sniffing. The only directive used for this header is nosniff. This header should be used by developers when they are sure that the MIME type in the Content-Type header is appropriate for the response’s content.
Cross-Site Scripting Using MIME Sniffing(Applicable in old browser versions)
The XCTO header is mainly useful in two parsing contexts: JavaScript and CSS. This is because, in these contexts, client-side code execution is possible. An attacker-induced client-side code execution might result in a Cross-Site Scripting (XSS) vulnerability.
Examples of JavaScript and CSS parsing contexts relevant to MIME sniffing are:
- <script> tags
- <link> tags
Now, let’s see how MIME sniffing can result in an XSS vulnerability. For an attacker to perform an XSS attack by leveraging MIME sniffing, there are certain preconditions.
Preconditions on client-side (both necessary for successful exploitation):
- The attacker should be able to control the content of the response in the server-side so that malicious JavaScript(client-side)can be injected.
- The attacker should be able to introduce an executable context via HTML injection.
Preconditions on the server-side (only one necessary for successful exploitation):
- If the server misrepresents a resource, the attack will be successful. For example, the developer sets text/javascript as the value of the Content-Type header in a response containing a text file.
- The server represents a resource correctly. However, the browser’s MIME sniffing mechanism makes the resource “executable”. For example, the developer sets text/plain as the value of the Content-Type header in a response containing text file. Although text/plain is the correct Content-Type for a text response, the browser performs MIME sniffing and makes it possible for an attacker to execute malicious JavaScript from the text file.
Once these preconditions are satisfied, the attacker can use HTML injection to inject executable context and then specify the source as the attacker-controlled resource. An example exploit payload is as follows:
<script src=”https://www.test.com/attacker_file”></script>
Once this payload is encountered by the browser, it may try to parse the response from test.com as JavaScript. As stated before, MIME sniffing algorithms vary by browser, and hence it is necessary to create a proof of concept to confirm the behavior of a browser and exploitability of the vulnerability.
At this point, some of you may be wondering that MIME sniffing or a misrepresented resource is not necessary to exploit an XSS vulnerability. An attacker can specify a remotely hosted malicious JavaScript as the source of the script tag to exploit the vulnerability. Yes, you are correct. However, there is one case where the MIME sniffing behavior of a browser might be the only way to exploit an XSS vulnerability.
What if CSP is Present?
Let’s assume that test.com deploys a Content Security Policy (CSP) that mitigates XSS exploits by disallowing scripts included from remote hosts. An example of such CSP would be:
Content-Security-Policy: default-src ‘self’; img-src https://www.test.com; script-src https://www.test.com
In this case, an attacker cannot exploit an XSS vulnerability by using inline JavaScript or remotely hosted JavaScript because the payload will be blocked by CSP. However, an attacker can make use of a resource hosted on test.com and MIME sniffing to bypass CSP.
Let’s assume that an attacker can upload text files on test.com. The attacker can write malicious JavaScript in a text file and specify the text file as the source of a script tag.
<script src=”https://www.test.com/attacker_malicious_file.txt” ></script>
Even if the server sets the Content-Type response header as text/plain, a browser may MIME sniff the response and parse the text file content as JavaScript. CSP will not mitigate an attack in this case because test.com is a whitelisted domain.
In the above scenarios, if the developers deploy the XCTO header and specify the correct value of the Content-Type response header, the XSS attack can be mitigated.
An example demonstrating JSON XSS:
Here is the stored XSS scenario which retrieves the user-related information from the database when the content-type is set to JSON and HTML.
Bug Bounty Tip To Bypass:
If you have discovered XSS on the endpoint with JSON Content-Type, open Firefox browser and try to append ;.html to it. You might trick the browser to serve this page as HTML (instead of JSON) and trigger the XSS payload.
Example: /api/users -> api/users;.html
This trick might work on apps that are built on Rails.
Try it out and let me know if it works!!
What Should Developers Do?
Developers should always make sure that all resources served by a web application have correct Content-Type header value in response. Also, the X-Content-Type-Options header with nosniff directive should be deployed for all application responses. A proper encoding mechanism should be implemented to prevent XSS.
A final conclusion would be XSS will not be possible when content-type is set to application/json in modern browsers.
References: