Understanding How Attackers Exploit HTTP Redirects in Web Applications [Part 1]

Igor Kantor
Author
Igor Kantor
Co-founder, CEO
Understanding How Attackers Exploit HTTP Redirects in Web Applications [Part 1]

Redirects are a common feature in web applications, but they can also introduce vulnerabilities if not properly managed. This article explores the ways attackers can exploit HTTP redirects to target web application users. We’ll explore situations where a user unknowingly ends up on an attacker-controlled resource, which then redirects them back to a legitimate web application, causing it to perform a malicious action. 

Drawing on Iterasec extensive experience, we will provide a detailed guide to understanding these security mechanisms and their potential weaknesses. 

Before we get into these attack scenarios, we’ll cover the core security mechanisms of web browsers: Same Origin Policy (SOP), Cross-Origin Resource Sharing (CORS), and the SameSite attribute on cookies. Understanding these basics will help better understand how these attacks work and their impact on web security. Please, note that all examples are presented in a controlled environment specifically for educational purposes. We strongly advise against applying these techniques on actual products without proper authorization.

Same Origin Policy (SOP)

Same Origin Policy (SOP) is a browser mechanism that prevents JavaScript from accessing the values of the documents served from another Origin. A browser understands Origin as the combination of Protocol (HTTP / HTTPS), Domain name / IP address / Filesystem Path and Port. Keep in mind that most browsers function in a similar way, however there are exceptions like Internet Explorer that does not consider the Port value to be a part of the Origin. Also, Internet Explorer uses such terms as the Trust Zones.

Understanding SOP involves knowing when browsers enforce origin checks. Developers use various images, stylesheets, and JavaScript libraries to enhance applications, often sourcing these from third-party components to save time and costs. Browsers don’t see downloading such external resources as a security issue, especially when hosted on Content Delivery Networks (CDNs) that improve loading speeds and reduce server workload.

A browser does not enforce the Same Origin Policy (SOP) when a user submits an HTML form, allowing data to be submitted to any origin. It’s up to the server to allow data processing coming from another Origin or deny it.

However, SOP is always applied to network communications initiated by JavaScript, such as HTTP and WebSockets. A browser can’t send data to another origin via XMLHttpRequest or Fetch API without SOP checks. Similarly, documents from Origin A can’t interact with frames or iframes from Origin B, nor can they read or write to cookies or local storage of different origins.

Same Origin Policy (SOP)

If SOP is so restrictive, how can HTML pages make HTTP/WebSockets requests to other domains? While forms can handle some communication, it’s often insufficient. SOP doesn’t block these requests entirely but performs checks and uses mechanisms like Cross-Origin Resource Sharing (CORS) to enable secure and smooth communication.

Cross-Origin Resource Sharing (CORS)

When JavaScript initiates an HTTP or WebSocket request to another origin, browsers perform CORS checks. It involves exchanging specific HTTP headers between the browser and the server to determine if the cross-origin request is allowed. 

Cross-Origin Resource Sharing (CORS)

While the Origin header is not directly related to the CORS request headers, the browser includes this header in every request and this header is the important part in the CORS mechanism.

JavaScript sends a CORS request to the server, which responds to the browser. The browser then verifies the CORS headers in the response. If the headers are correct, the browser allows JavaScript to process the response data; otherwise, it blocks access.

a CORS request

CORS requests are categorized into Simple and Preflight requests, with some considering credential-carrying requests as a separate category.

Simple and Preflight requests

If a JavaScript-initiated HTTP request passes all checks, it is a SIMPLE CORS request. The browser sends it directly to the server, which decides whether to process it based on its CORS policy. If allowed, the server responds to the browser.

For non-SIMPLE CORS requests, the browser performs an additional step. It sends an HTTP OPTIONS request to the server, informing it about the upcoming request and asking for permission. This preflight request includes details that make it non-simple, such as HTTP methods, credentials, and specific headers.

The server checks the preflight request against its CORS policy. If approved, the browser proceeds with the actual request.

Same Origin Policy (SOP) and Cross-Origin Resource Sharing (CORS) working  together

Modern browsers use Same Origin Policy (SOP) and Cross-Origin Resource Sharing (CORS) security mechanisms. While SOP is more about not letting a browser do dangerous things, the CORS mechanism is designed to relax SOP for certain, safe cross-origin requests. 

