WayWitch

Hidden in the shadows, a coven of witches communicates through arcane tokens, their messages cloaked in layers of dark enchantments....

Looking at the code

The code is uses NodeJs framework which has this kind of file system:

├── build-docker.sh
├── config
│   └── supervisord.conf
├── Dockerfile
├── entrypoint.sh
├── flag.txt
└── src
    ├── database.js
    ├── index.js
    ├── package.json
    ├── routes
    │   └── index.js
    ├── static
    │   ├── css
    │   │   ├── bootstrap.min.css
    │   │   └── main.css
    │   ├── images
    │   │   └── logo.png
    │   └── js
    │       └── jose.min.js
    ├── util.js
    └── views
        └── index.html

util.js

  • Contains utility functions shared across the application.

  • Example tasks:

    • File system operations.

    • Generating or validating tokens.

    • Parsing data or configurations

Src/

The folder that contains the core logic and handling of the web server

Database.js

Implements the database connection and sets up the tables according to the defined schema

We can see there's some kind of ticketing system going on which maybe used to authenticate the users. We also see that these tickets are made of id , name , username, content:

Look how the admin ticket contains the flag

Also the description said to craft the ticket

Index.js

  • The application’s main entry point.

  • Sets up:

    • Express server.

    • Middleware (e.g., for serving static files or handling requests).

    • Routes (from routes/index.js).

  • Also there's package.json file that defines what scripts to run

Routes/

  • Contains route definitions (index.js).

  • Responsible for:

    • Handling HTTP requests.

    • Sending responses (e.g., rendering views or returning JSON data).

The router is defined with casesensitive:true meaning they require exact word for the route. Now looking at the routes itself:


1. GET /tickets

  • Purpose: Fetches all tickets, restricted to admin users.

  • Workflow:

    1. Checks for Session Token:

      • Retrieves the session_token from cookies.

      • If missing, returns a 401 Unauthorized status.

    2. Validates the Token:

      • Decodes the session_token using getUsernameFromToken.

      • If invalid, returns a 400 Bad Request with the error message.

    3. Checks Admin Privileges:

      • If the username is not "admin", returns 403 Forbidden.

    4. Fetches Tickets:

      • Calls db.get_tickets() to retrieve all tickets.

      • If successful, returns a 200 OK with the tickets as a JSON object.

      • On failure, returns 500 Internal Server Error.


2. POST /submit-ticket

  • Purpose: Allows authenticated users to submit a new ticket.

  • Workflow:

    1. Checks for Session Token:

      • Retrieves session_token from cookies.

      • If missing, returns 401 Unauthorized.

    2. Validates the Token:

      • Decodes the session_token using getUsernameFromToken.

      • If invalid, returns 400 Bad Request with the error message.

    3. Validates Request Body:

      • Extracts name and description from the request body.

      • If either is missing, returns 400 Bad Request.

    4. Adds a Ticket:

      • Calls db.add_ticket(name, username, description) to insert the ticket into the database.

      • If successful, returns 200 OK with a success message.

      • On failure, returns 500 Internal Server Error.

Browsing the application

shall we use the data we got from database file?

So we looked at the code , now we know how app works , let's test the theory:

JSon huh

So we control the name and description from client side and also:

So we craft a token to get the flag from the admin description as seen above in the code. We need the jwt secret for that -> which is in the utils.js file.

Not So Secret huh?

Then we craft the token:

and get the cookie:

HTB{k33p_th3s3_jwt_s3cr3t_s4f3f_br0}

Last updated