---
# System prepended metadata

title: m0leCon Beginner CTF 2023

---

# m0leCon Beginner CTF 2023``

## 1. Ungessable
![image](https://hackmd.io/_uploads/r15MsWcS6.png)
![image-1](https://hackmd.io/_uploads/HkoGi-cBp.png)

Đa số mấy bài guess kiểu này thường không thể guess được 🤣
Vô check source xem thử


```javascript
<script>
    const loader = document.getElementById("loader");
    const card = document.getElementById("resultCard");
    const text = document.getElementById("resultText");

    function advance() {
      const width = parseInt(loader.style.width);
      if (width < 100) {
        loader.style.width = `${width + 1}%`;
        loader.innerText = `${width + 1}%`;
      }
      return width;
    }

    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    async function load() {
      loader.parentElement.removeAttribute("hidden");
      let width = 0;
      while ((width = advance()) < 100) {
        await sleep(width == 98 ? 5000 : Math.random() * 100);
      }
      loader.style.width = "0%";
      loader.parentElement.setAttribute("hidden", "");
    }

    function update(res) {
      if (res === "wrong") {
        card.style.backgroundColor = "red";
        text.innerText = "Wrong, try again";
      } else {
        card.style.backgroundColor = "green";
        fetch("/vjfYkHzyZGJ4A7cPNutFeM/flag")
          .then((response) => response.text())
          .then((str) => {
            text.innerText = str
          });
      }

      card.removeAttribute("hidden");
    }

    document.getElementById("guessBtn").onclick = function () {
      card.setAttribute("hidden", "");
      load().then(() =>
        fetch("/guess", {
          body: document.getElementById("guess").value,
          method: "POST",
        }))
        .then((response) => response.json())
        .then((json) => update(json["result"]))
        .then(() => loader.parentElement.setAttribute("hidden", ""));

    };
</script>

```
- Nôm na là fetch sẽ gửi một yêu cầu POST đến `/guess` kèm theo giá trị mà mình đoán
- Kết quả trả về được chuyển thành json và truyền giá trị của key `result` vô hàm **`update`**
- Nếu kết quả khác `wrong` thì sẽ thực hiện fetch từ `/vjfYkHzyZGJ4A7cPNutFeM/flag` về và lấy kết quả đó hiện thị ra màn hình
</br>

Mình sẽ thử fetch `/vjfYkHzyZGJ4A7cPNutFeM/flag` về xem sao

```javascript
jurl = 'https://unguessable.challs.m0lecon.it/vjfYkHzyZGJ4A7cPNutFeM/flag'
fetch (url)
    .then(res => {
        return res.text()
    })
    .then(flag => {
        console.log(flag)
    })
```

![image-2](https://hackmd.io/_uploads/SJlEsZqr6.png)
Ú là la

Hoặc có thể truy cập vào endponit `/vjfYkHzyZGJ4A7cPNutFeM/flag` để lấy flag
![image-3](https://hackmd.io/_uploads/Skt4o-qB6.png)


Flag: **~~`ptm{4lw4y5_ch3ck_th3_50urc3_c0d3}`~~**


## 2. SecureAcess
![image](https://hackmd.io/_uploads/rkpdjWqB6.png)

Nhìn có vẻ bài này phải kết hợp với `rev` để làm được

![image-1](https://hackmd.io/_uploads/rkzKsWqBa.png)

Mình thử login với username là `admin`
![image-3](https://hackmd.io/_uploads/ryYtoZ5BT.png)

Có vẻ như mình phải tính toán `2F781F93-C662-4B7C-BE86-983E5A9C29FC` để lấy được `ACCESS TOKEN`
Mình có thử với các username khác nhưng vẫn thu về token y hệt

Mình có ném file `leaked.pyc` cho thằng bạn rev
```python
import hashlib
import json
import base64

def generate_token(nonce = None):
    username = 'user001'
    secret = hashlib.sha256(username.encode() + nonce.encode()).hexdigest()
    bundle = {
        'user': username,
        'secret': secret }
    return base64.b64encode(json.dumps(bundle).encode())
```
Hiểu nôm na là hàm **`generate_token`** sẽ generate ra một token được `base64_encode` với đối số là `nonce` nếu không truyền thì mặc định là `None`

Mình sẽ thử truyền token bên trên vào hàm thử xem nó trả về token gì cho mình
![image-4](https://hackmd.io/_uploads/Hy0Kib5BT.png)

**`eyJ1c2VyIjogInVzZXIwMDEiLCAic2VjcmV0IjogImZjZjNjYTNjNTQ4NDBlMzJiN2U5YzUyMDVmODFhNDJlODAwNTU4NjljZWQ4ODM5NmJkNjFhZGQyZWMwOWY4YjMifQ==`**
Khả năng cao đây là `ACCESS TOKEN` mà nó bắt mình tính

![image-5](https://hackmd.io/_uploads/BJbqib5rT.png)
Ú là la

Flag: ~~**`ptm{m4yb3_7he_A1s_4r3_n0t_th4t_5m4r7}`**~~




## 3. PianoCarriera
![image](https://hackmd.io/_uploads/B1EZnb9H6.png)


![image-1](https://hackmd.io/_uploads/ByL-n-qST.png)

Nhìn sơ qua thì có lẽ mình phải tick được `Internship` để đăng ký được môn học
<br>

![image-2](https://hackmd.io/_uploads/Sk9b2-cHT.png)

Nhưng có vẻ không dễ dàng gì
Vô check source xem thử
<br>

Để ý có đoạn này
![image-3](https://hackmd.io/_uploads/HkpZ2-qSp.png)

Nôm na là nó sẽ không cho tick những thẻ nào có class là `noProp`
Hướng làm của mình là sẽ tìm những thẻ này và remove class `noProp` đi
<br>

script
```javascript
var elements = document.querySelectorAll('.noProp')
elements.forEach(element => {
    element.classList.remove('noProp')   
})
```
![image-4](https://hackmd.io/_uploads/BJzGhbqBT.png)

Có vẻ như mình đã tick được khóa `Internship` rồi
![image-5](https://hackmd.io/_uploads/ByLf2b5Sp.png)

Nhưng đời không như là mơ
Có vẻ như nó yêu cầu mình phải chọn đủ 30 tín chỉ, nhưng học phần `Internship` chỉ mới có 12
<br>

Lúc đầu mình có tìm cách để chuyển số tín chỉ của `Internship` lên thành 30 nhưng có vẻ không được
Sau một hồi suy nghĩ thì sao mình không chọn thêm học phần để nó đủ 30 tín chỉ??

![image-6](https://hackmd.io/_uploads/Hyozhb9BT.png)

Mình sẽ chọn thêm thằng `Thesis` bên dưới có tín chỉ là 18 để đủ 30 tín, trùng hợp là nó có class `noProp` và mình đã tiện thể remove trước đó
<br>

![image-7](https://hackmd.io/_uploads/S1O7nWqSp.png)

Giờ đi confirm thôi
![image-8](https://hackmd.io/_uploads/SyjQ3-5r6.png)

Ú là la

Hoặc có thể làm theo cách này
![image-9](https://hackmd.io/_uploads/rkg42W5B6.png)

Mình sẽ intercept của thằng `Tesi`
![image-10](https://hackmd.io/_uploads/SyVNnW9rp.png)

Sau đó mình thay đổi `cod_ins` từ thằng `Tesi` thành `Internship`
![image-11](https://hackmd.io/_uploads/HkwN3W9rp.png)

Và sau đó đi confirm và lấy flag
![image-12](https://hackmd.io/_uploads/BJpE3Z9rT.png)


Flag: ~~**`ptm{p0p1P0P1_d1_70r1n0}`**~~