SOP does not apply to form submissions because HTTP forms perform SIMPLE CORS requests. While browsers allow cross-origin form submissions, sending the same HTTP request with the same method, headers, and body via JavaScript will result in a CORS error. The request itself succeeds, but the browser blocks JavaScript from accessing the response. This distinction is crucial for understanding how these mechanisms work and how they can be exploited. 

SameSite Attribute

The SameSite attribute on cookies is a browser security mechanism that controls cookie inclusion in cross-site requests. The server can specify the SameSite value in the Set-Cookie response header.

SameSite has three values:

  • Strict: Most secure. Cookies are only included in requests from the same site that set them.
  • Lax: Balanced. Cookies are included if the initiating and target sites are the same, and when a user navigates to the cookie’s origin site from another site.
  • None: Cookies are included in both same-site and cross-site requests.

The behavior of SameSite can vary depending on the browser type and version.

Demo Application architecture

After discussing SOP and CORS, let’s demonstrate an attack using redirects. This example application, while not reflective of a real-life setup, is suitable for showing some techniques.

Two ASP.NET Core applications are running in Docker containers on an Ubuntu Server, with domain names (4rt1cl3s.fun and soci4l.fun) and TLS certificates managed by an Nginx reverse proxy server. The following image shows the architectural scheme:Demo Application architecture

 The home page of the application for authenticated users is exemplified as follows:

TLS certificates managed by an Nginx reverse proxy server

These three links (Forms, Fetch, XMLHttpRequest) all direct to the article management functionality, which allows users to create, display, edit, and delete articles, providing basic CRUD capabilities. The key difference between them lies in their implementation:

  • Forms: Uses GET and POST forms.
  • Fetch: Uses JavaScript Fetch API.
  • XMLHttpRequest: Uses the older XMLHttpRequest object.

The comments for the articles are handled by a second application, which can return and save comments related to an article. The communication between these two applications is depicted in the following image:

Applications communication in HTTP redirects

In this example of form request redirection, neither the Articles App nor the Comments App has any CORS configurations applied on the server side. It means both applications follow the default behavior when handling cross-origin requests.

The developer team behind the Articles application wanted it to be adjustable, allowing the base URL of the Comments application to be set if it moved domains. However, a poor implementation created a security vulnerability: anyone knowing a user’s ID could change their base API URL without authentication, affecting where the user’s browser reads or posts comments. 

Threat Modeling, Attack ideas and Thinking process

An attacker can exploit the known vulnerability by redirecting a user to a phishing site or injecting an XSS payload in a comment. While security-aware users might avoid phishing sites, and the application might prevent XSS, the attacker still controls the resource for comment-related requests. This control means they can return any response to the user’s browser.

Changing a user’s base API URL to point directly to another endpoint in the articles’ application will not work because the application only accepts the base part of the URL, such as the IP/Domain and/or Port.

Redirecting a harmless HTTP GET request may have little impact, but redirecting an HTTP POST request can be more dangerous. HTTP status codes 307 and 308 allow for preserving the original HTTP method, enabling the attacker to redirect POST requests to another location, potentially performing state-changing operations.


HTTP GET request

Although the attacker can’t see the cookies or authorization headers due to cross-origin requests, they can redirect the POST request back to the original article application, where the browser includes the necessary cookies and CSRF tokens. It allows the attacker to manipulate the application’s behavior, depending on how the client’s browser handles cross-origin POST requests.

Redirecting a Form Request

The attack scenario features two steps:

  1. Changing the Base API URL:  The attacker changes the victim’s base API URL to redirect comment-related requests to an attacker-controlled resource. It requires knowing the victim’s ID.
  2. Crafting a 308 HTTP Redirect: The attacker returns a 308 HTTP status code redirect for the victim’s /Social/Comments/PostComment request.

In this demonstration, the victim uses Chrome, and the attacker uses Safari and a mock server from Beeceptor. The victim’s Chrome browser traffic is proxied through Burp Suite to get a clear picture of what is actually happening.

Phase 1: The attacker sends an HTTP POST request to the https://4rt1cl3s.fun/RedirectTest/Accounts/ChangeBaseApiUrl endpoint, which requires no authentication. The request includes the user’s ID and the new base API URL.

Once changed, any comment-related requests from the victim’s browser will lead to https://redirect-test.free.beeceptor.com.

An attacker uses the following Python script for changing the BaseApiUrl parameter in the Articles’ application without authentication:

import requests

