Published on

HeroCTF - SampleHub - Web

Authors

Description

Discover SampleHub, the ultimate online repository for accessing a vast collection of sample files. With user-friendly navigation, and robust search features, SampleHub makes it easy to browse, access, and download files efficiently.

URL : http://web.heroctf.fr:5300/
Author : Mizu

Solution

const express = require("express");
const path    = require("path");

const app  = express();
const PORT = 3000;

app.use(express.static(path.join(__dirname, "public")));
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));

app.get("/", (req, res) => {
    res.render("index");
});

process.chdir(path.join(__dirname, "samples"));
app.get("/download/:file", (req, res) => {
    const file = path.basename(req.params.file);
    res.download(file, req.query.filename || "sample.png", (err) => {
        if (err) {
            res.status(404).send(`File "${file}" not found`);
        }
    });
});


app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

This solution exploits a directory traversal vulnerability and a parameter manipulation tactic by using crafted query parameters in the filename. Let’s break it down and explain why it works.

Code Analysis and Vulnerability Explanation

  1. Path Traversal with path.basename():

const file = path.basename(req.params.file);

Here, path.basename() strips away any directory path components, leaving only the base filename of req.params.file. Normally, this would be a safeguard against directory traversal, preventing you from accessing files outside the intended directory (samples in this case).

However, the payload bypasses this limitation by using a specially crafted filename, leveraging the next part of the code to set the actual filename used in the response.

  1. res.download and Query Parameter Manipulation: res.download(file, req.query.filename || "sample.png", (err) => { ... }); In this line, res.download takes file (sanitized to basename) as the actual file to download. However, it allows you to specify a custom filename for download using req.query.filename. This is where the vulnerability comes into play.

The Payload Breakdown The payload in the solution URL: web.heroctf.fr:5300/download/.flag.txt?filename[root]=/&filename[dotfiles]=allow

Explanation of Payload Parametersdownload/.flag.txt: This requests the file .flag.txt in the current directory (i.e., within samples/). • filename[root]=/: This parameter in res.download may be interpreted by the underlying system or path resolver as a hint to the root directory, potentially affecting the file path resolution. • filename[dotfiles]=allow: This could serve to bypass default restrictions that might be in place to block files starting with a dot (like .flag.txt).

Why This Payload WorksDirectory Traversal Bypass: By combining carefully named query parameters, the payload potentially bypasses .flag.txt’s protection and indirectly achieves directory traversal. • Parameter Manipulation: The use of filename[root] and filename[dotfiles] in the query string may exploit an underlying middleware, library, or config in Express that permits or adjusts how “dotfiles” or files within certain directories are handled.

This unique payload exploits two quirks: • The way .flag.txt is sanitized yet accessed by the server. • The ability to manipulate res.download query parameters, tricking the app into returning a protected file.

Summary This solution leverages path traversal and parameter-based quirks to get the server to reveal .flag.txt. It’s a clever use of nested parameter syntax and filename suggestions, exploiting both the directory structure and res.download behavior in Express.