Many of you already know that any cross-site HTTP requests invoked from scripts running within a browser are restricted by the Same-Origin-Policy. Basically this means that any cross-site HTTP requests, such as XMLHttpRequest, are only allowed to make requests to the same domain that the page was loaded from, and not to any other domains. However, HTML5 has provided a way to allow browsers to make cross-site HTTP requests while controlling access by the web server. The CORS standard added HTTP headers that allow servers to service resource requests based on permitted origin domains. Browsers, in turn, support these new HTTP headers and enforce the restrictions set by the header responses.
So, let’s take a look at a typical cross-site HTTP request using two separate domains, foo.com and bar.com. First, the client browser loads a page from www.foo.com. This page includes Java Script that uses the XMLHttpRequest object to make a cross-site HTTP request with a parameter that specifies the target resource; in this case it’s http://www.bar.com/page.
The client browser then establishes a connection to www.bar.com and makes a GET request via HTTP. Cross-site HTTP requests support both GET and POST methods without having to perform a “preflighted” OPTIONS request, which is used to ensure the request is safe to send. When the request is sent, an Origin http header is included with a value of the domain or site that served the original page, which in this case is http://www.foo.com.
The www.bar.com web server can inspect the Origins header in the GET request to determine if the request is permitted. If it is permitted (or more likely not checked), it responds with a CORS header response and the requested resource. In this example, the www.bar.com website allows cross-site HTTP requests from any domain, which is indicated by the Access-Control-Allow-Origin: * response header.Basically, the Access-Control-Allow-Origin header tells the browser which origins are permitted to access the requested resource. If the value is an * then any origin domain is permitted to access the resource. If, however, the header in our example instead had a value of www.bar.com, then the XMLHttpRequest would fail, and the content from the request resource would not be available to the browser.
The beauty of CORS is that it is accessible via Java Script and basically executes without the users knowledge. This means that while the user is viewing or interacting with a page, the Java Script code can be interacting and making requests with resources from many different sites.
So, how can we abuse this? Well, like most vulnerabilities, a lot depends on if the code is written with security in mind. If developers don’t understand CORS, they may decide to go down the path of least resistance and allow any domain to make cross-site HTTP requests. Here’s something else to consider. Many organizations believe that their internal web applications are inherently safe because they are not accessible from the Internet. So internal web applications are not coded with the same security-mindedness as may be done with those that are Internet facing. Yet another possibility is that developers want to be able to perform cross-site HTTP requests between their internal domains. The problem is, if cross-site HTTP requests are allowed from any domain, then this permits these requests to originate not just from any internal domain, but external domains as well.
Since the response includes the HTTP header Access-Control-Allow-Origin: * the response is accepted by the victim’s browser, and the content of the request is available to the Java Script code running in the browser.
So it’s pretty clear that allowing cross-site HTTP requests from any domain is a bad idea and that it makes sense to set the Access-Control-Allow-Origin header to only those domains that are expected to perform cross-site requests. However, these can be circumvented with a Man-in-the-Middle attack! Remember that it is the browser that enforces the server restrictions set by the HTTP header, so if anyone can manipulate the responses back to the browser, then the restriction can be circumvented. For instance, with Burp, you can setup automatic match/replace values using regular expressions. This can be found under the Proxy tab, and then under the Options sub-tab, then scroll down to Match and Replace. Replacing the value for the Access-Control-Allow-Origin header with an “*” will tell the browser that cross-site HTTP requests are permitted from any domain, thus any resource data sent to the browser will be accepted.
If the web server checks the Origin header in the request, this too can be manipulated with Burp, setting the value in the header to the same domain as the target resource. Unfortunately, from an attacker’s perspective, you can’t set the Origin header with Java Script using <object>.setRequestHeader(<header>, <value>);.
HTML5 has really provided pen testers, and attackers, with a nice suite of features and functionality for attacking the client, and using that client to pivot into the internal network. A great example of this is the Browser Exploitation Framework, or BeEF. This is a great tool for exploiting browser vulnerabilities to perform client-side attacks and pivot into the internal network. Many organizations have matured their perimeter security, but are still in the process of understanding the potential threats that are available through the browsers on their internal network. It’s important that we know what the potential threats are so we can identify ways to mitigate the risks.
For more information on CORS, go to the Mozilla Developer Network at https://developer.mozilla.org/en-US/docs/HTTP_access_control, and the W3C at http://www.w3.org/access-control/. For more information about HTML5 vulnerabilities, attacks, and filters, check out our open source project Securing HTML5 Assessment Resource Kit, or SH5ARK, at http://sh5ark.secureideas.net.
Tony DeLaGrange is a Senior Security Consultant with Secure Ideas. If you are in need of a penetration test or other security consulting services you can contact him at firstname.lastname@example.org or visit the Secure Ideas - Professionally Evil site for services provided.