TCP1P CTF — Nuclei
Tags: tcp1pctf2023, misc
Published: 2023-10-15 15:17:47

![Challenge Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m3nkrxo4q6v7czs4yy52.png)

In this challenge, we are presented with a rather simple web page.

![Page preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1enhugslc78v1zguciun.png)

Here, we can input a valid URL only as it will validate the input. Since there is not much exciting stuff on the website, let's dive into the [source code](https://ctf.tcp1p.com/challenges#A%20simple%20website-311) provided.

## ⛏ Source digging

In the zip archive, we can find docker-related files, `custom-template.yaml` file, and also `app.py` which is a flask application.

![dist.zip files](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2znhguq6eezg4v31e0yu.png)

In the `custom-template.yaml` file, we can find interesting metadata, and HTTP requests..? We'll get into it further later.

![custom-template.yaml](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7bjasvuw9qe675zrm9n.png)

On the other side, we can find the source code! `app.py`. Inside, we can find the corresponding file that handles the `/submit` route. We can also find the validation code for the URL input.

![Validation code snippet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ciltdprwimdbg9byjmja.png)

Following that, we can also find a command snippet that will run a process that uses our **input**, and by getting the desired output, we can get the flag ✨.

![Command snippet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0ee8twfhz4mq1t7tecq.png)

## ⚛ Nuclei

By doing a short Google search, [Nuclei](https://docs.nuclei.sh/) is:

> a fast scanner used to scan modern applications, infrastructure, cloud environments, and networks to help you find and remediate vulnerabilities. [(source)](https://docs.nuclei.sh/getting-started/overview)

Now, we also know that `custom-template.yaml` is for nuclei to use. We can find the templating guide in the official nuclei [templating guide](https://docs.nuclei.sh/template-guide/introduction) documentation. From the custom template, URL input, and source code, we can safely assume that we need to craft an HTTP server that fulfills the template requirements.

![Nuclei template introduction](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ma1umma4s9zikczcfnj.png)

## 🛠 Crafting the server

Let's first list the things we need to do.

1. **Routes**

    We need to create 2 endpoints that are written in the template.yaml file:

    - `/api/v1/version`
    - `/api/v2/echo`

    ![HTTP endpoints](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s5kz0t3f7z4c9m8uokhd.png)

2. **Response**

    1. In the `/version` endpoint, we need to respond with:
        - `version` that needs to be under or equal to `10.0.5` but later than `10.0.1`
        - Exact words that matches `"NAME":"TCP1P"` and `"msg":"success"`
    
        ![First request matcher](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sslz06ag0auzr42ek0wl.png)

    2. As for the `/echo` endpoint, we have a more complex requirement:
        - the body need to match `TCP1P{[a-z]}` regex,
        - contains the string `<script>alert(1)</script>`,
        - and responds with status code 200.

        ![Second request matcher](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdlm45no7er25tey7x3g.png)

    3. Lastly, every request must respond with code 200.
    
    ![Status 200](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xtxfqpwh3unjlfiwlbe.png)

Now, we can actually make the server that will definitely give us the flag! For this example, I'll use [Express](https://expressjs.com/) and [Node](https://nodejs.org/en).

```js
import express from 'express';

const app = express();

app.get('/api/v1/version', (req, res) => {
  res
    .json({
      "NAME": "TCP1P",
      "msg": "success",
      "version": "10.0.4"
    });
});

app.get('/api/v2/echo', (req, res) => {
  res
    .send("TCP1P{a} <script>alert(1)</script>");
});

app.listen(3000, () => {
  console.log('Server listening on port 3000');
});
```

![Server running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jyp0dijvl7vmy0pw5g9.png)

## 🩸 Execution

To allow nuclei from the challenge to access our server, we can use a tunnel service like [ngrok](https://ngrok.com/) to give us a public URL.

![ngrok](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46h1fhtjvjfqn37q3oet.png)

Just like that, submitting the URL... and we got the flag ✨!

![Flag!!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kynfyqsyn70nwd376twl.png)

*Feedback are appreciated!*