url = 'https://4rt1cl3s.fun/RedirectTest/Accounts/ChangeBaseApiURL'
request_data = {
    'Id': 2,
    'NewBaseApiUrl': 'redirect-test.free.beeceptor.com'
}
headers = {
    'Content-Type': 'application/json'
}
response = requests.post(url, json=request_data, headers=headers)

if response.status_code == 200:
    print("Request was successful.")
    print("Response Content:", response.content)
else:
    print(f"Request failed with status code {response.status_code}")
    print("Response Content:", response.content)

Now, when the victim views any article authored by user ID 2, the requests for retrieving or posting comments will be redirected to the attacker-controlled resource at https://redirect-test.free.beeceptor.com.

Phase 2: The attacker sets up the mock server to respond with an HTTP 308 status code and a Location header pointing to https://4rt1cl3s.fun/RedirectTest/Profile/ChangePassword when the victim attempts to post a comment.


respond with an HTTP 308 status code

Here’s what happens when the victim visits this page and attempts to post a new comment:

HTTP status code redirect

When the victim tries to post a comment:

1. The attacker’s resource (https://redirect-test.free.beeceptor.com) redirects the victim to https://4rt1cl3s.fun/RedirectTest/Profile/ChangePassword using a 308 HTTP status code and the location header.
a POST request to the new URL

2. The victim’s browser makes a POST request to the new URL with the same data initially sent to the attacker’s resource. It includes URL-encoded data such as ArticleId=2&AuthorId=2&AuthorNickname=TestUser&AuthorProfileImageName=default.png&Content=Test+Comment. The browser also sends cookies after the redirect.

Note that the Origin header in this request equals null, but the victim’s browser allows it to happen, as it is a Form submission request. 

SOP, CORS, Redirects

3. The article application accepts the request, changes the password, and redirects to /RedirectTest/Profile/Me, indicating a successful operation. The victim’s UI reflects this change.

password is changed

The victim’s password is changed to “Test+Comment,” allowing the attacker to log into the victim’s account. This attack demonstrates how the attacker can exploit redirects to take over the victim’s account.

limitations and conditions of this attack vector

Next, let’s discuss the limitations and conditions of this attack vector.

Form Redirection specifics and limitations

The attacker can’t control the headers and body of the HTTP request after a redirection. The victim sends request headers and body data (ArticleId, AuthorId, AuthorNickname, AuthorProfileImage, Content) to the attacker’s resource, which then redirects to another endpoint. The same data is sent to the new endpoint.

The reason this request succeeded, despite the expectation that the request to /RedirectTestProfile/ChangePassword should fail due to mismatched data, is that the success of such form redirections heavily depends on the backend technology, model binding implementation, and content-type formatters. The following image shows a comparison between the data sent by the victim’s browser and the data expected by the /RedirectTest/Profile/ChangePassword endpoint:

ASP.NET's model-binding

The request succeeded because ASP.NET’s model-binding ignored unmatched fields and only used the required “Content” field in the request, matching the expected “Content” field on the server-side. It allowed the attack to be successful despite the mismatched data.

An interesting case occurred when trying to reproduce the attack using Chromium from Burp Suite and Selenium. In both situations, the victim’s browser refused to send cookies after the redirection.

reproduce the attack using Chromium from Burp Suite and Selenium

The first request goes to the attacker-controlled resource which redirects it back to the 4rt1cl3s.fun domain. 

the HTTP POST request

However the HTTP POST request to the https://4rt1cl3s.fun/RedirectTest/Profile/ChangePassword now goes without Cookies resulting in a failed attack.

the ASP.NET Core framework

Research dedicated to this specific case revealed that the behavior is due to the SameSite cookie attribute. By default, the ASP.NET Core framework sets cookies with the SameSite attribute to Lax. As mentioned in the SameSite attribute section, the behavior may vary depending on the browser.

Conclusion

In this article, we have demonstrated the potential threats posed by HTTP redirect attacks and how they can exploit vulnerabilities in web applications. By understanding the complexities of SOP, CORS, and SameSite attributes, developers can better safeguard their applications against such attacks. Protecting users from malicious redirects requires a comprehensive approach, including secure development practices and strict testing.

For more insights into web security and how to protect your applications, contact Iterasec. Our team of cybersecurity experts is ready to help you secure your digital assets and ensure your applications are resilient against emerging threats.

Contact us

Please tell us what are you looking for and we will happily support you in that.

Fell free to use our contact form or contact us directly.