I've uncovered a technique that exposes a new class of web vulnerability. By leveraging two seemingly unrelated browser features, an attacker can trick an unsuspecting user into performing actions on a different website with minimal user interaction. Let's dive into the technical details of this web attack vector. .
Attack Methodology:
To execute this attack, a target user must visit an attacker-controlled website and engage in minimal user interaction. The attacker employs various methods for successful exploitation of this vector, including the victim pressing a key or holding down a key while on the attacker's website. A more intricate approach involves the target user double-clicking on the attacker's website through popups and pop-unders in a technique I call the sandwich method. There are also a few ideas around avenues other than either methods that exploit this behavior, and I am excited to see how the security community might evolve this. I want to give shout out to @Qab for improving some of the techniques here.
How does the vulnerability work?
In HTML, an "ID" attribute can be assigned to an HTML tag, serving as a reference. This attribute can also be utilized in the URL Fragment. For instance, if a webpage has an HTML tag similar to the following
<input type="submit" id="important_button" onclick=dosomething()>,
the button can be preselected by navigating to the URL victim.com/page#important_button. If a user navigates to such a URL and presses Enter or Space key, the browser automatically clicks on the newly focused ID attribute, triggering associated action on the website.
So how is this behavior exploitable?
Vector 1: Pressing/Holding A Key on Attacker website
Using new windows that are very small, we can open the target page with a sensitive button in a new window with its sensitive button's ID referenced in the URL Fragment. The attacker can instruct the target user to hold a key (For example: Enter or space key), tricking them into interacting with unintended elements on the target website.
While testing this around in the wild on websites like Coinbase and Yahoo, I found that this can lead to an account takeover if a victim that is logged into either site goes to an attacker website and holds the Enter/Space key. This is possible because both sites allow a potential attacker to create an OAuth application with wide scope to access their API, and they both set a static and / or predictable “ID” value to the “Allow/Authorize” button that is used to authorize the application into the victim's account.
To pull off the attack, the attacker will prepare a website that will open the attacker’s malicious OAuth authorization prompt URL in a new window when the target user holds Enter key or another gesture that causes affirmation (like a mouse click).
The opened window preferably stays as a very small window in the corner of the screen or hidden using pop-under tricks so the victim doesn’t realize they have interacted with a different site. Here is a simple example:
function attack(){ //open new window with smallest possible height and width for a window var win = window.open('https://target.com/oauth/allow?appId=attackerApp#allow-button','a','width=1,heght=1'); //attempt to resize the window to even smaller size (works better for Safari and IE/Edge/Opera) win.resizeTo(1, 1); //sleight of hand to move the new window to the edge of the screen so it doesn't capture the eye. win.moveTo(4000, 4000); //close the new window as fast as possible to hide what happened //(the faster the page loads, the faster the window can close) setTimeout(()=>{win.close()},1290); //show target user a message their expected action is complete setTimeout(()=>{document.getElementById('div').innerText = "Cookies approved! welcome to our site!";},1500); //setTimeout(()=>{location.reload();},4000); } //when target presses and holds Enter/Space key launch the attack window.onkeypress=e=>{ attack(); }
The above simplifies the understanding of the attack process. Various techniques can be employed to reduce the attack's detectability and dramatically improve the likelihood of success. For example the attack appears less suspicious when a target doesn't need to hold their key for more than approximately 1 second. The effectiveness relies on how quickly we can close the target window, a factor influenced by the speed at which the target page loads. The accompanying video demonstrates the code in action. Attack Improvement ideas for key press vector:
Prerendering: Using the <link rel="prerender" href="https://example.com/content/to/prerender"> tag, an attacker website can instruct a browser to prefetch and render the target page in the background before initiating an attack. This significantly accelerates the loading process of the target page in a new window.
Prefetching: Leveraging <link rel="prefetch" href="https://example.com/content/to/prerender">, an attacker page can notably boost the response time of the target page. Prefetch, a new browser feature, speeds up webpage load times by performing DNS resolutions before a link is opened or clicked. However, similar to prerender, prefetch requires an absolute URL to function. Unfortunately, if the final URL of the OAuth request is unknown due to multiple redirection, prefetching becomes impractical.
Caching Sub-Resources: Sub-resources of a page loaded through window.open() are cached by the browser, resulting in faster loading when opened in a new window. This allows the attacker to open the target page in a new hidden window, close it, and then reload it with the desired preselected fragment. This strategy significantly accelerates page loading as the newly opened window retrieves the target page's sub-resources from the cache.
Forced Caching: In instances where forced caching is possible across origins, an attacker can compel the victim's browser to cache the target page before opening it in a new window. This dramatically reduces load time as the target page is loaded from the cache rather than the internet.
Safari Window Tricks: Browsers like Safari and Opera, when opened with a new window of 1x1 width and height, do not display the URL bar or title of a window. This can be paired with prompts like "Allow cookies"/"Allow Javascript" on the attacker's website to convince the victim that they haven't interacted with a different origin. In scenarios with slower prompts, this window may appear for less than 1 seconds, creating uncertainty of what might've happened, especially if the victim hasn't interacted with OAuth before.
Attack Limitations:
Known Mitigations:
1. The easiest way to mitigate this is by randomizing ID attributes so they can't be guessed cross origin. So, an example of this would be renaming the ID "allow" to "allow234b" where 234b is a dynamically generated value either from the server or client unique for that particular user and can't be predicted by an attacker. You might observe Facebook doing the same thing regarding these buttons.
2. Another way to mitigate this is by removing ID attributes from important buttons and actively moderating for abuse. This is another mitigation technique implemented by Coinbase and Dropbox. 3. For the double click vector, requiring a mouse gesture before enabling a button or waiting few ms to activate a button is one way to mitigate the vector.
FAQ Section:
Q: Is this considered a browser bug?
A: No, it's not.
Q: Can popup blockers address this vulnerability class?
No, the "pop-ups" occur after a user performs a gesture, such as clicking or pressing a key while on an attacker's website. Popup blockers in all modes still permit new windows to open following such user-initiated events.
Q: If I want to fix this, what do I do?
A: To address this issue, consider adding or using unpredictable and hard-to-guess values for the "id" attribute. Alternatively, you may want to explore using the "name" attribute.
Q: Can I randomize the ID?
A: While randomizing the "id" attribute can enhance security, be cautious. Previous research by Gareth Hayes has demonstrated a method for leaking "id" attributes cross-domain. Unless the "id" value is sufficient entropy, there might be a risk of brute-forcing across sites, especially if the target site lacks iframe protection using X-Frame-Options.
Q: Who is vulnerable?
If your web application uses ID attribute to reference to a sensitive state changing action, you might be vulnerable.