# UoftCTF Writeup [toc] ## Web ### The Vartity FLAGは、article配列内にあります。 ```javascript const articles = [ { "title": "Pioneering the Future: UofT's Revolutionary AI Research", "content": "The University of Toronto continues to lead groundbreaking research in artificial intelligence, with its latest project aiming to develop algorithms that can understand emotions in text. Spearheaded by a team of international students, this initiative promises to revolutionize how machines interact with human language." }, ... { title: "UofT Hosts its 2nd Inaugural Capture the Flag Event", content: "Your flag is: " + FLAG, }, ]; ``` articleを参照できるのは、`/article`エンドポイントなので、詳しく見ていきましょう。 ```javascript app.post("/article", (req, res) => { const token = req.cookies.token; if (token) { try { const decoded = jwt.verify(token, JWT_SECRET); let issue = req.body.issue; if (req.body.issue < 0) { return res.status(400).json({ message: "Invalid issue number" }); } if (decoded.subscription !== "premium" && issue >= 9) { return res .status(403) .json({ message: "Please subscribe to access this issue" }); } issue = parseInt(issue); if (Number.isNaN(issue) || issue > articles.length - 1) { return res.status(400).json({ message: "Invalid issue number" }); } return res.json(articles[issue]); } catch (error) { res.clearCookie("token"); return res.status(403).json({ message: "Not Authenticated" }); } } else { return res.status(403).json({ message: "Not Authenticated" }); } }); ``` `issue変数`が、配列内の要素を表すようです。 ```javascript return res.json(articles[issue]); ``` FLAGは、index 9にあるため、`issue:9`にすればよさそうですが、`subscription`がguestになります。 <details> <summary>server.ts</summary> ```javascript app.post("/register", (req, res) => { const { username, voucher } = req.body; if ( typeof username === "string" && (!voucher || typeof voucher === "string") ) { const subscription = voucher === FLAG + JWT_SECRET ? "premium" : "guest"; if (voucher && subscription === "guest") { return res.status(400).json({ message: "Invalid voucher" }); } ``` </details> そのため、issueは9未満でなければなりません。 ```javascript if (decoded.subscription !== "premium" && issue >= 9) { return res .status(403) .json({ message: "Please subscribe to access this issue" }); } ``` ですが、issueは再代入されることがわかります。 ```javascript issue = parseInt(issue); ``` ここで悪用ができれば幸せです。 では検証していきましょう。 ```javascript issue = "9-9"; issue >= 9; // false parseInt(issue); // 9 ``` この挙動を利用すればうまくいきそうなことがわかります。 ```javascript if (decoded.subscription !== "premium" && issue >= 9) { return res .status(403) .json({ message: "Please subscribe to access this issue" }); } ``` まずここは、true && falseの結果falseで次の処理へ行きます。 ```javsacript issue = parseInt(issue); ``` 続いて、issueに9が入ります。 ```javascript if (Number.isNaN(issue) || issue > articles.length - 1) { return res.status(400).json({ message: "Invalid issue number" }); } ``` 最後、ここはもちろん引っかかりません。 `articles.length - 1 = 9`で、`issue = 9`ですし、isNaNではないためです。 つまりこれでFLAGが降ってきます。 ![image](https://hackmd.io/_uploads/HJYYr8ZYT.png) ```json {"title":"UofT Hosts its 2nd Inaugural Capture the Flag Event","content":"Your flag is: uoftctf{w31rd_b3h4v10r_0f_parseInt()!}"} ``` ## Miscellaneous ### Out of the Buscket `/out-of-the-bucket`にアクセスすると、以下のように怪しい何かが見えます。 ```xml <Contents><Key>secret/dont_show</Key><Generation>1703868647771911</Generation><MetaGeneration>1</MetaGeneration><LastModified>2023-12-29T16:50:47.809Z</LastModified><ETag>"737eb19c7265186a2fab89b5c9757049"</ETag><Size>29</Size></Contents> ``` `/out-of-the-bucket/secret/dont_show`にアクセスするとフラグが取得できます。 ```text= uoftctf{allUsers_is_not_safe} ``` ## Forensics ### Secret Message 1 配布されるsecret.pdfの黒塗り部分をコピーしてどっかに貼り付けるとフラグが取得できる。 ```text= uoftctf{fired_for_leaking_secrets_in_a_pdf} ```