Welcome to the second installment of our “Attacks You Should Know About” series! This blog provides valuable insights for both novice and experienced cybersecurity professionals on common attacks and vulnerabilities. Today, we examine cross-origin resource sharing misconfigurations. Our goal is to explain the attack, its potential impact, mitigation strategies, and present a real-world proof of concept. Let’s dive in!

What is Cross-Origin Resource Sharing?

Cross-origin resource sharing (CORS) is a security feature implemented in browsers via HTTP headers that controls access to resources outside the current domain. It offers a more flexible alternative to the same-origin policy (SOP), which completely restricts external resource access. Since many applications need to access external domains for tasks like obtaining an API key or authentication, organizations often implement CORS instead of SOP.

Before a cross-origin request is made, the browser may send a preflight request, an HTTP request that uses the OPTIONS method to verify whether the request methods, headers, and CORS policies are allowed. If the server responds with the correct options, the browser will send the actual request

There are two key CORS headers to keep in mind in the postflight request:

Access-Control-Allow-Origin

The first header, “Access-Control-Allow-Origin,” specifies whether an origin is allowed to access an application’s resource. There are three possible settings for this header:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Origin: {origin}
  • Access-Control-Allow-Origin: null

Each configuration value serves a purpose but also introduces potential challenges. The wildcard value “*” allows any domain to access a resource, which is too permissive for most applications. To restrict access, the “{origin}” value permits only a specified domain, offering stronger security. However, this approach can be problematic if an application needs to trust multiple domains or subdomains, as CORS allows only one origin per response. Lastly, the “null” value can signify various contexts, often being used in local, sandboxed, or untrusted environments.

Access-Control-Allow-Credentials

Most applications have two kinds of resources: public and private. The “Access-Control-Allow-Credentials” header allows the requesting domain to access its private resources, which can include:

  • Session Cookies
  • Tokens
  • Authorization Headers
  • TLS Certificates

There are two states for this header. If credentials are allowed, it is set to “true.” If cross-origin credentials are not allowed, the header is omitted from the response entirely. It is important to note that if the Access-Control-Allow-Origin header is set to the wildcard value (“*”), the Access-Control-Allow-Credentials header cannot be used, as this would pose a severe security risk. Conversely, when the origin is set to null, the credentials header can still be utilized.

Dynamic Generation

One issue mentioned earlier is that CORS allows only a single, fixed origin in the response. However, many business cases require a domain to trust more than one application or service. In such instances, developers use a technique called “dynamic generation” to elastically set the origin header based on the request’s origin. The following code snippet illustrates this approach:

While this approach addresses one issue, it can introduce more if the dynamic generation function is not implemented correctly. For example, if the function accepts any domain with the *.victim.com string, a threat actor could register a domain like attack.victim.com to gain cross-origin access. In practice, we can detect improper dynamic generation by supplying an arbitrary origin and verifying whether it is reflected in the response with the allow credentials header. More on that shortly.

Impact of CORS Misconfiguration

The impact of a CORS misconfiguration can vary drastically depending on if and how the application has dynamic generation implemented. In mild instances, a misconfiguration can lead sensitive data exposure, such as:

  • Authentication/Session Tokens
  • Personal Information
  • Financial Data
  • API Keys and Secrets

In severe cases, CORS can be combined with other attacks to carry out more consequential actions. With sufficient effort, it could serve as an initial catalyst toward remote code execution.

CORS Misconfiguration – Arbitrary Origin Reflected

Let’s examine, from start to finish, how to identify a poor CORS configuration and how one might exploit it.

Enumeration & Identification

Suppose an application exists where users can access their API key after logging in:

If we examine the request and response for accessing these account details, there are several giveaways that the application is using CORS.

The first giveaway is the “Sec-Fetch-Mode” header in our request, which helps the server determine the type of request the browser is making. One possible value for this header is CORS, which indicates that the application is using it. Additionally, the HTTP response shows that the “Access-Control-Allow-Credentials” header is in use, another clear indication of CORS. The most important header to check in the response is “Access-Control-Allow-Origin,” as it can quickly reveal if the application has improperly configured its CORS policy. Let’s try adding an origin header to our request.

We included an “Origin” header with an arbitrary domain, which the server accepted and allowed to access the application.

Exploitation

Now that we’ve identified the CORS misconfiguration, we can emulate what it would look like for a threat actor to take advantage of it. The end goal here is to get the Administrator’s API key.

The first step would be creating a malicious script that will interact with the victim’s session. PayloadsAllTheThings is a great resource when scavenging for POCs and just so happens to have one for CORS origin reflection misconfiguration.

Let’s break down what the JavaScript is doing. The request object is created to open the victim page, which, in our case, is the URL with the /accountDetails endpoint. Additionally, the request instructs the browser to send credentials to the application. This is where the “Access-Control-Allow-Origin” header from earlier comes into play, as it allows us to use the user’s credentials to access what is meant to be a private resource. The request is then sent. We also have a function acting as a request listener on our attacker server, which will fetch the response from our request and log it into our server’s logs.

Here’s what a full HTML page impersonating a 404 error would look like:

 

The threat actor would then send the admin a phishing message, hoping they click the link containing the HTML page.

While the administrator may dismiss the link as non-functional, their API key has been captured and sent to the attacker’s server.

We can now use a URL decoder to clearly see the contents from the response.

Mitigating CORS Misconfiguration

At the end of the day, the best way to prevent cross-site attacks is to configure CORS properly. A good starting point is ensuring that any dynamic generation uses a whitelist of allowed hosts for requesting resources. Avoid using wildcards unless absolutely necessary, both in dynamic generation and in the overall CORS policy. If you must provide access to many similarly named domains, ensure that your regex is strict and intentional. Lastly, do not whitelist a null origin. As mentioned earlier, it is quite easy to add a null origin header on the client side, making it arguably even worse than using a wildcard.

Warning: Please do not try these tactics and techniques on any domain without explicit permission from the domain owner. This information is provided solely for educational purposes, and Abricto Security is not responsible for any individuals who use these tactics and techniques in an unauthorized or malicious manner.