---
# System prepended metadata

title: Ping CTF path-traversal-101

---

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

## Recon and review source code
Ở ngay trang chính gần như không có gì để chúng ta có thể tận dụng được nhưng sau khi tìm robots.txt thì có một đoạn tên là
```
Disallow: /🤖
```

Nhưng nếu như các bạn gọi luôn cái đường dẫn này nó sẽ in ra một đoạn lỗi do đoạn mã này

```javascript=
export default (req, res, next) => {
    const userAgent = req.get("User-Agent");
    if (userAgent == "robot") {
        next();
    } else {
        console.log("forget to change user-agent");
        res.render("robot", { error: "🤖🤖🤖🤖🤖" });
    }
};

```
Vậy nên ta phải chỉnh lại user-agent thành chữ robot rồi sau đó sẽ được gửi đến nơi để làm bài

Đầu tiên ta có task 1:
```javascript=
export const task1 = (solution) => {
    preTask(solution);
    if (!solution.startsWith("/robot") || solution.endsWith("/flag")) {
        console.log("inside task 1: " + solution);
        throw new Error(
            "You cannot access the flag!!! You are UNAUTHORIZED!!! 🤖🤖🤖🤖🤖"
        );
    }
    console.log("outside task 1 " + solution);
    const solutionPath = path.join("/", solution);
    console.log("solutionPath: " + solutionPath);
    if (solutionPath === "/flag") {
        console.log("You did it!")
    }
    return solutionPath === "/flag";
};
```
Cái đoạn console.log là chỗ mình thêm vào để xem các hoạt động của chương trình thôi các bạn có thể xem ở terminal sau khi chạy ```docker-compose up --build``` 
Đoạn mã trên nhận vào biến solution và rồi kiểm tra xem nó có bắt đầu "/robot" hay không và kiểm tra có kết thúc bằng "/flag" nếu như thỏa mãn 1 trong hai thì sẽ nhận được thông báo lỗi ngược lại nếu như thỏa mãn thì sẽ thực hiện join với "/" trả về true hoặc false sau khi so sánh với chữ "/flag" và ở file index.js ta có thể thấy
```javascript=
app.post(
    "/%F0%9F%A4%96",
    rl,
    robot,
    withCatch(async (req, res) => {
        const token = req.cookies.token;
        console.log("token: " + token);
        if (!token) {
            throw new Error("Unauthorized");
        }
        const session = sessions.find((session) => session.id === token);
        console.log("session: " + session);
        if (!session) {
            throw new Error("Unauthorized");
        }
        const { solution } = req.body;
        if (!session.task1) {
            const result = task1(solution);
            console.log("Result in task 1 file index.js: " + result);
            if (result) {
                console.log("Execute in task 1 file index.js");
                session.task1 = true;
                res.render("exam", {
                    task: tasks[1],
                });
                console.log("Have been render task 1!")
            } else {
                res.render("exam", {
                    task: tasks[0],
                    error: "Try again!",
                });
                console.log("Have not been render! else statement");
            }
        } else if (!session.task2) {
            const result = task2(solution);
            if (result) {
                session.task2 = true;
                res.render("exam", {
                    task: tasks[2],
                });
            } else {
                res.render("exam", {
                    task: tasks[1],
                    error: "Try again!",
                });
            }
        } else if (!session.task3) {
            const result = task3(solution);
            if (result) {
                session.task3 = true;
                res.render("exam", {
                    task: FLAG,
                });
            } else {
                res.render("exam", {
                    task: tasks[2],
                    error: "Try again!",
                });
            }
        }
    })
);

```
Dễ thấy được rằng để có thể đi đến task tiếp theo thì các task phải trả về là true
Sau khi nghiên cứu và hỏi ban tổ chức thì mình được biết là có một cách để solution sau khi bị path.join() sẽ in ra là "/flag"

```=
task 1: /robot/../../../../../../../../../flag/././.
```
Đây được gọi là path truncation có thể đọc thêm ở [đây](https://book.hacktricks.xyz/pentesting-web/file-inclusion) theo như trang chủ của node.js viết về [path](https://nodejs.org/api/path.html) thì ta có thể biết được rằng nó sẽ kết nối các đường dẫn để tạo thành một cái path đến cái file ta cần và nếu như ta để là ../ nó sẽ tự lùi một bước giống hệt như là cách ta thực hiện path traversal chẳng hạn như mình chỉ viết là "/robot/../" kết quả sẽ trả về là "/"

Sau khi ta hoàn thành được task 1 thì đến task 2

```javascript=
export const task2 = (solution) => {
    preTask(solution);
    solution = solution.replaceAll("../", "");
    console.log("inside task 2 after replace: " + solution)
    if (solution === "/flag") {
        console.log("inside check condition task 2: " + solution);
        throw new Error(
            "You cannot ACCESS the flag!!! You are UNAUTHORIZED!!! 🤖🤖🤖🤖🤖"
        );
    }
    const solutionPath = path.join("/", solution);
    return solutionPath === "/flag";
};
```
Cái này thì khá là đơn giản chỉ cần thêm là "....//" sau khi bị replace nó sẽ in ra được là đoạn mã giống như ở task 1

```=
task 2: /robot/....//....//....//....//....//....//....//....//....//flag/././.
```

Cuối cùng là task 3 hoàn thành là có flag rồi

```javascript=
export const task3 = (solution) => {
    preTask(solution);
    console.log("Out side task 3 prepare solution: " + solution);
    if (solution.includes("../") || solution === "/flag") {
        console.log("inside task 3: " + solution);
        throw new Error(
            "You CANNOT ACCESS the flag!!! You are UNAUTHORIZED!!! 🤖🤖🤖🤖🤖"
        );
    }
    const solutionPath = path.join("/", solution);
    console.log("solution path task 3: " + solutionPath);
    return solutionPath === "/flag";
};
```
Đoạn này chính mình cũng mất một lúc thời gian rồi mới nhận ra hướng đi cho bản thân nó sẽ không nhận các payload có chứa "../" vì vậy dùng các payload như ở trên sẽ không được vậy thay vì dùng là "../" thì sao không dùng là "/flag/././." như vậy là khi ta path.join() lại kết quả sẽ ra là "/flag"

## Flag
```
ping{p4th_tr4V3Rs4L_06c22f693acd46015891c98cb72f45e3}
```
Toàn bộ source code có thể xem ở [đây](https://github.com/khacminh03/CTF-Write-Up/tree/main/pingCTF/path-traversal-101)