---
# System prepended metadata

title: uoftctf the varsity

---

# Task
![image](https://hackmd.io/_uploads/S1b1GNfK6.png)

## Recon
Đầu tiên khi vào trang web thì ta có một cái trang để có thể đăng ký tên người dùng và điền voucher vào 
![image](https://hackmd.io/_uploads/ryrwM4Gta.png)
Sau khi điền thông tin vào thì ta được điều hướng qua một cái trang khác 
![image](https://hackmd.io/_uploads/Hyn3f4zYT.png)
Từ bây giờ ta chỉ có thể load được article từ 1 đến 8 thôi còn 9 thì không phải có voucher là preminum thì mới được đọc được nên giờ là lúc review source code

```javascript=
app.post("/register", (req, res) => {
  const { username, voucher } = req.body;

  if (
    typeof username === "string" && // kiểm tra xem có đúng kiểu là string hay không
    (!voucher || typeof voucher === "string") 
  ) {
    console.log("voucher: " + (FLAG + JWT_SECRET));
    const subscription = voucher === FLAG + JWT_SECRET ? "premium" : "guest"; // nếu như voucher đúng bằng là flag + jwt_secret thì là preminum không thì guest
    console.log("subscription: " + subscription);   
    console.log(voucher === FLAG + JWT_SECRET ? "premium" : "guest");
    console.log("voucher: " + (FLAG + JWT_SECRET));
    if (voucher && subscription === "guest") { 
      return res.status(400).json({ message: "Invalid voucher" });
    }
    const userToken = jwt.sign({ username, subscription }, JWT_SECRET, { // xét ngày hết hạn của cái mã json thôi
      expiresIn: "1d",
    });
    res.cookie("token", userToken, { httpOnly: true });
    return res.json({ message: "Registration successful", subscription });
  }

  return res.status(400).json({ message: "Invalid username or voucher" });
});
```

Ở đoạn này ta có thể thấy được rằng để có được voucher thì ta phải có được flag thật và cả mã hash của jwt nữa nên việc crack hash jwt là thừa và không thể khi mà signature lên tới 64 byte và hoàn toàn ngẫu nhiên nên mình đi theo hướng khác
Đến đây là mình hoàn toàn không có hướng đi gì nhưng nhờ một anh đồng nghiệp cũng chỗ làm đã chỉ cho mình một điểm bất hợp lý trong source code và cũng từ đó mình có hướng giải

```javascript=
app.post("/article", (req, res) => { // sử dụng phương thức post để gửi các req và res
  const token = req.cookies.token; // token lấy từ cookie sẽ là mã json

  if (token) { // kiểm tra token có rỗng hay không?
    try {
      const decoded = jwt.verify(token, JWT_SECRET); // xác nhận chữ ký của mã json
      console.log("decoded in post /article: " + decoded)
      let issue = req.body.issue; // lấy issue từ req

      if (req.body.issue < 0) { // kiểm tra xem có nhỏ hơn 0
        return res.status(400).json({ message: "Invalid issue number" });
      }

      if (decoded.subscription !== "premium" && issue >= 9) { // kiểm tra xem nếu như subscription mà không phải preminum và issue >= 9 
        return res // trả về lỗi 403 chưa có quyền đọc
          .status(403)
          .json({ message: "Please subscribe to access this issue" });
      }

      issue = parseInt(issue); // ép kiểu về int

      if (Number.isNaN(issue) || issue > articles.length - 1) { // kiểm tra xem có phải là số hay không và có lớn hơn độ dài của cái mảng
        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" });
  }
});
```

Các bạn có thể thấy rằng ở dòng 14 đầu tiên là đã check issue >= 9 rồi nhưng ở dưới lại ép kiểu thành integer với function là parseInt nên sẽ thế nào nếu như ta đặt issue là "9aaa" nó sẽ tự ép kiểu thành 9 và có thể lấy được flag

Payload
```=
{ 
    "issue":"9aaa"
}
```

## Flag
![image](https://hackmd.io/_uploads/r14AN4zKa.png)

```uoftctf{w31rd_b3h4v10r_0f_parseInt()!}```